pax_global_header00006660000000000000000000000064143222432330014510gustar00rootroot0000000000000052 comment=94e86d109a4eaa1a093efc66059b74648ebf6dc5 hart-software-services-2022.10/000077500000000000000000000000001432224323300162655ustar00rootroot00000000000000hart-software-services-2022.10/.cproject000066400000000000000000001020421432224323300200760ustar00rootroot00000000000000 hart-software-services-2022.10/.github/000077500000000000000000000000001432224323300176255ustar00rootroot00000000000000hart-software-services-2022.10/.github/CODE_OF_CONDUCT.md000066400000000000000000000062101432224323300224230ustar00rootroot00000000000000# Microchip PolarFire SoC Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contribute to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at polarfiresoc@microchip.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq hart-software-services-2022.10/.github/CONTRIBUTING.md000066400000000000000000000061101432224323300220540ustar00rootroot00000000000000# Microchip PolarFire SoC Contributing Guidelines [fork]: /fork [pr]: /compare [style]: https://standardjs.com/ [code-of-conduct]: CODE_OF_CONDUCT.md [discussion-forum]: https://github.com/polarfire-soc/polarfire-soc-documentation/discussions Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. ## Discussions, Issues and PRs If you have suggestions for how this project or an individual component could be improved, have a question or need help please open a discussion thread in the organization's [discussion forum](discussion-forum). Note: if your question is related to a fork of an external repository (e.g Zephyr) and the query isn't directly related to any Microchip code, please be aware that it may be better to open an discussion thread in the source repository. If you want to report a bug, open an issue against the source repository containing the offending code. We appreciate any contributions. We also welcome PRs to add features, board support for new targets and fix issues. If you would like to add a new feature it is advised to make an enhancement request in our [discussion forum](discussion-forum) so the feature request can be discussed. If you would like to add board support please reach out to your Mi-V ecosystem contact before opening a PR. Look at the links below if you're not sure how to open a PR. ## Submitting a pull request 1. Fork and clone the repository. 1. Create a new branch: `git checkout -b my-branch-name`. 1. Make and test your changes. 1. When you're happy that your fix or improvement is stable commit your changes and push to your fork. 1. Verify that your changes apply to the head of the source branch. 1. Submit a pull request. 1. Wait for your pull request to be reviewed. 1. As we push to GitHub from an internal git repository, we may not merge your change directly on GitHub, it is more likely to be applied internally as a patch and mirrored to GitHub. 1. If this is the case we will let you know when change has been reviewed and if it has been accepted or not. 1. We will update the PR and let you know when the change has been released and subsequently close the PR. Here are a few things you can do that will increase the likelihood of your pull request being accepted: - Explain why this change is needed, what bugs are fixed or why this feature should be merged. - Demonstrate how you have tested and verified your change is stable. - Keep your changes as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). ## Resources - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) - [GitHub Help](https://help.github.com) hart-software-services-2022.10/.github/issue_template.md000066400000000000000000000031771432224323300232020ustar00rootroot00000000000000# Microchip PolarFire SoC Issue Template [discussion-forum]: https://github.com/polarfire-soc/polarfire-soc-documentation/discussions ## Checklist Please complete this checklist before filing an issue: - [ ] Are you using the latest releases of our deliverables? - If not please update to the latest version of the each deliverable needed (reference design, HSS, Linux / bare metal example) and re-test as this issue may already have been resolved. - [ ] Is this something you can debug and fix? - Send a pull request! Bug fixes and documentation fixes are welcome. - [ ] Have a usage question? - Ask your question on our [discussion forum](discussion-forum). We use the discussion forum for usage questions. - [ ] Have an idea for a feature? - Post the feature request on the [discussion forum](discussion-forum). This will allow us to assess and plan for the feature without having an open issue until it is released. GitHub issues should only be used for code bugs. - [ ] Is this issue directly related to Microchip code? I.e have you found an upstream bug? - If so please open an issue against the upstream repository and not the Microchip fork. ## None of the above, create an issue Please make sure to add all the information needed to understand the bug so that someone can help. If the info is missing we'll add the 'Needs more information' label and close the issue until there is enough information. - [ ] Provide a minimal code snippet example that reproduces the bug where appropriate. - [ ] Provide screenshots where appropriate - [ ] Does this occur all of the time or is it intermittent? - [ ] Have you tried on another board? hart-software-services-2022.10/.github/pull_request_template.md000066400000000000000000000021551432224323300245710ustar00rootroot00000000000000# Description Please include a summary of the changes and the related issue. Explain why this change is needed, what bugs are fixed or why this feature should be merged. List any dependencies that are required for this change. Fixes # (issue) ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] This change requires a documentation update # How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Test A - [ ] Test B **Test Configuration**: * Reference design release: * Hardware: * HSS version: * Bare metal examples version: * Buildroot / Yocto release: # Checklist: - [ ] I have reviewed my code - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have tested that my fix is effective or that my feature works - [ ] I have added a maintainers file for any new board support hart-software-services-2022.10/.github/workflows/000077500000000000000000000000001432224323300216625ustar00rootroot00000000000000hart-software-services-2022.10/.github/workflows/build-hss.yaml000066400000000000000000000005301432224323300244360ustar00rootroot00000000000000on: [push] jobs: build-hss: runs-on: ubuntu-latest container: microsemiproess/softconsole-headless-slim:6.6-2021.1-hss steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 - run: cp boards/mpfs-icicle-kit-es/def_config .config - run: make BOARD=mpfs-icicle-kit-es - run: ls -la ./Default hart-software-services-2022.10/.gitignore000066400000000000000000000001341432224323300202530ustar00rootroot00000000000000*.d *.o *.bin *.elf *.hex *.map *.sym .config .config.old config.h include/tool_versions.h hart-software-services-2022.10/.project000066400000000000000000000014671432224323300177440ustar00rootroot00000000000000 hart-software-services org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature hart-software-services-2022.10/CHANGELOG.md000066400000000000000000000054241432224323300201030ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## 2022.09 ### Added * HSS: OpenSBI: updated to OpenSBI v1.0 (SBI v0.3) * HSS: tiny-cli: Added "debug opensbi" command, along with U54 state tracking * HSS: mpfs-hal: updated to mpfs-hal v2.0.101 - Using mpfs-hal to switch MSSIOs for SD/eMMC switchover - `SDIO_REGISTER` renamed to `FABRIC_SD_EMMC_DEMUX_SELECT` * HSS: QSPI: add support for booting from Micron MT25Q * HSS: eMMC: fixes for HS200 / HS400 * HSS: remoteproc: ecall support for remoteproc - the ability to start and stop a remote AMP context using the remoteproc framework in Linux. - Payload Generator: add `skip-autoboot` flag to YAML to skip automatically loading and booting a payload on a per-context basis - IHC: various related ecall fixes * HSS: reboot: add context-based reboot support (via SRST) - Kconfig: add `ALLOW_COLDREBOOT` option to enable cold reboot - Payload Generator: add `allow-reboot` flag to YAML to control entitlement to warm/cold reboot * HSS: ddr: add Kconfig option to skip training DDR * HSS: ddr: early output status of DDR training progress * Payload Generator: add ability to override context boot image name in YAML ### Changed * HSS: save space by enabling LTO and whole program optimization - Note this means disabling strong stack protection. - Removed function names from console output to save space. ### Fixed * Payload Generator: secure-boot: update from deprecated OpenSSL APIs * HSS: platform: fixed potential NULL lookup of fdt ## 2022.03 ### Added * HSS: QSPI: Add support for booting from Winbond W25N01GV flash ### Changed * HSS: resets: bringing all peripherals out of reset * HSS: scrub: add throttling support to memory scrubber ### Fixed * HSS: board/custom-board-design: update to build with latest HSS code base * HSS: boot: Resolve out-of-bounds issue ## 2022.02 ### Added * HSS: secure-boot: image signing for payload.bin * Payload Generator: secure-boot: support for image signing payload.bin * HSS: m100pfsevp: Aries Board Support Package added * HSS: Added support for Kconfiglib guiconfig tool - This requires python3 tkinter bindings on Linux. For Ubuntu/Debian, use $ sudo apt install python3-tk ### Changed * HSS: DDR: Configured for High-Memory DDR (0x10'0000'0000) instead of Low-Memory (0x8000'0000) - **WARNING:** Pre-existing code will break if not re-linked for the new DDR address * HSS: L2: Move decompressed HSS from L2LIM to L2-Scratchpad ### Fixed * Payload Generator: updated to ignore zero-byte sections * Payload Generator: enhance error checks, and ensure string concatenation always safe for names hart-software-services-2022.10/Default/000077500000000000000000000000001432224323300176515ustar00rootroot00000000000000hart-software-services-2022.10/Default/README.md000066400000000000000000000001551432224323300211310ustar00rootroot00000000000000This directory is used by SoftConsole programming. It will contain the hexfile output from the HSS build. hart-software-services-2022.10/Kconfig000066400000000000000000000003121432224323300175640ustar00rootroot00000000000000mainmenu "Hart Software Services (HSS) Configuration" source "boards/Kconfig" source "services/Kconfig" source "application/Kconfig.general" source "application/Kconfig.build" source "modules/Kconfig" hart-software-services-2022.10/LICENSE.md000066400000000000000000000101651432224323300176740ustar00rootroot00000000000000# The HSS Software License The HSS software is released under the following software license: Copyright 2019-2021 Microchip Corporation. SPDX-License-Identifier: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## The HSS Payload Generator The HSS Payload Generator is dual licensed under the MIT license and the GNU GPL. See tools/hss-payload-generator/LICENSE.md for details. ## RISC-V OpenSBI License This software includes the RISC-V OpenSBI code, which is released under the following license: The 2-Clause BSD License SPDX short identifier: BSD-2-Clause Copyright (c) 2019 Western Digital Corporation or its affiliates. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## MiniZ This software includes the MiniZ compression library, which is released under the following license: The MIT License (MIT) Copyright 2013-2014 RAD Game Tools and Valve Software Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hart-software-services-2022.10/Makefile000066400000000000000000000101311432224323300177210ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Toplevel HSS Makefile # SHELL=/bin/sh # # To build the HSS under SoftConsole on Windows, we need to use SoftConsole-provided # tools, and potentially to modify paths # .ONESHELL: include application/os.mk include application/Makefile include .config ifneq ("$(wildcard boards/${BOARD}/Makefile)","") include boards/${BOARD}/Makefile else ifndef BOARD BOARD:=mpfs-icicle-kit-es export BOARD $(info INFO: BOARD not specified, defaulting to ${BOARD}) # default to icicle if nothing found include boards/${BOARD}/Makefile else $(error Board >>${BOARD}<< not found) endif endif CORE_CFLAGS+=-DBOARD=${BOARD} MCMODEL=-mcmodel=medany include application/rules.mk include application/targets.mk include init/Makefile include baremetal/Makefile include services/Makefile include modules/Makefile LIBS = #$(info $$INCLUDES is [${INCLUDES}]) ifdef CONFIG_CC_USE_MAKEDEP DEPENDENCIES=$(SRCS-y:.c=.d) $(EXTRA_SRCS-y:.c=.d) $(TEST_SRCS:.c=.d) $(ASM_SRCS:.S=.d) $(ASM_SRCS-y:.S=.d) .PHONY: dep dep: $(DEPENDENCIES) -include $(DEPENDENCIES) endif ifdef CONFIG_DISPLAY_TOOL_VERSIONS include/tool_versions.h: echo \#define CC_VERSION_STRING \"`$(CC) --version | head -n 1`\" > include/tool_versions.h echo \#define LD_VERSION_STRING \"`$(LD) --version | head -n 1`\" >> include/tool_versions.h DEPENDENCIES+=include/tool_versions.h endif include envm-wrapper/Makefile ################################################################################################ # # Main Build Targets # OBJS-envm = $(OBJS) EXTRA_OBJS-envm = $(EXTRA_OBJS) OBJS-l2scratch = $(OBJS) EXTRA_OBJS-l2scratch = $(EXTRA_OBJS) define main-build-target $(ECHO) " LD $@"; $(CC) -T $(LINKER_SCRIPT-$(1)) $(CFLAGS_GCCEXT) $(OPT-y) \ -static -nostdlib -nostartfiles -nodefaultlibs \ -Wl,--build-id -Wl,-Map=$(BINDIR)/output-$(1).map -Wl,--gc-sections \ -o $(BINDIR)/$@ $(OBJS-$(1)) $(EXTRA_OBJS-$(1)) $(LIBS) $(LIBS-y) $(ECHO) " NM `basename $@ .elf`.sym"; $(NM) -n $(BINDIR)/$@ > $(BINDIR)/`basename $@ .elf`.sym endef # # Build Targets # $(TARGET-envm): $(OBJS) $(EXTRA_OBJS) config.h $(DEPENDENCIES) $(LINKER_SCRIPT-envm) $(LIBS) $(call main-build-target,envm) $(ECHO) " BIN `basename $@ .elf`.bin" $(OBJCOPY) -O binary $(BINDIR)/$@ $(BINDIR)/`basename $@ .elf`.bin $(ECHO) " HEX `basename $@ .elf`.hex"; $(OBJCOPY) -O ihex $(BINDIR)/$@ $(BINDIR)/`basename $@ .elf`.hex $(SIZE) $(BINDIR)/$(TARGET-envm) 2>/dev/null $(TARGET-l2scratch): $(OBJS) $(EXTRA_OBJS) config.h $(DEPENDENCIES) $(LINKER_SCRIPT-l2scratch) $(LIBS) $(LIBS-y) $(call main-build-target,l2scratch) $(ECHO) " BIN `basename $@ .elf`.bin" $(OBJCOPY) -O binary $(BINDIR)/$@ $(BINDIR)/`basename $@ .elf`.bin $(SIZE) $(BINDIR)/$(TARGET-l2scratch) 2>/dev/null $(BINDIR)/$(TARGET-envm): $(TARGET-envm) $(BINDIR)/$(TARGET-l2scratch): $(TARGET-l2scratch) $(TARGET-ddr): $(OBJS) $(EXTRA_OBJS) config.h $(DEPENDENCIES) $(LINKER_SCRIPT-ddr) $(LIBS) $(call main-build-target,ddr) hart-software-services-2022.10/README.md000066400000000000000000000201361432224323300175460ustar00rootroot00000000000000# Hart Software Services This is the Hart Software Services (HSS) code. On PolarFire SoC, this is comprised of two portions: - A superloop monitor running on the E51 minion processor, which receives requests from the individual U54 application processors to perform certain services on their behalf; - A Machine-Mode software interrupt trap handler, which allows the E51 to send messages to the U54s, and request them to perform certain functions for it related to rebooting a U54. The HSS performs boot and system monitoring functions for PolarFire SoC. The HSS is compressed (DEFLATE) and stored in eNVM. On power-up, a small decompressor decompressor wrapper inflates the HSS from eNVM flash to L2-Scratchpad memory and starts the HSS. ## Contributions Pull requests to this repository must include a per-commit sign-off made by a contributor stating that they agree to the terms published at https://developercertificate.org/ for that particular contribution. ## Source Source code is found under the `hart-software-services` folder. hart-software-services ├── application (main function, crt startup, init function) ├── baremetal │   ├── drivers (local modules) │   └── polarfire-soc-bare-metal-library (subtree) ├── boards │   ├── mpfs-icicle-kit-es (Microchip Icicle Kit) │   ├── aries-m100pfsevp (Aries M100PFEVPS Kit) │   └── custom-board-design (template for new boards) ├── envm-wrapper (helper routines to inflate the HSS to L2-Scratchpad) ├── include ├── init (system initialization) ├── modules │   ├── compression │   ├── crypto │   ├── debug (helper routines for function profiling) │   ├── misc (miscellaneous routines) │   └── ssmb (secure software message bus) │   └── ipi ├── services (software service state machines) │   ├── beu │   ├── boot │   ├── crypto │   ├── ddr │   ├── goto │   ├── ipi_poll │   ├── mmc │   ├── opensbi │   ├── powermode │   ├── qspi │   ├── scrub │   ├── sgdma │   ├── spi │   ├── tinycli │   ├── uart │   ├── usbdmsc │   │  └── flash_drive │   ├── wdog │   └── ymodem └── thirdparty ├── Kconfiglib (a Kconfig implementation in Python) ├── libecc (library for elliptic curves based cryptography (ECC)) ├── miniz (fast lossless compression library)    └── opensbi (RISC-V OpenSBI) ## Building The build is configured using the Kconfig system of selecting build options. The Hart Software Services includes the Kconfig parsing infrastructure directly as a third-party tool invoked by the build system. Both Linux and Windows are supported by Kconfiglib. The HSS currently support PolarFire SoC-based icicle kit (mpfs-icicle-kit-es) as a board build target. ### Building on Linux The HSS relies on SoftConsole v2021.3 or later to build on Linux. It also needs tkinter installed for the KConfiglib guiconfig tool. To install this on Ubuntu/Debian: $ sudo apt install python3-tk First, ensure that the environment variable `$SC_INSTALL_DIR` is set to the location of SoftCOnsole on your system. For example, assuming that SoftConsole is installed at `/home/user/Microchip/SoftConsole-v2022.2`: $ export SC_INSTALL_DIR=/home/user/Microchip/SoftConsole-v2022.2 For building on Linux from the command line, configure the path appropriately. For example, the following will add the SoftConsole provided Python and RISC-V compiler toolchain to the path: $ export PATH=$PATH:$SC_INSTALL_DIR/python/bin:$SC_INSTALL_DIR/riscv-unknown-elf-gcc/bin Next, set the environment variable `$FPGENPROG` to the location of the fpgenprog tool installed by Libero -- this is used to program the eNVM ('make program') and also to generate hex files suitable for programming by Libero, or inclusion in the fabric design with Libero. For example, assuming that Libero is installed at `/usr/local/microsemi/Libero_SoC_v2021.2/`: $ export FPGENPROG=/usr/local/microsemi/Libero_SoC_v2021.2/Libero/bin64/fpgenprog To make these persistent upon logging in, these three environment variables - `$SC_INSTALL_DIR`, `$FPGENPROG` and the additions to `$PATH` - should be updated in your user shell initialization file (for example, `/home/user/.bashrc` for those running the bash shell). You can enter an interactive Kconfiglib configuration selection by running `make BOARD=mpfs-icicle-kit-es config`. This will generate a `.config` file (which is used to configure the Make build system) and a `config.h` header file (which is used to configure the source code): $ make BOARD=mpfs-icicle-kit-es config Alternatively, copy the default config for your board. For example: $ cp boards/mpfs-icicle-kit-es/def_config .config or just use the defconfig target to do the copy: $ make BOARD=mpfs-icicle-kit-es defconfig Once configured, to build, run `make`: $ make BOARD=mpfs-icicle-kit-es In the `Default` subdirectory, the standard build will create `hss-envm.elf` and various binary formats (`hss-envm.hex` and `hss-envm.bin`). Also generated are `output-envm.map`, which is a mapfile for the build, and `hss-envm.sym`, which is a list of symbols. (The name `Default` is required by SoftConsole for programming purposes.) A variety of alternative build options can be seen by running `make help`: $ make help Verbose builds (which show each individual command) are possible by adding V=1 to the end of the make command. For example: $ make V=1 ### Building on Windows The HSS relies only on SoftConsole v2021.3 or later to build on Windows. For more detailed build instructions, particular with regards to using SoftConsole on Windows, see https://github.com/polarfire-soc/polarfire-soc-documentation/blob/master/software-development/polarfire-soc-software-tool-flow.md#build-the-hss. First, ensure that the `%SC_INSTALL_DIR%` environment variable is correctly set to the location of SoftConsole. For example, if SoftConsole is installed in `C:\Microchip\SoftConsole-v2021.3-7.0.0.578`: C:\> set SC_INSTALL_DIR=C:\Microchip\SoftConsole-v2021.3-7.0.0.578 For building on Windows from the command line, you must configure the path appropriately to add Python, GNU build tools, and the RISC-V compiler toolchain. For example: C:\> path %SystemRoot%;%SC_INSTALL_DIR%\build_tools\bin;%SC_INSTALL_DIR%\python3;%SC_INSTALL_DIR%\python;%SC_INSTALL_DIR%\riscv-unknown-elf-gcc\bin Ensure the `%SC_INSTALL_DIR%` variable correctly matches your system. Next, set the environment variable `%FPGENPROG%` to the location of the fpgenprog tool installed by Libero -- this is used to program the eNVM ('make program') and also to generate hex files suitable for programming by Libero, or inclusion in the fabric design with Libero. For example, assuming that Libero is installed at `C:\Microchip\Libero_SoC_v2022.2\Designer\bin64\fpgenprog.exe`: C:\> set FPGENPROG=C:\Microchip\Libero_SoC_v2022.2\Designer\bin64\fpgenprog.exe To make these persistent, set them via the Control Panel or via the Settings App. ### Debug The `modules/debug/` subdirectory contains code to enable a number of debug features, including: * Logging all state machine transitions to the serial console (MMUART0); * Periodic logging of super loop timings to the serial console; * Logging of IPI statistics to the serial console; * Logging all IPI messages for MSC traces; * Function profiling. ### Function Profiling Function profiling allows capturing of the time spent in each C function (through the use of `__cyg_profile_func_enter` and `__cyg_profile_func_exit`. This information can be logged to the serial console through calling the `dump_profile()` function at an appropriate time, depending on what is being debugged. **NOTE:** *by default, this function is not called, even with profiling enabled.* hart-software-services-2022.10/application/000077500000000000000000000000001432224323300205705ustar00rootroot00000000000000hart-software-services-2022.10/application/Kconfig.build000066400000000000000000000057341432224323300232020ustar00rootroot00000000000000mainmenu "Build Options" menu "Build Options" config COLOR_OUTPUT bool "Color log output" default y help This feature enables color for HSS output If you do not know what to do here, say Y. config USE_LOGO bool "Display Logo" default y help This feature enables output for the Microchip logo. If you do not know what to do here, say Y. menu "Logo" config LOGO_INVERT_COLORS bool "Invert Logo colors" default n depends on USE_LOGO help This feature enables output for the Microchip logo, with white text. If you do not know what to do here, say N. endmenu config CC_STACKPROTECTOR_STRONG bool "Enable strong stack protection" default y help This feature enables strong stack checking on all function calls. If you do not know what to do here, say Y. config CC_DUMP_STACKSIZE bool "Dump stack sizes" default n help This feature dumps information about the stack sizes If you do not know what to do here, say N. config LD_RELAX bool "Use RISC-V Relaxing and the Global Pointer, GP" default n help The GP (Global Pointer) register optimises memory accesses within a single 4KB region. This size is 4K because RISC-V immediate values ar 12-bit signed values (+/- 2048) The linker uses the __global_pointer$ symbol definition to compare memory addresses and, if within range, it replaces absolute/pc-relative addressing with gp-relative addressing. This can lead to smaller code size, but it does impose requirements on subsequent firmwares that they save/restore the GP. If you do not know what to do here, say N. config CC_USE_MAKEDEP bool "Enable make dependencies in build system" default y help This feature enables automatic dependencies in the Makefile. This will create *.d files - one for each source file - which contain the analysed dependencies for the source. This improves source dependency checking during builds. If you do not know what to do here, say Y. config CC_USE_GNU_BUILD_ID bool "Enable GNU Build ID in image" default y help This feature enables the generation of a GNU Build ID in binaries. If you do not know what to do here, say Y. config CC_HAS_INTTYPES bool "Use inttypes.h" default y help This features uses the inttypes.h header file from the toolchain. If the toolchain does not provide inttypes.h, say N here. config DISPLAY_TOOL_VERSIONS bool "Display Compiler and Linker tool version information at startup." default y help This features displays compiler and linker tool version information at startup. If you do not know what to do here, say Y. config LOG_FUNCTION_NAMES bool "Display function names in console log messages" default y help This features displays the function names when loggin messages to the HSS console. This may be useful for debugging, but increases the code size by a few KiB. If you do not know what to do here, say Y. endmenu hart-software-services-2022.10/application/Kconfig.general000066400000000000000000000057111432224323300235130ustar00rootroot00000000000000menu "General Configuration Options" menu "Miscellaneous" config USE_PCIE bool "Setup PCIe" default y help Setup the PCIe prior to application load If you don't know what to do here, say Y. config UART_SURRENDER bool "HSS UART Surrender" depends on OPENSBI && !SERVICE_TINYCLI_REGISTER default n help If enabled, this feature "surrenders" MMUART0 after boot. After this point, HSS status messages will no longer be sent out MMUART0 This feature is not compatible with SERVICE_TINYCLI_REGISTER. If you want the HSS to surrender MMUART0 UART after boot, do not enable SERVICE_TINYCLI_REGISTER. If you do not know what to do here, say N. config OPENSBI def_bool y help This feature enables support for the RISC-V OpenSBI. If you don't know what to do here, say Y. config USE_IHC bool "Use MiV Inter-hart Communication" default y help Enable MiV Inter-Hart Communication (IHC) config ALLOW_COLDREBOOT bool "Allow contexts to issue a cold reboot" default y help If enabled, this feature globally allows a context to issue a cold reboot ecall. If disabled, only warm reboots will be permitted. In addition to enabling this option, the permission to issue a cold reboot must granted to a context via the payload generator YAML file. If you do not know what to do here, say Y. menu "Cold Reboot" visible if ALLOW_COLDREBOOT config ALLOW_COLDREBOOT_ALWAYS bool "Always allow contexts to issue a cold reboot" default y depends on ALLOW_COLDREBOOT help If enabled, this feature globally allows all contexts to issue a cold reboot ecall, irrespective of payload.bin flag entitlements. If you do not know what to do here, say Y. endmenu endmenu menu "OpenSBI" visible if OPENSBI config PROVIDE_DTB bool "Provide a DTB for OpenSBI" depends on OPENSBI default n help This feature enabling the building in of a device tree blob and the provision of this blob to OpenSBI via the a1 register. If this isn't needed, it is possible to save some space by removing it. If you don't know what to do here, say Y. config DEFAULT_DEVICE_TREE string "hifive-unleashed-a00-freedom-u540.dtb" depends on PROVIDE_DTB help This option specifies the default Device Tree to be used. endmenu menu "Memory Options" config SKIP_DDR bool "Skip DDR Training" default n help This feature enables skipping DDR training for systems without DDR. If you don't know what to do here, say N. config MEMTEST bool "DDR Memory Tester" depends on !SKIP_DDR default n help This feature enables a simple walking 1's style memory tester for the DDR. If you don't know what to do here, say N. config USE_PDMA bool "Use PDMA for memory-to-memory transfers" default y help Use the PDMA for memory to memory transfers. config INITIALIZE_MEMORIES bool "Initialize memories to zero" default y help Initialize memories to zero, to seed ECC. If you don't know what to do here, say N for now. endmenu endmenu hart-software-services-2022.10/application/Makefile000066400000000000000000000037051432224323300222350ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # all: $(TARGETS) config.h include .config SRCS-y += \ application/hart0/hss_state_machine.c \ application/hart0/hss_clock.c \ application/hart0/hss_registry.c \ INCLUDES +=\ -I./include \ -I. ASM_SRCS += \ application/crt.S \ EXTRA_SRCS-y += \ application/hart0/hss_init.c \ application/hart0/hss_main.c application/hart0/hss_main.o: CFLAGS=$(CFLAGS_GCCEXT) application/hart0/hss_init.o: CFLAGS=$(CFLAGS_GCCEXT) application/hart0/hss_init.o: include/tool_versions.h application/hart0/hss_state_machine.o: CFLAGS=$(CFLAGS_GCCEXT) tools/bin2chunks/bootImage.o: CFLAGS=$(CFLAGS_GCCEXT) # # U54 Functionality EXTRA_SRCS-y += \ application/hart1-4/u54_handle_ipi.c \ application/hart1-4/u54_state.c \ application/hart1-4/u54_handle_ipi.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/application/crt.S000066400000000000000000000277021432224323300215140ustar00rootroot00000000000000/* * The HSS software is released under the following software license: * * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Based on OpenSBI fw_base.S * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Western Digital Corporation or its affiliates. */ #include #include #include #include #include #include .section .entry, "ax", %progbits .attribute unaligned_access, 0 .attribute stack_align, 16 .align 3 .globl _start .globl _start_warm _start: la ra, _start call _reset_regs .macro LOAD_GP // // RISC-V Relaxing and the Global Pointer, GP // // The gp (Global Pointer) register optimises memory accesses within a single 4KB region. // This size is 4K because RISC-V immediate values are 12-bit signed values (+/- 2048) // // The linker uses the __global_pointer$ symbol definition to compare memory addresses // and, if within range, it replaces absolute/pc-relative addressing with gp-relative // addressing. // // This process can be disabled by -Wl,--no-relax. // #if defined(CONFIG_LD_RELAX) .option push .option norelax la gp, __global_pointer$ .option pop #endif .endm LOAD_GP // Preload HART details // s7 -> HART Count // s8 -> HART Stack Size // a0 -> current HART ID // la a4, platform lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4) //lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4) la s8, STACK_SIZE_PER_HART csrr a0, CSR_MHARTID la tp, __stack_bottom add tp, tp, 63 and tp, tp, -64 li a1, 1 .setup_stack: mul a2, s8, a0 add tp, tp, a2 la sp, STACK_SIZE_PER_HART add sp, sp, tp .setup_scratches: // Setup scratch space for all the HARTs la tp, scratches li t2, 1 // Counter li t1, 0 // hartid 0 is mandated by ISA .disable_and_clear_interrupts: // Disable and clear all interrupts csrw CSR_MIE, zero csrw CSR_MIP, zero .validate_hart_id: bge a0, s7, _start_hang .find_my_scratch_space: la tp, scratches // find the scratch space for this hart li a5, SBI_SCRATCH_SIZE mul a5, a5, a0 add tp, tp, a5 csrw CSR_MSCRATCH, tp // update the mscratch csrr a0, CSR_MHARTID beqz a0, .boot_e51 .setup_u54_trap_handler: la a4, _trap_handler call .set_trap_handler csrw CSR_SATP, 0 # clear SATP early on U54s, as it appears to be coming up randomly .enable_interrupts: li a2, MIP_MSIP // set MSIE bit to receive IPIs csrw CSR_MIE, a2 csrw CSR_MSTATUS, a2 jal HSS_U54_Banner #if defined(CONFIG_HSS_USE_IHC) .enable_ihc: jal HSS_IHCInit_U54 #endif .spin_forever: wfi j .spin_forever .boot_e51: #if defined(CONFIG_HSS_USE_IHC) // initialise PLIC if required for IHC jal HSS_Setup_PLIC #endif // Setup E51 trap handler la a4, hss_e51_trap_handler call .set_trap_handler // clearing of DTIM and L2LIM done from previous decompression stage li a2, MIP_MSIP csrc CSR_MSTATUS, a2 j main .set_trap_handler: csrw CSR_MTVEC, a4 // // Make sure that mtvec is updated // // csrr a5, CSR_MTVEC bne a4, a5, .set_trap_handler ret .section .entry, "ax", %progbits .align 3 .globl _start_hang _start_hang: wfi j _start_hang .section .entry, "ax", %progbits .align 3 .globl _trap_handler _trap_handler: // Swap TP and MSCRATCH csrrw tp, CSR_MSCRATCH, tp // Save T0 in scratch space REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp) // Check which mode we came from csrr t0, CSR_MSTATUS srl t0, t0, MSTATUS_MPP_SHIFT and t0, t0, PRV_M xori t0, t0, PRV_M beq t0, zero, _trap_handler_m_mode // We came from S-mode or U-mode _trap_handler_s_mode: // Set T0 to original SP add t0, sp, zero // Setup exception stack add sp, tp, -(SBI_TRAP_REGS_SIZE) // Jump to code common for all modes j _trap_handler_all_mode // We came from M-mode _trap_handler_m_mode: // Set T0 to original SP add t0, sp, zero // Re-use current SP as exception stack add sp, sp, -(SBI_TRAP_REGS_SIZE) _trap_handler_all_mode: // Save original SP (from T0) on stack REG_S t0, SBI_TRAP_REGS_OFFSET(sp)(sp) // Restore T0 from scratch space REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp) // Save T0 on stack REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp) // Swap TP and MSCRATCH csrrw tp, CSR_MSCRATCH, tp // Save MEPC and MSTATUS CSRs csrr t0, CSR_MEPC REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp) csrr t0, CSR_MSTATUS REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp) // Save all general regisers except SP and T0 //REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp) REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp) REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp) REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp) REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp) REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp) REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp) REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp) REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp) REG_S a1, SBI_TRAP_REGS_OFFSET(a1)(sp) REG_S a2, SBI_TRAP_REGS_OFFSET(a2)(sp) REG_S a3, SBI_TRAP_REGS_OFFSET(a3)(sp) REG_S a4, SBI_TRAP_REGS_OFFSET(a4)(sp) REG_S a5, SBI_TRAP_REGS_OFFSET(a5)(sp) REG_S a6, SBI_TRAP_REGS_OFFSET(a6)(sp) REG_S a7, SBI_TRAP_REGS_OFFSET(a7)(sp) REG_S s2, SBI_TRAP_REGS_OFFSET(s2)(sp) REG_S s3, SBI_TRAP_REGS_OFFSET(s3)(sp) REG_S s4, SBI_TRAP_REGS_OFFSET(s4)(sp) REG_S s5, SBI_TRAP_REGS_OFFSET(s5)(sp) REG_S s6, SBI_TRAP_REGS_OFFSET(s6)(sp) REG_S s7, SBI_TRAP_REGS_OFFSET(s7)(sp) REG_S s8, SBI_TRAP_REGS_OFFSET(s8)(sp) REG_S s9, SBI_TRAP_REGS_OFFSET(s9)(sp) REG_S s10, SBI_TRAP_REGS_OFFSET(s10)(sp) REG_S s11, SBI_TRAP_REGS_OFFSET(s11)(sp) REG_S t3, SBI_TRAP_REGS_OFFSET(t3)(sp) REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp) REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp) REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp) LOAD_GP // Call C routine csrr a0, CSR_MCAUSE sext.w a0, a0 blt a0, zero, .checkIfOpenSBITrap .checkIfHssIpi: call HSS_U54_HandleIPI // check if it is a HSS IPI bnez a0, .skipOpenSbi .checkIfOpenSBITrap: add a0, sp, zero csrr a1, CSR_MSCRATCH call sbi_trap_handler .skipOpenSbi: // Restore all general regisers except SP and T0 REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp) REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp) REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp) REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp) REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp) REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp) REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp) REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp) REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp) REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp) REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp) REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp) REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp) REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp) REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp) REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp) REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp) REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp) REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp) REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp) REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp) REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp) REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp) REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp) REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp) REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp) REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp) REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp) REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp) // Restore MEPC and MSTATUS CSRs REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp) csrw CSR_MEPC, t0 REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) csrw CSR_MSTATUS, t0 // Restore T0 REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp) // Restore SP REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp) mret .section .entry, "ax", %progbits .align 3 .globl _reset_regs _reset_regs: // flush the instruction cache fence.i // Reset all registers except ra, a0, a1 and a2 li gp, 0 li sp, 0 li tp, 0 li t0, 0 li t1, 0 li t2, 0 li s0, 0 li s1, 0 li a3, 0 li a4, 0 li a5, 0 li a6, 0 li a7, 0 li s2, 0 li s3, 0 li s4, 0 li s5, 0 li s6, 0 li s7, 0 li s8, 0 li s9, 0 li s10, 0 li s11, 0 li t3, 0 li t4, 0 li t5, 0 li t6, 0 csrw CSR_MSCRATCH, 0 ret .section .entry, "ax", %progbits .align 3 .globl hss_e51_trap_handler hss_e51_trap_handler: wfi j hss_e51_trap_handler /*********************************************************************************** * * The following init_memory() symbol overrides the weak symbol in the HAL and does * a safe copy of RW data and clears zero-init memory * */ // zero_section helper function: // a0 = exec_start_addr // a1 = exec_end_addr // .type .zero_section, @function .zero_section: beq a0, a1, .zero_section_done sd zero, (a0) addi a0, a0, 8 j .zero_section .zero_section_done: ret // copy_section helper function: // a0 = load_addr // a1 = exec_start_addr // a2 = exec_end_addr .globl copy_section .type copy_section, @function copy_section: beq a1, a0, .copy_section_done // if load_addr == exec_start_addr, goto copy_section_done .check_if_copy_section_done: beq a1, a2, .copy_section_done // if offset != length, goto keep_copying .keep_copying: ld a3, 0(a0) // val = *load_addr sd a3, 0(a1) // *exec_start_addr = val; addi a0, a0, 8 // load_addr = load_addr + 8 addi a1, a1, 8 // exec_start_addr = exec_start_addr + 8 j .check_if_copy_section_done .copy_section_done: ret // init_memory function, used to initialize memory early before C code runs // .globl init_memory .type init_memory, @function init_memory: addi sp,sp,-16 sd ra,8(sp) // // Initialize R/W data // (sdata and data sections) // la a0, __sdata_load la a1, __sdata_start la a2, __sdata_end call copy_section la a0, __data_load la a1, __data_start la a2, __data_end call copy_section // // Clear zero-init memory // (SBSS and BSS sections) // la a0, __sbss_start la a1, __sbss_end call .zero_section la a0, __bss_start la a1, __bss_end ld ra,8(sp) addi sp,sp,16 tail .zero_section /*********************************************************************************** * * The following copy_switch_code() symbol overrides the weak symbol in the HAL and does * a safe copy of HW config data */ .globl copy_switch_code .type copy_switch_code, @function copy_switch_code: la a5, __sc_start // a5 = __sc_start la a4, __sc_load // a4 = __sc_load beq a5,a4,.copy_switch_code_done // if a5 == a4, goto copy_switch_code_done la a3, __sc_end // a3 = __sc_end beq a5,a3,.copy_switch_code_done // if a5 == a3, goto copy_switch_code_done .copy_switch_code_loop: lw a2,0(a4) // a2 = *a4 sw a2,0(a5) // *a5 = a2 addi a5,a5,4 // a5+=4 addi a4,a4,4 // a4+=4 bltu a5,a3,.copy_switch_code_loop // if a5 < a3, goto copy_switch_code_loop .copy_switch_code_done: ret /*********************************************************************************** * */ .clear_l2lim: // Clear the LIM // // On reset, the first 15 ways are L2 and the last way is cache // We can initialize all, as cache write through to DDR is blocked // until DDR in initialized, so will have no effect other than clear ECC // // NOTE: we need to check if we are debugging from LIM,if so do not initialize // la a2, _hss_start la a4, __l2lim_start beq a2, a4, .done_clear la a5, __l2lim_end j 1f .clear_dtim: // // Clear the E51 DTIM to prevent any memory errors on initial access // to the cache // la a4, __dtim_start la a5, __dtim_end 1: // common loop used by both .clear_l2lim and .clear_dtim REG_S x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, 1b .done_clear: ret hart-software-services-2022.10/application/hart0/000077500000000000000000000000001432224323300216065ustar00rootroot00000000000000hart-software-services-2022.10/application/hart0/hss_clock.c000066400000000000000000000022731432224323300237260ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Access Local Tick Information * \brief Get acccess to tick counts from processor */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_clock.h" #include "csr_helper.h" /** * \brief Get acccess to tick counts from processor */ HSSTicks_t HSS_GetTime(void) { HSSTicks_t tickCount; tickCount = CSR_GetTime(); return tickCount; } HSSTicks_t HSS_GetTickCount(void) { HSSTicks_t tickCount; tickCount = CSR_GetTickCount(); return tickCount; } bool HSS_Timer_IsElapsed(HSSTicks_t startTick, HSSTicks_t durationInTicks) { return (HSS_GetTime() > (startTick + durationInTicks)); } void HSS_SpinDelay_MilliSecs(uint32_t milliseconds) { HSSTicks_t delayTick = HSS_GetTime(); while (!HSS_Timer_IsElapsed(delayTick, ONE_MILLISEC * milliseconds)) { ; } } void HSS_SpinDelay_Secs(uint32_t seconds) { HSSTicks_t delayTick = HSS_GetTime(); while (!HSS_Timer_IsElapsed(delayTick, ONE_SEC * seconds)) { ; } } hart-software-services-2022.10/application/hart0/hss_init.c000066400000000000000000000176771432224323300236140ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Software Initalization * \brief Full System Initialization */ #include "config.h" #include "hss_types.h" #include #include "hss_state_machine.h" #include "ssmb_ipi.h" #include "hss_debug.h" #include "hss_registry.h" #include "hss_atomic.h" #include "hss_init.h" #include "hss_version.h" #if IS_ENABLED(CONFIG_SERVICE_TINYCLI) # include "tinycli_service.h" #endif #include "csr_helper.h" #if IS_ENABLED(CONFIG_SERVICE_BOOT) # include "hss_boot_service.h" #endif #if IS_ENABLED(CONFIG_OPENSBI) # include "sbi/riscv_asm.h" # include "sbi/sbi_version.h" #endif #include "hss_sys_setup.h" #include "mpfs_reg_map.h" #include "hss_memcpy_via_pdma.h" #include "mpfs_hal_version.h" #include "miv_ihc_version.h" #include "mss_sys_services.h" #include "mss_sysreg.h" /** * \brief Main Initialization Function * * All other initialization routines to be chained off this... */ /****************************************************************************/ #include #define mMEM_SIZE(REGION) (REGION##_END - REGION##_START + 1u) extern const uint64_t __dtim_start, __dtim_end; extern const uint64_t __l2_start; extern const uint64_t __ddr_start, __ddr_end; extern const uint64_t _hss_start; #define E51_DTIM_START (&__dtim_start) #define E51_DTIM_END (&__dtim_end) #define E51_ITIM_START (&__e51itim_start) #define E51_ITIM_END (&__e51itim_end) #define U54_1_ITIM_START (&__u54_1_itim_start) #define U54_1_ITIM_END (&__u54_1_itim_end) #define U54_2_ITIM_START (&__u54_2_itim_start) #define U54_2_ITIM_END (&__u54_2_itim_end) #define U54_3_ITIM_START (&__u54_3_itim_start) #define U54_3_ITIM_END (&__u54_3_itim_end) #define U54_4_ITIM_START (&__u54_4_itim_start) #define U54_4_ITIM_END (&__u54_4_itim_end) #define L2_START (&__l2_start) #define L2_END (&__l2_end) #define DDR_START (&__ddr_start) // can't access DDR_END without getting an error: // R_RISCV_PCREL_HI20 against symbol `__ddr_end' // solution is to use assembler instead as the symbol is constant at link time // // #define DDR_END (&__ddr_end) asm(".align 3\n" "hss_init_ddr_end: .quad (__ddr_end)\n"); extern const uint64_t hss_init_ddr_end; #define DDR_END (&hss_init_ddr_end) #if IS_ENABLED(CONFIG_PLATFORM_MPFS) # include "mss_sysreg.h" #endif bool HSS_ZeroDDR(void) { #if IS_ENABLED(CONFIG_INITIALIZE_MEMORIES) uint64_t volatile *pDWord = (uint64_t volatile *)DDR_START; while (pDWord < (uint64_t volatile const * const)DDR_END) { *pDWord = 0llu; pDWord++; } #endif __sync_synchronize(); return true; } /* Init memories.. */ #include "system_startup.h" bool HSS_ZeroTIMs(void) { #if IS_ENABLED(CONFIG_INITIALIZE_MEMORIES) memset((void*)E51_DTIM_START, 0, E51_DTIM_END - E51_DTIM_START); /* 8KiB */ memset((void*)U54_1_ITIM_START, 0, U54_1_ITIM_END - U54_1_ITIM_START); /* 28KiB */ memset((void*)U54_2_ITIM_START, 0, U54_2_ITIM_END - U54_2_ITIM_START); /* 28KiB */ memset((void*)U54_3_ITIM_START, 0, U54_3_ITIM_END - U54_3_ITIM_START); /* 28KiB */ memset((void*)U54_4_ITIM_START, 0, U54_4_ITIM_END - U54_4_ITIM_START); /* 28KiB */ #endif __sync_synchronize(); return true; } bool HSS_Init_RWDATA_BSS(void) { //UART not setup at this point //mHSS_DEBUG_PRINTF("Setting up RW Data and BSS sections\n"); #if IS_ENABLED(CONFIG_PLATFORM_MPFS) init_memory(); #endif return true; } #if IS_ENABLED(CONFIG_CC_USE_GNU_BUILD_ID) void HSS_PrintBuildId(void); void HSS_PrintBuildId(void) { extern const struct { uint32_t namesz; uint32_t descsz; uint32_t type; uint8_t data[]; } gnu_build_id; const size_t padding = sizeof(uint32_t) - 1u; const size_t offset = (gnu_build_id.namesz + padding) & ~padding; const uint8_t *pBuildId = (const uint8_t *)&(gnu_build_id.data[offset]); mHSS_FANCY_PUTS(LOG_STATUS, "Build ID: "); for (int i = 0; i < gnu_build_id.descsz; ++i) { mHSS_PRINTF("%02x", pBuildId[i]); } mHSS_PRINTF("\n"); } #endif #if IS_ENABLED(CONFIG_DISPLAY_TOOL_VERSIONS) #include "tool_versions.h" void HSS_PrintToolVersions(void); void HSS_PrintToolVersions(void) { mHSS_FANCY_PUTS(LOG_STATUS, "Built with the following tools:\n"); mHSS_PUTS(" - " CC_VERSION_STRING "\n"); mHSS_PUTS(" - " LD_VERSION_STRING "\n\n"); } #endif bool HSS_E51_Banner(void) { #ifndef VENDOR_STRING # define VENDOR_STRING "" #endif #if !IS_ENABLED(CONFIG_SKIP_DDR) extern const char DDR_DRIVER_VERSION[]; #endif mHSS_FANCY_PRINTF(LOG_STATUS, "PolarFire(R) SoC Hart Software Services (HSS) - version %d.%d.%d" VENDOR_STRING "\n" "MPFS HAL version %d.%d.%d" #if !IS_ENABLED(CONFIG_SKIP_DDR) " / DDR Driver version %s" #endif #if IS_ENABLED(CONFIG_USE_IHC) " / Mi-V IHC version %d.%d.%d" #endif " / BOARD=" STR(BOARD) "\n" "(c) Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions.\n\n" "incorporating OpenSBI - version %d.%d\n" "(c) Copyright 2019-2022 Western Digital Corporation.\n\n", HSS_VERSION_MAJOR, HSS_VERSION_MINOR, HSS_VERSION_PATCH, MPFS_HAL_VERSION_MAJOR, MPFS_HAL_VERSION_MINOR, MPFS_HAL_VERSION_PATCH #if !IS_ENABLED(CONFIG_SKIP_DDR) , DDR_DRIVER_VERSION #endif #if IS_ENABLED(CONFIG_USE_IHC) // add the comma separator here if adding IHC version information to prevent a // compile error on the macro if CONFIG_USE_IHC is not enabled , MIV_IHC_VERSION_MAJOR, MIV_IHC_VERSION_MINOR, MIV_IHC_VERSION_PATCH #endif , OPENSBI_VERSION_MAJOR, OPENSBI_VERSION_MINOR ); #if IS_ENABLED(CONFIG_CC_USE_GNU_BUILD_ID) HSS_PrintBuildId(); #endif #if IS_ENABLED(CONFIG_DISPLAY_TOOL_VERSIONS) HSS_PrintToolVersions(); #endif if (&_hss_start == &__l2_start) { mHSS_FANCY_PRINTF(LOG_WARN, "NOTICE: Running from L2 Scratchpad\n\n"); } return true; } bool HSS_ResetReasonInit(void) { #if IS_ENABLED(CONFIG_DEBUG_RESET_REASON) uint8_t reset_reason = SYSREG->RESET_SR; const char* const reset_reason_string[] = { [ RESET_SR_SCB_PERIPH_RESET_OFFSET ] = "SCB peripheral reset signal", [ RESET_SR_SCB_MSS_RESET_OFFSET ] = "SCB MSS reset register", [ RESET_SR_SCB_CPU_RESET_OFFSET ] = "SCB CPU reset register", [ RESET_SR_DEBUGER_RESET_OFFSET ] = "Risc-V Debugger", [ RESET_SR_FABRIC_RESET_OFFSET ] = "fabric", [ RESET_SR_WDOG_RESET_OFFSET ] = "watchdog", [ RESET_SR_GPIO_RESET_OFFSET ] = "fabric asserted the GPIO reset inputs", [ RESET_SR_SCB_BUS_RESET_OFFSET ] = "SCB bus reset occurred", [ RESET_SR_CPU_SOFT_RESET_OFFSET ] = "CPU reset the MSS using soft reset register" }; if (reset_reason) { mHSS_DEBUG_PRINTF(LOG_WARN, "NOTICE: Reboot reason = 0x%x\n", reset_reason); for (int bitPosn = 0; bitPosn <= RESET_SR_CPU_SOFT_RESET_OFFSET; bitPosn++) { if (reset_reason & (1 << bitPosn)) { mHSS_DEBUG_PRINTF_EX("\t=> %s\n", reset_reason_string[bitPosn]); } } } else { mHSS_DEBUG_PRINTF(LOG_WARN, "No reboot reason bits set\n"); } // Clear the value to 0 so it is armed for next time SYSREG->RESET_SR = 0u; #endif return true; } /****************************************************************************/ void HSS_Init(void) { RunInitFunctions(spanOfGlobalInitFunctions, globalInitFunctions); #if IS_ENABLED(CONFIG_SERVICE_BOOT) HSS_Boot_RestartCore(HSS_HART_ALL); # if IS_ENABLED(CONFIG_UART_SURRENDER) # if IS_ENABLED(CONFIG_SERVICE_TINYCLI) HSS_TinyCLI_SurrenderUART(); # endif void uart_surrender(void); uart_surrender(); # endif #endif } hart-software-services-2022.10/application/hart0/hss_main.c000066400000000000000000000043621432224323300235600ustar00rootroot00000000000000/****************************************************************************************** * * MPFS HSS Embedded Software * * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /*\! *\file Main Entrypoint *\brief Main Entrypoint */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include "hss_init.h" #include "hss_registry.h" #if IS_ENABLED(CONFIG_SERVICE_WDOG) # include "wdog_service.h" #endif #include "csr_helper.h" #include /******************************************************************************************/ void hss_main(void); void hss_main(void) { #if IS_ENABLED(CONFIG_SERVICE_WDOG) HSS_Wdog_MonitorHart(HSS_HART_ALL); #endif while (true) { RunStateMachines(spanOfPGlobalStateMachines, pGlobalStateMachines); } } int main(int argc, char **argv) { (void)argc; // unused (void)argv; // unused HSS_Init(); if (current_hartid() != 0) { sbi_hart_hang(); } hss_main(); // will never be reached __builtin_unreachable(); return 0; } hart-software-services-2022.10/application/hart0/hss_registry.c000066400000000000000000000216051432224323300245030ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file MPFS HSS Registered Tables * \brief Contains all registered tables. * * Items such as IPI handlers and state machines are statically registered * at compile time by design in the MPFS HSS Embedded Software. * These tables are defined in this file. */ #include "config.h" #include "hss_types.h" #include "ssmb_ipi.h" #if IS_ENABLED(CONFIG_SERVICE_IPI_POLL) # include "ipi_poll_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_BOOT) # include "hss_boot_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_UART) # include "uart_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_SPI) # include "spi_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_SCRUB) # include "scrub_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_SGDMA) # include "sgdma_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_DDR) # include "ddr_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_GOTO) # include "goto_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_OPENSBI) # include "opensbi_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_TINYCLI) # include "tinycli_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) # include "usbdmsc_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_POWERMODE) # include "powermode_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_CRYPTO) # include "crypto_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_WDOG) # include "wdog_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_BEU) # include "beu_service.h" #endif #include "hss_debug.h" #include "hss_registry.h" #include /*! * \brief Empty IPI handler * * Default empty handler for incoming IPI requests */ static enum IPIStatusCode HSS_Null_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { (void)transaction_id; (void)source; (void)immediate_arg; (void)p_extended_buffer_in_ddr; (void)p_ancilliary_buffer_in_ddr; mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s() called -- ignoring\n"); return IPI_SUCCESS; } /******************************************************************************************************/ /*! * \brief IPI Registration Table * * The following structure is used to connect in new IPIs... * * \warning It must end with a 'NULL' sentinel for the last handler function pointer to indicate end */ const struct IPI_Handler ipiRegistry[] = { { IPI_MSG_NO_MESSAGE, HSS_Null_IPIHandler }, #if IS_ENABLED(CONFIG_SERVICE_BOOT) { IPI_MSG_BOOT_REQUEST, HSS_Boot_IPIHandler }, { IPI_MSG_PMP_SETUP, HSS_Boot_PMPSetupHandler }, #else { IPI_MSG_BOOT_REQUEST, HSS_Null_IPIHandler }, { IPI_MSG_PMP_SETUP, HSS_Null_IPIHandler }, #endif #if IS_ENABLED(CONFIG_SERVICE_SPI) { IPI_MSG_SPI_XFER, HSS_Null_IPIHandler }, #else { IPI_MSG_SPI_XFER, HSS_Null_IPIHandler }, #endif #if IS_ENABLED(CONFIG_SERVICE_NET) { IPI_MSG_NET_RXPOLL, HSS_Null_IPIHandler }, { IPI_MSG_NET_TX, HSS_Null_IPIHandler }, #else { IPI_MSG_NET_RXPOLL, HSS_Null_IPIHandler }, { IPI_MSG_NET_TX, HSS_Null_IPIHandler }, #endif #if IS_ENABLED(CONFIG_SERVICE_SGDMA) { IPI_MSG_SCATTERGATHER_DMA, HSS_SGDMA_IPIHandler }, #else { IPI_MSG_SCATTERGATHER_DMA, HSS_Null_IPIHandler }, #endif #if IS_ENABLED(CONFIG_SERVICE_WDOG) { IPI_MSG_WDOG_INIT, HSS_Null_IPIHandler }, #else { IPI_MSG_WDOG_INIT, HSS_Null_IPIHandler }, #endif { IPI_MSG_GPIO_SET, HSS_Null_IPIHandler }, #if IS_ENABLED(CONFIG_SERVICE_UART) { IPI_MSG_UART_TX, HSS_UartTx_IPIHandler }, { IPI_MSG_UART_POLL_RX, HSS_UartPollRx_IPIHandler }, #else { IPI_MSG_UART_TX, HSS_Null_IPIHandler }, { IPI_MSG_UART_POLL_RX, HSS_Null_IPIHandler }, #endif #if IS_ENABLED(CONFIG_SERVICE_POWERMODE) { IPI_MSG_POWERMODE, HSS_Null_IPIHandler }, #else { IPI_MSG_POWERMODE, HSS_Null_IPIHandler }, #endif { IPI_MSG_ACK_PENDING, IPI_ACK_IPIHandler }, { IPI_MSG_ACK_COMPLETE, IPI_ACK_IPIHandler }, { IPI_MSG_HALT, HSS_Null_IPIHandler }, { IPI_MSG_CONTINUE, HSS_Null_IPIHandler }, #if IS_ENABLED(CONFIG_SERVICE_GOTO) { IPI_MSG_GOTO, HSS_GOTO_IPIHandler }, #else { IPI_MSG_GOTO, HSS_Null_IPIHandler }, #endif #if IS_ENABLED(CONFIG_SERVICE_OPENSBI) { IPI_MSG_OPENSBI_INIT, HSS_OpenSBI_IPIHandler }, #else { IPI_MSG_OPENSBI_INIT, HSS_Null_IPIHandler }, #endif }; const size_t spanOfIpiRegistry = ARRAY_SIZE(ipiRegistry); /******************************************************************************************************/ /*! * \brief State Machine Registration Table * * The following structure is used to connect in new state machines. * * \warning It must end with a 'NULL' sentinel to indicate end */ struct StateMachine /*@null@*/ * const pGlobalStateMachines[] = { #if IS_ENABLED(CONFIG_SERVICE_IPI_POLL) &ipi_poll_service, #endif #if IS_ENABLED(CONFIG_SERVICE_BOOT) &boot_service1, &boot_service2, &boot_service3, &boot_service4, #endif #if IS_ENABLED(CONFIG_SERVICE_SPI) &spi_service, #endif #if IS_ENABLED(CONFIG_SERVICE_UART) &uart_service, #endif #if IS_ENABLED(CONFIG_SERVICE_WDOG) &wdog_service, #endif #if IS_ENABLED(CONFIG_SERVICE_SGDMA) &sgdma_service, #endif #if IS_ENABLED(CONFIG_SERVICE_POWERMODE) &powermode_service, #endif #if IS_ENABLED(CONFIG_SERVICE_CRYPTO) &crypto_service, #endif #if IS_ENABLED(CONFIG_SERVICE_DDR) &ddr_service, #endif #if IS_ENABLED(CONFIG_SERVICE_OPENSBI) &opensbi_service, #endif #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_REGISTER) &tinycli_service, #endif #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) &usbdmsc_service, #endif #if IS_ENABLED(CONFIG_SERVICE_SCRUB) &scrub_service, #endif #if IS_ENABLED(CONFIG_SERVICE_BEU) &beu_service, #endif }; const size_t spanOfPGlobalStateMachines = ARRAY_SIZE(pGlobalStateMachines); /******************************************************************************************************/ /*! * \brief Init Function Registration Table * * The following structure is used to connect in new init functions. */ #include "hss_init.h" #include "hss_boot_init.h" #include "hss_boot_pmp.h" #include "hss_sys_setup.h" #include "hss_board_init.h" #include "device_serial_number.h" #if IS_ENABLED(CONFIG_MEMTEST) # include "hss_memtest.h" #endif #if !IS_ENABLED(CONFIG_TINYCLI) # include "tinycli_service.h" #endif const struct InitFunction /*@null@*/ globalInitFunctions[] = { // Name FunctionPointer Halt Restart // { "HSS_Setup_L2Cache", HSS_Setup_L2Cache, false, false }, { "HSS_Init_RWDATA_BSS", HSS_Init_RWDATA_BSS, false, false }, { "HSS_UARTInit", HSS_UARTInit, false, false }, { "HSS_OpenSBIInit", HSS_OpenSBIInit, false, false }, { "HSS_BoardInit", HSS_BoardInit, false, false }, #if IS_ENABLED(CONFIG_USE_LOGO) { "HSS_LogoInit", HSS_LogoInit, false, false }, #endif { "HSS_E51_Banner", HSS_E51_Banner, false, false }, { "Device_Serial_Number_Init", Device_Serial_Number_Init, false, false }, { "HSS_DDRPrintSegConfig", HSS_DDRPrintSegConfig, false, false }, { "HSS_DDRPrintL2CacheWaysConfig", HSS_DDRPrintL2CacheWaysConfig, false, false }, #if IS_ENABLED(CONFIG_MEMTEST) { "HSS_MemTestDDRFast", HSS_MemTestDDRFast, false, false }, #endif #if IS_ENABLED(CONFIG_DEBUG_RESET_REASON) { "HSS_ResetReasonInit", HSS_ResetReasonInit, false, false }, #endif { "HSS_BoardLateInit", HSS_BoardLateInit, false, false }, #if IS_ENABLED(CONFIG_SERVICE_MMC) { "HSS_MMCInit", HSS_MMCInit, false, false }, #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI) { "HSS_QSPIInit", HSS_QSPIInit, false, false }, #endif #if IS_ENABLED(CONFIG_SERVICE_BOOT) # if IS_ENABLED(CONFIG_SERVICE_TINYCLI) { "HSS_TinyCLI_Parser", HSS_TinyCLI_Parser, false, false }, # endif # if IS_ENABLED(CONFIG_USE_IHC) { "HSS_IHCInit", HSS_IHCInit, false, false }, # endif { "IPI_QueuesInit", IPI_QueuesInit, false, false }, { "HSS_PMP_Init", HSS_PMP_Init, false, false }, { "HSS_BootInit", HSS_BootInit, false, true }, #endif }; const size_t spanOfGlobalInitFunctions = ARRAY_SIZE(globalInitFunctions); /******************************************************************************************************/ hart-software-services-2022.10/application/hart0/hss_state_machine.c000066400000000000000000000217711432224323300254430ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file State Machine Engine * * \brief Registered state machine super-loop */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_progress.h" #include "hss_clock.h" #include "hss_debug.h" #include #include "ssmb_ipi.h" #include "csr_helper.h" #include "profiling.h" #include "hss_registry.h" #include "u54_state.h" /** * \brief Ensure that state is valid for given state machine */ static inline bool IsValidState(struct StateMachine *pStateMachine, int state) { bool result = false; if ((state >= 0) && (state < (int)pStateMachine->numStates)) { result = true; } return result; } /** * \brief Run all registered state machines */ void RunStateMachine(struct StateMachine *const pCurrentMachine) { assert(pCurrentMachine != NULL); const char *pMachineName = ""; if (pCurrentMachine->pMachineName != NULL) { pMachineName = (const char *)pCurrentMachine->pMachineName; } //mHSS_DEBUG_PRINTF(LOG_NORMAL, "running machine %s\n", pMachineName); { stateType_t prevState = pCurrentMachine->prevState; stateType_t currentState = pCurrentMachine->state; struct StateDesc const * const pCurrentStateDesc = &(pCurrentMachine->pStateDescs[currentState]); assert(pCurrentStateDesc != NULL); // mandatory handler assert(pCurrentStateDesc->state == currentState); HSSTicks_t lastEntry = HSS_GetTime(); if (!pCurrentMachine->startTime) { pCurrentMachine->startTime = lastEntry; } pCurrentMachine->lastExecutionTime = lastEntry; if (prevState != currentState) { if (IsValidState(pCurrentMachine, prevState)) { struct StateDesc const * const pLastStateDesc = &(pCurrentMachine->pStateDescs[prevState]); assert(pLastStateDesc->state == prevState); if (pLastStateDesc->state_onExit) { // optional onExit handler pLastStateDesc->state_onExit(pCurrentMachine); } } if (pCurrentStateDesc->state_onEntry) { // optional onEntry handler pCurrentStateDesc->state_onEntry(pCurrentMachine); } pCurrentMachine->executionCount = 0; pCurrentMachine->prevState = pCurrentMachine->state; } if (likely(pCurrentStateDesc->state_handler != NULL)) { pCurrentStateDesc->state_handler(pCurrentMachine); } ++pCurrentMachine->executionCount; HSSTicks_t lastExit = HSS_GetTime(); pCurrentMachine->lastDeltaExecutionTime = lastExit - lastEntry; if (pCurrentMachine->lastDeltaExecutionTime > pCurrentMachine->maxExecutionTime) { pCurrentMachine->maxExecutionTime = pCurrentMachine->lastDeltaExecutionTime; pCurrentMachine->maxState = pCurrentMachine->prevState; } if (IS_ENABLED(CONFIG_DEBUG_LOG_STATE_TRANSITIONS)) { // debug print any state transitions... if (pCurrentMachine->debugFlag) { // refresh states prevState = pCurrentMachine->prevState; currentState = pCurrentMachine->state; #ifdef DEBUG { const char *pLastStateName = (pCurrentMachine->pStateDescs[prevState]).pStateName; // should be valid at this stage const char *pCurrentStateName = (pCurrentMachine->pStateDescs[currentState]).pStateName; if (prevState != currentState) { mHSS_DEBUG_PRINTF(LOG_STATE_TRANSITION, "%s :: [%s] -> [%s]\n", pMachineName, pLastStateName, pCurrentStateName); } } #endif } } else { (void)pMachineName; } } } static HSSTicks_t maxLoopTime = 0u; static uint64_t loopCount = 0u; void RunStateMachines(const size_t spanOfPStateMachines, struct StateMachine *const pStateMachines[]) { HSSTicks_t const startTicks = HSS_GetTickCount(); HSSTicks_t endTicks; if (!IS_ENABLED(CONFIG_SERVICE_IPI_POLL)) { // poll IPIs each iteration for new messages const union HSSHartBitmask hartBitmask = { .uint = mHSS_BITMASK_ALL_U54 }; bool status = IPI_PollReceive(hartBitmask); if (status) { enum HSSHartId const myHartId = current_hartid(); size_t i; for (i = 0u; i < MAX_NUM_HARTS; ++i) { if (unlikely(i == myHartId)) { continue; } // don't handle messages if to myself uint32_t index = IPI_CalculateQueueIndex(i, myHartId); if (IPI_GetQueuePendingCount(index)) { IPI_ConsumeIntent(i, IPI_MSG_ACK_COMPLETE); // gobble up any ACK completes IPI_ConsumeIntent(i, IPI_MSG_ACK_PENDING); // gobble up any ACK pendings } } } } { size_t i = 0u; for (i = 0; i < spanOfPStateMachines; ++i) { struct StateMachine * const pCurrentMachine = pStateMachines[i]; RunStateMachine(pCurrentMachine); } } ++loopCount; endTicks = HSS_GetTickCount(); if (IS_ENABLED(CONFIG_DEBUG_LOOP_TIMES) || IS_ENABLED(CONFIG_DEBUG_IPI_STATS)) { HSSTicks_t const delta = endTicks - startTicks; bool dump_flag = false; bool max_exceeded_flag = false; if (unlikely(delta > maxLoopTime)) { maxLoopTime = delta; max_exceeded_flag = true; } HSS_U54_DumpStatesIfChanged(); #if IS_ENABLED(CONFIG_DEBUG_LOOP_TIMES) if (unlikely((loopCount % (unsigned long)CONFIG_DEBUG_LOOP_TIMES_THRESHOLD) == 0u)) { dump_flag = true; } #endif if (unlikely(dump_flag || max_exceeded_flag)) { if (IS_ENABLED(CONFIG_DEBUG_PROFILING_SUPPORT)) { dump_profile(); } if (IS_ENABLED(CONFIG_DEBUG_IPI_STATS)) { IPI_DebugDumpStats(); } if (IS_ENABLED(CONFIG_DEBUG_LOOP_TIMES)) { if (dump_flag) { mHSS_DEBUG_PRINTF(LOG_STATUS, "loop %" PRIu64 " took %" PRIu64 " tick%s (max %" PRIu64 " tick%s)\n", loopCount, delta, delta == 1u ? "" : "s", maxLoopTime, maxLoopTime == 1u ? "" : "s"); } else /* if (max_exceeded_flag) */ { mHSS_DEBUG_PRINTF(LOG_WARN, "loop %" PRIu64 " took %" PRIu64 " tick%s (max %" PRIu64 " tick%s)\n", loopCount, delta, delta == 1u ? "" : "s", maxLoopTime, maxLoopTime == 1u ? "" : "s"); } } } } else { (void)startTicks; (void)endTicks; (void)loopCount; (void)maxLoopTime; } } /** * \brief Get State Machines loop count */ uint64_t GetStateMachinesExecutionCount(void) { return loopCount; } /** * \brief Run through array of InitFunctions */ void RunInitFunctions(const size_t spanOfInitFunctions, const struct InitFunction initFunctions[]) { size_t i; for (i = 0u; i < spanOfInitFunctions; ++i) { assert(initFunctions[i].handler); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Running %d of %d: %s()\n", i, spanOfInitFunctions, // initFunctions[i].pName); bool result = (initFunctions[i].handler)(); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s() returned %d\n", initFunctions[i].pName, result); if (initFunctions[i].haltOnFailure) { while (true) { ; } // HALT on failure } else if (initFunctions[i].restartOnFailure) { uint8_t rcvBuf; bool keyPressedFlag = HSS_ShowTimeout("Init failed, press a key to prevent restart\n", 5u, &rcvBuf); if (IS_ENABLED(CONFIG_SERVICE_TINYCLI) && keyPressedFlag) { bool HSS_TinyCLI_Parser(void); (void)HSS_TinyCLI_Parser(); } else { void _start(void); _start(); } } } } } void DumpStateMachineStats(void) { mHSS_DEBUG_PRINTF(LOG_STATUS, " State Machine Name: Max Exec Time / State : Last Delta Time / Current State\n"); for (size_t i = 0u; i < spanOfPGlobalStateMachines; i++) { mHSS_DEBUG_PRINTF(LOG_STATUS, "%19s: % 13" PRIu64 " / % 2" PRIu64 " : % 15" PRIu64 " / % 2" PRIu64 "\n", pGlobalStateMachines[i]->pMachineName, pGlobalStateMachines[i]->maxExecutionTime, pGlobalStateMachines[i]->maxState, pGlobalStateMachines[i]->lastDeltaExecutionTime, pGlobalStateMachines[i]->state); } } hart-software-services-2022.10/application/hart1-4/000077500000000000000000000000001432224323300217505ustar00rootroot00000000000000hart-software-services-2022.10/application/hart1-4/u54_handle_ipi.c000066400000000000000000000101521432224323300247040ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file U54 Handle IPI * \brief U54 Handle IPI */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include #include "csr_helper.h" #include "ssmb_ipi.h" #include "goto_service.h" #include "opensbi_service.h" #if IS_ENABLED(CONFIG_SERVICE_BOOT) # include "hss_boot_pmp.h" #endif #include "csr_helper.h" #include "u54_handle_ipi.h" #include "u54_state.h" #include "hss_atomic.h" #if IS_ENABLED(CONFIG_HSS_USE_IHC) # include "mss_plic.h" # include "miv_ihc.h" #endif // // This routine gets executed when a U54 receives an IPI from E51 in machine mode... // #if !IS_ENABLED(CONFIG_HSS_USE_IHC) static const struct IntentsArray { enum IPIMessagesEnum msg_type; } intentsArray[] = { #if IS_ENABLED(CONFIG_SERVICE_BOOT) { IPI_MSG_PMP_SETUP }, #endif #if IS_ENABLED(CONFIG_SERVICE_GOTO) { IPI_MSG_GOTO }, #endif #if IS_ENABLED(CONFIG_SERVICE_OPENSBI) { IPI_MSG_OPENSBI_INIT }, #endif }; #endif bool HSS_U54_ConsumeIntent(enum IPIMessagesEnum msg_type); bool HSS_U54_ConsumeIntent(enum IPIMessagesEnum msg_type) { bool result = false; #if IS_ENABLED(CONFIG_HSS_USE_IHC) result = IPI_ConsumeIntent(HSS_HART_E51, msg_type); #endif return result; } bool HSS_U54_HandleIPI(void); bool HSS_U54_HandleIPI(void) { bool result = false; #if IS_ENABLED(CONFIG_HSS_USE_IHC) enum HSSHartId my_hartid = current_hartid(); __extension__ const uint32_t hartid_to_ihc_ext_interrupt[HSS_HART_NUM_PEERS] = { [ HSS_HART_E51 ] = 0u, [ HSS_HART_U54_1 ] = IHCIA_hart1_INT, [ HSS_HART_U54_2 ] = IHCIA_hart2_INT, [ HSS_HART_U54_3 ] = IHCIA_hart3_INT, [ HSS_HART_U54_4 ] = IHCIA_hart4_INT, }; assert((my_hartid < HSS_HART_NUM_PEERS) && (my_hartid >= 0)); #define MCAUSE64_INT 0x8000000000000000llu #define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFFllu volatile uint64_t mcause = csr_read(mcause); if (((mcause & MCAUSE64_INT) == MCAUSE64_INT) && ((mcause & MCAUSE64_CAUSE) == IRQ_M_EXT)) { uint32_t my_ihc_interrupt; switch (my_hartid) { case HSS_HART_U54_1: __attribute__((fallthrough)); /* deliberately fallthrough */ case HSS_HART_U54_2: __attribute__((fallthrough)); /* deliberately fallthrough */ case HSS_HART_U54_3: __attribute__((fallthrough)); /* deliberately fallthrough */ case HSS_HART_U54_4: my_ihc_interrupt = hartid_to_ihc_ext_interrupt[my_hartid]; if (PLIC_pending(my_ihc_interrupt)) { int interrupt = PLIC_ClaimIRQ(); assert(interrupt == my_ihc_interrupt); PLIC_CompleteIRQ(my_ihc_interrupt); IHC_message_present_poll(); __sync_synchronize(); result = true; } break; case HSS_HART_E51: __attribute__((fallthrough)); /* deliberately fallthrough */ default: break; } } #else bool intentFound = false; for (int i = 0; i < ARRAY_SIZE(intentsArray); i++) { intentFound = IPI_ConsumeIntent(HSS_HART_E51, intentsArray[i].msg_type) | intentFound; } result = intentFound; #endif // in testing, for harts that aren't in either its domain or the root domain, U-Boot still seems to // be generating some unexpected MSIP interrupts which otherwise never get cleared so if not using // OpenSBI we could clear explicitly here, but it could affect baremetal SMP... // if ( // #if !IS_ENABLED(CONFIG_HSS_USE_IHC) // intentFound || // #endif // !mpfs_is_hart_using_opensbi(my_hartid)) { // CSR_ClearMSIP(); // } return result; } void HSS_U54_Banner(void) { // wait for E51 to setup BSS... HSS_U54_SetState(HSS_State_Idle); mHSS_DEBUG_PRINTF(LOG_NORMAL, "u54_%d: Waiting for E51 instruction\n", current_hartid()); } hart-software-services-2022.10/application/hart1-4/u54_state.c000066400000000000000000000066071432224323300237420ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file U54 States * \brief U54 States */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include #include "csr_helper.h" #include "u54_state.h" static enum HSSHartState_t hartStates[HSS_HART_NUM_PEERS] = { 0u, }; void HSS_U54_SetState(int state) { int const myHartId = current_hartid(); switch (myHartId) { case HSS_HART_U54_1 ... HSS_HART_U54_4: //mHSS_DEBUG_PRINTF(LOG_STATE_TRANSITION, "u54_%d :: [%s] -> [%s]\n", myHartId, // HSS_U54_GetStateName(HSS_U54_GetState_Ex(myHartId)), HSS_U54_GetStateName(state)); HSS_U54_SetState_Ex(myHartId, state); break; default: // out of bounds assert((myHartId >= HSS_HART_U54_1) && (myHartId <= HSS_HART_U54_4)); break; } } int HSS_U54_GetState(void) { int result = HSS_State_Idle; int const myHartId = current_hartid(); switch (myHartId) { case HSS_HART_U54_1 ... HSS_HART_U54_4: result = HSS_U54_GetState_Ex(myHartId); break; default: // out of bounds assert((myHartId >= HSS_HART_U54_1) && (myHartId <= HSS_HART_U54_4)); break; } return result; } int HSS_U54_GetState_Ex(int hartId) { int result; __atomic_load(&(hartStates[hartId]), &result, __ATOMIC_RELAXED); return result; } static char const * const hartStateNames[] = { [ HSS_State_Idle ] = "Idle", [ HSS_State_Booting ] = "Booting", [ HSS_State_SBIHartInit ] = "SBIHartInit", [ HSS_State_SBIWaitForColdboot ] = "SBIWaitForColdboot", [ HSS_State_Running ] = "Running", [ HSS_State_Trap ] = "Trap", [ HSS_State_Fatal ] = "Fatal", }; char const * HSS_U54_GetStateName(int state) { char const * result = NULL; if ((state >= HSS_State_Idle) && (state <= HSS_State_Fatal)) { result = hartStateNames[state]; } return result; } static long reportingFlag = 0u; void HSS_U54_SetState_Ex(int hartId, int state) { switch (hartId) { case HSS_HART_U54_1 ... HSS_HART_U54_4: __atomic_store(&(hartStates[hartId]), &state, __ATOMIC_RELAXED); hartStates[hartId] = state; __atomic_store_n(&reportingFlag, 1, __ATOMIC_RELAXED); break; default: // out of bounds assert((hartId >= HSS_HART_U54_1) && (hartId <= HSS_HART_U54_4)); break; } } void HSS_U54_DumpStatesIfChanged(void) { long retval = 0u; __atomic_load(&reportingFlag, &retval, __ATOMIC_RELAXED); if (retval) { mHSS_DEBUG_PRINTF(LOG_STATE_TRANSITION, "u54 State Change: "); HSS_Debug_Highlight(HSS_DEBUG_LOG_STATE_TRANSITION); \ for (int i = HSS_HART_U54_1; i < HSS_HART_NUM_PEERS; i++) { mHSS_DEBUG_PRINTF_EX(" [%s]", HSS_U54_GetStateName(HSS_U54_GetState_Ex(i))); } HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); mHSS_DEBUG_PRINTF_EX("\n"); __atomic_store_n(&reportingFlag, 0, __ATOMIC_RELAXED); } } void HSS_U54_DumpStates(void) { for (int i = HSS_HART_U54_1; i < HSS_HART_NUM_PEERS; i++) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "u54_%d :: [%s]\n", i, HSS_U54_GetStateName(HSS_U54_GetState_Ex(i))); } } hart-software-services-2022.10/application/os.mk000077500000000000000000000033431432224323300215500ustar00rootroot00000000000000# # OS Portability Abstraction # # Detect if running under: # Windows/Command Line # Windows/SoftConsole # Linux/Command Line (in Desktop, including with/without SoftConsole) # Linux/Command Line (via terminal) # ifeq ($(OS), Windows_NT) #If we need to patch up path for Windows, we could do it here... #TOOLPATH:=${SC_INSTALL_DIR}riscv-unknown-elf-gcc\bin #export PATH:="$(TOOLPATH);$(PATH)" $(info INFO: Windows detected) HOST_WINDOWS:=true PYTHON?=python.exe MPFS_BOOTMODE_PROGRAMMER = $(SC_INSTALL_DIR)\eclipse\jre\bin\java.exe -jar $(SC_INSTALL_DIR)\extras\mpfs\mpfsBootmodeProgrammer.jar MPFS_BOOTMODE_PROGRAMMER:=$(subst \,/,$(MPFS_BOOTMODE_PROGRAMMER)) export SC_INSTALL_DIR:=$(subst \,/,$(SC_INSTALL_DIR)) else SYSTEM:=$(shell uname -s) ifneq (, $(findstring Linux, $(SYSTEM))) # Linux-specific mods # Workaround SoftConsole v2021.1 Linux Python limitations by using system python export PATH:=/usr/bin:$(PATH) $(info INFO: Linux detected) HOST_LINUX:=true PYTHON?=python3 MPFS_BOOTMODE_PROGRAMMER = $(SC_INSTALL_DIR)/eclipse/jre/bin/java -jar $(SC_INSTALL_DIR)/extras/mpfs/mpfsBootmodeProgrammer.jar ifneq ($(origin XDG_SESSION_DESKTOP),undefined) HOST_LINUX_DESKTOP:=true $(info INFO: Linux Desktop detected) endif # # We could detect if running in SoftConsole on Linux, but we don't need to # as just detected a Desktop environment allows us run the guiconfig tool #ifeq ($(origin XDG_SESSION_CLASS),undefined) # HOST_LINUX_SOFTCONSOLE:=true #endif else $(error Unsupported build platform $(SYSTEM)) endif endif #$(info INFO: MPFS_BOOTMODE_PROGRAMMER is $(MPFS_BOOTMODE_PROGRAMMER)) #$(info INFO: SC_INSTALL_DIR is $(SC_INSTALL_DIR)) hart-software-services-2022.10/application/rules.mk000066400000000000000000000144311432224323300222560ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Defines Rules such as compiler and tool choice/settings, build flags, and # basic build rules (.c to .o, etc) # CROSS_COMPILE?=riscv64-unknown-elf- #CROSS_COMPILE?=riscv-none-elf- CC=$(CROSS_COMPILE)gcc RANLIB=$(CROSS_COMPILE)ranlib CPP=$(CROSS_COMPILE)cpp LD=$(CROSS_COMPILE)ld SIZE=$(CROSS_COMPILE)size GPROF=$(CROSS_COMPILE)gprof OBJCOPY=$(CROSS_COMPILE)objcopy OBJDUMP=$(CROSS_COMPILE)objdump READELF=$(CROSS_COMPILE)readelf NM=$(CROSS_COMPILE)nm ECHO=echo MAKE=make CP=cp MAKEDEP=makedepend GENCONFIG:=thirdparty/Kconfiglib/genconfig.py MENUCONFIG:=thirdparty/Kconfiglib/menuconfig.py GUICONFIG:=thirdparty/Kconfiglib/guiconfig.py # # PLATFORM_RISCV_ABI=lp64 #PLATFORM_RISCV_ISA=rv64imac_zicsr_zifencei PLATFORM_RISCV_ISA=rv64imac CORE_CFLAGS+=$(MCMODEL) -mstrict-align CORE_CFLAGS+=-mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) # Debug options CORE_CFLAGS+=-g3 -DDEBUG -pipe -grecord-gcc-switches #CORE_CFLAGS+=-pipe # Warning / Code Quality CORE_CFLAGS+=-Wall -Werror -Wshadow -fno-builtin -fno-builtin-printf \ -fomit-frame-pointer -Wredundant-decls -Wall -Wundef -Wwrite-strings -fno-strict-aliasing \ -fno-common -Wendif-labels -Wmissing-include-dirs -Wempty-body -Wformat=2 -Wformat-security \ -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition \ -Wtype-limits -Wstrict-prototypes -Wimplicit-fallthrough=5 CORE_CFLAGS+=-mno-fdiv # CORE_CFLAGS+=-fanalyzer # Compiler hooks to enable link-time garbage collection CORE_CFLAGS+=-ffunction-sections -fdata-sections # Stack Usage ifdef CONFIG_CC_DUMP_STACKSIZE CORE_CFLAGS+=-fstack-usage endif #-ffreestanding # TODO - introduce the following prototype warnings... CORE_CFLAGS+=-Wmissing-prototypes # TODO - introduce the following conversion warnings... Currently fails on drivers and OpenSBI #CORE_CFLAGS+=-Wconversion # TODO - introduce trapv for integer overflows etc... Currently missing primitives #CORE_CFLAGS+=-ftrapv CFLAGS=-std=c11 $(CORE_CFLAGS) $(PLATFORM_CFLAGS) -Wmissing-prototypes # separate flags for C files that need GCC Extensions... CFLAGS_GCCEXT=$(CORE_CFLAGS) $(PLATFORM_CFLAGS) #OPT-y=-O2 #OPT-y+=-Os -funroll-loops -fpeel-loops -fgcse-sm -fgcse-las OPT-y+=-Os -fno-strict-aliasing -fwhole-program -Wno-lto-type-mismatch #OPT-y+=-Os -fno-strict-aliasing ifndef CONFIG_LD_RELAX OPT-y+=-Wl,--no-relax endif # # for some reason, -flto isn't playing nicely currently with -fstack-protector-strong... # Stack protection is really useful, but if it is enabled, for now disabling LTO optimisation # ifdef CONFIG_CC_STACKPROTECTOR_STRONG $(info INFO: Not enabling -flto as stack protector enabled) CORE_CFLAGS+=-fstack-protector-strong # CORE_CFLAGS+=-fstack-clash-protection # currently does nothing on RISC-V else $(info INFO: NOTICE: enabling -flto (which means stack protection is disabled)) OPT-y+=-flto=auto -ffat-lto-objects -fcompare-debug -fno-stack-protector endif ############################################################################## # # Sanity Checks # # is compile toolchain what we are expecting? ifeq ($(HOST_LINUX), true) ifeq ($, $(shell which $(CC))) $(error "No $(CC) in $(PATH)" endif CC_VERSION = $(strip $(shell $(CC) -dumpversion)) EXPECTED_CC_VERSION := 8.3.0 ifneq ($(CC_VERSION),$(EXPECTED_CC_VERSION)) $(info INFO: Expected $(CC) version $(EXPECTED_CC_VERSION) but found $(CC_VERSION)) endif CC_MACHINE = $(strip $(shell $(CC) -dumpmachine)) EXPECTED_CC_MACHINE := riscv64-unknown-elf ifneq ($(CC_MACHINE),$(EXPECTED_CC_MACHINE)) $(info INFO: Expected $(CC) version $(EXPECTED_CC_MACHINE) but found $(CC_MACHINE)) endif endif ############################################################################## # # Build Rules # ifeq ($(V), 1) else .SILENT: endif OBJS = $(SRCS-y:.c=.o) EXTRA_OBJS += $(EXTRA_SRCS-y:.c=.o) $(ASM_SRCS:.S=.o) $(EXTRA_OBJS-y) $(ASM_SRCS-y:.S=.o) .SUFFIXES: %.s: %.c config.h $(ECHO) " CC -s $@" $(CC) $(CFLAGS_GCCEXT) $(OPT-y) $(INCLUDES) -c -S -g $< -o $@ %.S: %.c config.h $(ECHO) " CC -S $@" $(CC) $(CFLAGS_GCCEXT) $(OPT-y) $(INCLUDES) -c -Wa,-adhln -g $< > $@ %.e: %.c config.h $(ECHO) " CC -E $@" $(CC) $(CFLAGS_GCCEXT) $(OPT-y) $(INCLUDES) -c -E -o $@ $< %.e: %.s config.h $(ECHO) " CC -E $@" $(CC) $(CFLAGS_GCCEXT) $(OPT-y) $(INCLUDES) -c -E -o $@ $< ifdef CONFIG_CC_USE_MAKEDEP %.o: %.c config.h %.d else %.o: %.c config.h endif $(ECHO) " CC $@" $(CC) $(CFLAGS) $(OPT-y) $(INCLUDES) -c -o $@ $< %.o: %.S config.h $(ECHO) " CC $@" $(CC) $(CFLAGS) $(OPT-y) $(INCLUDES) -D__ASSEMBLY__=1 -c -o $@ $< #%.hex: %.elf # $(ECHO) " HEX $@" # $(OBJCOPY) -O ihex $< $@ # $(OBJCOPY) -O ihex $< Default/$@ %.lss: %.elf $(ECHO) " LSS $@" $(OBJDUMP) -h -S -z $< > $@ %.sym: %.elf $(ECHO) " NM $@" $(NM) -n $< > $@ %.bin: %.elf $(ECHO) " BIN $@" $(OBJCOPY) -O binary $< $@ %.ld: %.lds config.h $(ECHO) " CPP $@" $(CPP) -P $(INCLUDES) $< -o $@ # %.d: %.c $(MAKEDEP) -f - $(INCLUDES) $< 2>/dev/null | sed 's,\($*\.o\)[ :]*\(.*\),$@ : $$\(wildcard \2\)\n\1 : \2,g' > $*.d %.d: %.S $(MAKEDEP) -f - $(INCLUDES) $< 2>/dev/null | sed 's,\($*\.o\)[ :]*\(.*\),$@ : $$\(wildcard \2\)\n\1 : \2,g' > $*.d hart-software-services-2022.10/application/targets.mk000066400000000000000000000162271432224323300226020ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Defines build targets # all: config.h $(TARGET) ############################################################################## # # KConfig support # defconfig: @$(ECHO) " CP def_config"; cp boards/${BOARD}/def_config .config @$(ECHO) " GENCONFIG" $(PYTHON) $(GENCONFIG) menuconfig: @$(ECHO) " MENUCONFIG" $(PYTHON) $(MENUCONFIG) config: @$(ECHO) " MENUCONFIG" $(PYTHON) $(MENUCONFIG) guiconfig: @$(ECHO) " GUICONFIG" $(PYTHON) $(GUICONFIG) # we can't run curses in SoftConsole, so just copy a pre-canned # config, and the user can tweak if necessary .config: ifeq ($(HOST_WINDOWS), true) $(info Using boards/${BOARD}/def_config - edit as necessary.) @$(ECHO) " CP def_config"; cp boards/${BOARD}/def_config .config @$(ECHO) " GENCONFIG" $(PYTHON) $(GENCONFIG) else ifeq ($(HOST_LINUX_DESKTOP), true) @$(ECHO) " CP def_config"; cp boards/${BOARD}/def_config .config @$(ECHO) " GUICONFIG" $(PYTHON) $(GUICONFIG) else @$(ECHO) " CP def_config"; cp boards/${BOARD}/def_config .config @$(ECHO) " MENUCONFIG" $(PYTHON) $(MENUCONFIG) endif endif config.h: .config @$(ECHO) " GENCONFIG" $(PYTHON) $(GENCONFIG) genconfig: config.h ############################################################################## # # Build Targets # #coverage: CORE_CFLAGS +=-fsanitize=address coverage: CORE_CFLAGS +=-fprofile-arcs -ftest-coverage coverage: OPT-y:=-O0 # lcov seg-faults without at least -O1 for some reason.. coverage: clean $(TARGET) profile: CFLAGS +=-pg -DLOOP_COUNT=10000 profile: clean $(TARGET) ./$(TARGET) >/dev/null 2>/dev/null $(GPROF) $(TARGET) |less .PHONY: clean cppcheck splint cscope cscope.files clean: envm-wrapper_clean $(RM) $(TARGET) $(TEST_TARGET) cppcheck.log splint.log valgrind.log \ $(OBJS:.o=.gcda) $(OBJS) $(OBJS:.o=.gcno) $(OBJS:.o=.c.gcov) $(OBJS:.o=.su) \ $(EXTRA_OBJS) $(EXTRA_OBJS:.o=.c.gcov) $(EXTRA_OBJS:.o=.su) \ $(TEST_OBJS) $(TEST_OBJS.o=.gcno) $(TEST_OBJS.o=.c.gcov) $(TEST_OBJS:.o=.su) \ $(DEPENDENCIES) \ gmon.out cscope.out \ error.log flawfinder.log sparse.log $(BINDIR)/output-*.map config.h \ $(TARGET:.elf=.hex) $(TARGET:.elf=.lss) $(TARGET:.elf=.sym) $(TARGET:.elf=.bin) $(RM) -r docs/DoxygenOutput $(RM) -r lcovOutput coverage.info $(RM) *.gcov $(RM) *.lss *.hex *.sym $(RM) $(BINDIR)/hss* $(BINDIR)/output.map $(RM) x509-ec-secp384r1-public.h distclean: $(RM) $(OBJS) $(TARGET) cppcheck.log splint.log valgrind.log \ cscope.out cscope.files $(RM) -r docs/DoxygenOutput cppcheck: $(SRCS-y) cppcheck --suppress=missingIncludeSystem -v --enable=all --inconclusive --std=posix \ -ibaremetal/polarfire-soc-bare-metal-library/examples -ithirdparty \ $(INCLUDES) -UDECLARE_CAUSE -UDECLARE_CSR -UDECLARE_INSN --force . \ >cppcheck.log 2>&1 sparse: REAL_CC:=$(CC) sparse: MCMODEL:= sparse: CC=cgcc sparse: clean $(TARGET) smatch: $(SRCS-y) $(EXTRA_SRCS-y) $(TEST_SRCS) smatch $(INCLUDES) $(SRCS-y) $(EXTRA_SRCS-y) $(TEST_SRCS) splint: $(SRCS-y) find . -name \*.c -exec splint +posixlib -DPRIu64=\"llu\" -Dtarget_ulong="unsigned long" \ -Dasm="(void)" -weak $(INCLUDES) \ -D__riscv_xlen=64 -D__SIZEOF_POINTER__=8 -D__SIZEOF_INT__=4 -D__SIZEOF_SHORT__=2 \ \{\} \; >splint.log 2>&1 cscope: cscope.files cscope.out cscope.files: find . -name \*.[chS] > cscope.files cscope.out: cscope.files cscope -b lcov: coverage ./$(TARGET) | tee foo lcov --capture --directory . --output-file coverage.info lcov --remove coverage.info '/usr/include/*' 'test/*' --output-file coverage2.info mv coverage2.info coverage.info genhtml coverage.info --output-directory lcovOutput showloc: @$(ECHO) -n "There are " && \ $(ECHO) -n `find . -name \*.[chs] -exec wc -l \{\} \; | awk '{count += $$1;} END { print count;}'` && \ $(ECHO) " lines of source code" valgrind: CC=cc valgrind: MCMODEL:= valgrind: $(TARGET) valgrind -v --tool=memcheck --show-reachable=yes --leak-check=yes --track-origins=yes \ ./$(TARGET) 2> valgrind.log doxygen: doxygen docs/doxygen.cfg $(MAKE) -C docs/DoxygenOutput/latex all flawfinder: flawfinder `find . -type d | grep -v thirdparty | grep -v .git | grep -v baremetal | tail -n +2` baremetal/drivers baremetal/polarfire-soc-bare-metal-library/src >flawfinder.log showsize: $(BINDIR)/hss-l2lim.elf @echo @$(SIZE) $(BINDIR)/hss-l2lim.elf showfullsize: $(BINDIR)/hss-l2lim.elf @echo @$(NM) --print-size --size-sort --radix=x $(BINDIR)/hss-l2lim.elf @$(READELF) -e $(BINDIR)/hss-l2lim.elf ifdef CONFIG_CC_DUMP_STACKSIZE showstack: hss-envm.elf @echo @cat `find . -name \*.su` | awk '{print $$2 " " $$0}' | sort -rn | cut -d " " -f 2- | head -20 showmaxstack: hss-envm.elf @echo @cat `find . -name \*.su` | awk '$$2>a {a=$$2; b=$$0} END {print b}' endif .PHONY: config clean docs distclean doxygen showsize \ cppcheck splint sparse smatch cscope lcov valgrind flawfinder help: @$(ECHO) "Valid targets include:" @$(ECHO) " $ make" $(TARGET) " # Build binary" @$(ECHO) " $ make clean # Delete all built files" @$(ECHO) " $ make distclean # Fully clean all built files and test outputs" @$(ECHO) "" @$(ECHO) " $ make doxygen # Generate doxygen documentation" @$(ECHO) " $ make cppcheck # Run cppcheck on source code" @$(ECHO) " $ make splint # Run splint on source code" @$(ECHO) " $ make sparse # Run sparse on source code" @$(ECHO) " $ make smatch # Run smatch on source code" @$(ECHO) " $ make cscope # Build cscope database" @$(ECHO) " $ make lcov # Rebuild instrumented binaries and run lcov" @$(ECHO) " $ make valgrind # Run valgrind on binary" @$(ECHO) " $ make flawfinder # Run flawfinder on this directory" @$(ECHO) "" @$(ECHO) " $ make showloc # Print number of lines of code" @$(ECHO) " $ make showsize # Print information about binary size" @$(ECHO) " $ make showfullsize # Dump detailed information about object sizes" ifdef CONFIG_CC_DUMP_STACKSIZE @$(ECHO) " $ make showstack # Print top 10 functions by stack usage" @$(ECHO) " $ make showmaxstack # Print top function by stack usage" endif @$(ECHO) " $ make dep # Remake dependencies" hart-software-services-2022.10/baremetal/000077500000000000000000000000001432224323300202215ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/Makefile000066400000000000000000000173661432224323300216760ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Baremetal Drivers and HAL Support EXTRA_SRCS-y += \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_pdma/mss_pdma.c \ ifdef CONFIG_PLATFORM_MPFS EXTRA_SRCS-$(CONFIG_SERVICE_QSPI) += \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_qspi/mss_qspi.c \ EXTRA_SRCS-$(CONFIG_SERVICE_MMC) += \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/mss_mmc.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/mss_mmc_if.c \ EXTRA_SRCS-$(CONFIG_USE_IHC) += \ baremetal/drivers/fpga_ip/miv_ihc/miv_ihc.c \ endif EXTRA_SRCS-$(CONFIG_PLATFORM_MPFS) += \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart/mss_uart.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_sys_services/mss_sys_services.c \ baremetal/drivers/mss/mss_watchdog/mss_watchdog.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_mpu.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_peripherals.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_plic.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_l2_cache.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_util.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_nwc_init.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_io.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_pll.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_pmp.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_sgmii.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/system_startup.c \ ifndef CONFIG_SKIP_DDR EXTRA_SRCS-$(CONFIG_PLATFORM_MPFS) += \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_ddr.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_ddr_debug.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_ddr_test_pattern.c \ endif ASM_SRCS += \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/mss_utils.S \ # baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/mss_mutex.S \ INCLUDES += \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_qspi \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_pdma \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_sys_services \ -Ibaremetal/drivers/mss/mss_watchdog \ -Ibaremetal/drivers/fpga_ip/miv_ihc \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/hal \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/ \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/mss_mmc.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_qspi/mss_qspi.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart/mss_uart.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_pdma/mss_pdma.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/mss/mss_watchdog/mss_watchdog.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/fpga_ip/miv_ihc/miv_ihc.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/system_startup.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_nwc_init.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_ddr.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_ddr_debug.o: CFLAGS=$(CFLAGS_GCCEXT) -DHSS baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_io.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_pll.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_sgmii.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_l2_cache.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_util.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_sys_services/mss_sys_services.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_mpu.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_peripherals.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_plic.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_pmp.o: CFLAGS=$(CFLAGS_GCCEXT) ################################################################################################# # # USB ifdef CONFIG_PLATFORM_MPFS INCLUDES += \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_gpio \ SRCS-$(CONFIG_SERVICE_USBDMSC) += \ baremetal/drivers/mss/mss_usb/mss_usb_common_cif.c \ baremetal/drivers/mss/mss_usb/mss_usb_device.c \ baremetal/drivers/mss/mss_usb/mss_usb_device_cif.c \ baremetal/drivers/mss/mss_usb/mss_usb_device_msd.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/hal/hal_irq.c \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_gpio/mss_gpio.c \ endif baremetal/drivers/mss/mss_usb/mss_usb_common_cif.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/mss/mss_usb/mss_usb_device.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/mss/mss_usb/mss_usb_device_cif.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/mss/mss_usb/mss_usb_device_msd.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/hal/hal_irq.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_gpio/mss_gpio.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/baremetal/README.md000066400000000000000000000012221432224323300214750ustar00rootroot00000000000000# Subtrees `polarfire-soc-bare-metal-library` is a git subtree. It was created as a subtree using: $ git remote add -f polarfire-soc-bare-metal-library https://bitbucket.microchip.com/scm/fpga_pfsoc_es/polarfire-soc-bare-metal-library.git $ git subtree add --prefix baremetal/polarfire-soc-bare-metal-library polarfire-soc-bare-metal-library master --squash To update the bare metal drivers, use: $ git fetch polarfire-soc-bare-metal-library master $ git subtree pull --prefix baremetal/polarfire-soc-bare-metal-library polarfire-soc-bare-metal-library master --squash ## Notes The `examples` and `config` subdirectories were removed. hart-software-services-2022.10/baremetal/drivers/000077500000000000000000000000001432224323300216775ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/fpga_ip/000077500000000000000000000000001432224323300233045ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/000077500000000000000000000000001432224323300247225ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc.c000066400000000000000000000563561432224323300265230ustar00rootroot00000000000000/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC Microprocessor Subsystem Inter-Hart Communication bare metal * software driver implementation. * */ #include "mpfs_hal/mss_hal.h" #include "miv_ihc.h" /******************************************************************************/ /* defines */ /******************************************************************************/ #define NO_CONTEXT_INCOMING_ACK_OR_DATA 99U #define INVALID_HART_ID 0xFFU /******************************************************************************/ /* configuration arrays populated from user defines */ /******************************************************************************/ IHC_TypeDef IHC_H0_IP_GROUP ; IHC_TypeDef IHC_H1_IP_GROUP ; IHC_TypeDef IHC_H2_IP_GROUP ; IHC_TypeDef IHC_H3_IP_GROUP ; IHC_TypeDef IHC_H4_IP_GROUP ; IHC_TypeDef * IHC[] = { &IHC_H0_IP_GROUP , &IHC_H1_IP_GROUP, &IHC_H2_IP_GROUP, &IHC_H3_IP_GROUP, &IHC_H4_IP_GROUP}; /** * \brief IHC configuration * */ const uint64_t ihc_base_addess[][5U] = { /* hart 0 */ {0x0, IHC_LOCAL_H0_REMOTE_H1, IHC_LOCAL_H0_REMOTE_H2, IHC_LOCAL_H0_REMOTE_H3, IHC_LOCAL_H0_REMOTE_H4}, /* hart 1 */ {IHC_LOCAL_H1_REMOTE_H0, 0x0, IHC_LOCAL_H1_REMOTE_H2, IHC_LOCAL_H1_REMOTE_H3, IHC_LOCAL_H1_REMOTE_H4}, /* hart 2 */ {IHC_LOCAL_H2_REMOTE_H0, IHC_LOCAL_H2_REMOTE_H1, 0x0, IHC_LOCAL_H2_REMOTE_H3, IHC_LOCAL_H2_REMOTE_H4}, /* hart 3 */ {IHC_LOCAL_H3_REMOTE_H0, IHC_LOCAL_H3_REMOTE_H1, IHC_LOCAL_H3_REMOTE_H2, 0x0, IHC_LOCAL_H3_REMOTE_H4}, /* hart 4 */ {IHC_LOCAL_H4_REMOTE_H0, IHC_LOCAL_H4_REMOTE_H1, IHC_LOCAL_H4_REMOTE_H2, IHC_LOCAL_H4_REMOTE_H3, 0x0}, }; /** * \brief IHC configuration * */ const uint64_t IHCIA_base_addess[5U] = { IHCIA_LOCAL_H0, IHCIA_LOCAL_H1, IHCIA_LOCAL_H2, IHCIA_LOCAL_H3, IHCIA_LOCAL_H4 }; /** * \brief Remote harts connected via channel to a local hart * */ const uint32_t IHCIA_remote_harts[5U] = { IHCIA_H0_REMOTE_HARTS, IHCIA_H1_REMOTE_HARTS, IHCIA_H2_REMOTE_HARTS, IHCIA_H3_REMOTE_HARTS, IHCIA_H4_REMOTE_HARTS }; /** * \brief Remote harts connected via channel to a local hart * */ const uint32_t IHCIA_remote_hart_ints[5U] = { IHCIA_H0_REMOTE_HARTS_INTS, IHCIA_H1_REMOTE_HARTS_INTS, IHCIA_H2_REMOTE_HARTS_INTS, IHCIA_H3_REMOTE_HARTS_INTS, IHCIA_H4_REMOTE_HARTS_INTS }; /******************************************************************************/ /* Private Functions */ /******************************************************************************/ static void message_present_isr(void); static uint32_t parse_incoming_hartid(uint32_t my_hart_id, bool *is_ack, bool polling); static uint32_t parse_incoming_context_msg(uint32_t my_hart_id, uint32_t remote_hart_id, bool *is_ack, bool polling); static uint32_t rx_message(uint32_t my_hart_id, uint32_t remote_hart_id, QUEUE_IHC_INCOMING handle_incoming, bool is_ack, uint32_t * message_storage_ptr); static uint32_t lowest_hart_in_context(uint32_t mask); /******************************************************************************/ /* Public API Functions */ /******************************************************************************/ /***************************************************************************//** * IHC_global_init() * * See miv_ihc.h for details of how to use this * function. */ void IHC_global_init(void) { uint32_t remote_hart_id; uint32_t my_hart_id = 0; while(my_hart_id < 5U) { remote_hart_id = 0U; while(remote_hart_id < 5U) { IHC[my_hart_id]->local_h_setup.msg_in_handler[remote_hart_id] = NULL; /* * Configure base addresses */ IHC[my_hart_id]->HART_IHCC[remote_hart_id] = (IHCC_IP_TypeDef *)ihc_base_addess[my_hart_id][remote_hart_id]; IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG = 0U; remote_hart_id++; } /* * Configure base addresses */ IHC[my_hart_id]->HART_IHCIA = (IHCIA_IP_TypeDef *)IHCIA_base_addess[my_hart_id]; /* * Clear interrupt enables */ IHC[my_hart_id]->HART_IHCIA->INT_EN.INT_EN = 0x0U; my_hart_id++; } } /***************************************************************************//** * IHC_local_context_init() * * See miv_ihc.h or miv_ihc user guide for details of how to use this * function. */ void IHC_local_context_init(uint32_t hart_to_configure) { ASSERT(hart_to_configure < 5U); { /* * Configure the base addresses in this hart context * */ uint32_t remote_hart_id = 0U; while(remote_hart_id < 5U) { IHC[hart_to_configure]->local_h_setup.msg_in_handler[remote_hart_id] = NULL; /* * Configure base addresses */ IHC[hart_to_configure]->HART_IHCC[remote_hart_id] = (IHCC_IP_TypeDef *)ihc_base_addess[hart_to_configure][remote_hart_id]; IHC[hart_to_configure]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG = 0U; remote_hart_id++; } /* * Configure base addresses */ IHC[hart_to_configure]->HART_IHCIA = (IHCIA_IP_TypeDef *)IHCIA_base_addess[hart_to_configure]; /* * */ IHC[hart_to_configure]->HART_IHCIA->INT_EN.INT_EN = 0x0U; } IHC[hart_to_configure]->local_h_setup.connected_harts = IHCIA_remote_harts[hart_to_configure]; IHC[hart_to_configure]->local_h_setup.connected_hart_ints = IHCIA_remote_hart_ints[hart_to_configure]; } /***************************************************************************//** * IHC_local_remote_config() * * See miv_ihc.h or miv_ihc user guide for details of how to use this * function. */ void IHC_local_remote_config(uint32_t hart_to_configure, uint32_t remote_hart_id, QUEUE_IHC_INCOMING handler, bool set_mpie_en, bool set_ack_en ) { /* * Set-up enables in aggregator */ IHC[hart_to_configure]->local_h_setup.msg_in_handler[remote_hart_id] = handler; if(handler != NULL) { IHC[hart_to_configure]->HART_IHCIA->INT_EN.INT_EN = IHCIA_remote_hart_ints[hart_to_configure]; } if (set_mpie_en == true) { IHC[hart_to_configure]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG |= MPIE_EN; } if(set_ack_en == true) { IHC[hart_to_configure]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG |= ACKIE_EN; } } /***************************************************************************//** * IHC_tx_message_from_context() * * See miv_ihc.h for details of how to use this * function. */ uint32_t IHC_tx_message_from_context(IHC_CHANNEL remote_channel, uint32_t *message) { uint32_t i, ret_value = MESSAGE_SENT; uint32_t my_hart_id = IHC_partner_context_hart_id(remote_channel); uint32_t remote_hart_id = IHC_context_to_context_hart_id(remote_channel); uint32_t message_size = IHC[my_hart_id]->HART_IHCC[remote_hart_id]->size_msg; ASSERT(my_hart_id != INVALID_HART_ID); ASSERT(remote_hart_id != INVALID_HART_ID); /* * return if RMP bit 1 indicating busy */ if (RMP_MESSAGE_PRESENT == (IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG & RMP_MASK)) { ret_value = MP_BUSY; } else if (ACK_INT_MASK == (IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG & ACK_INT_MASK)) { ret_value = MP_BUSY; } else { /* * Fill the buffer */ for(i = 0;i < message_size; i++) { IHC[my_hart_id]->HART_IHCC[remote_hart_id]->mesg_out[i] = message[i]; } /* * set the MP bit. This will notify other of incoming hart message */ IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG |= RMP_MESSAGE_PRESENT; /* * report status */ ret_value = MESSAGE_SENT; } return (ret_value); } /***************************************************************************//** * IHC_tx_message_from_hart() * * See miv_ihc.h for details of how to use this * function. */ uint32_t IHC_tx_message_from_hart(IHC_CHANNEL remote_channel, uint32_t *message) { uint32_t i, ret_value = MESSAGE_SENT; uint64_t my_hart_id = read_csr(mhartid); uint32_t remote_hart_id = IHC_hart_to_context_or_hart_id(remote_channel); uint32_t message_size = IHC[my_hart_id]->HART_IHCC[remote_hart_id]->size_msg; /* * return if RMP bit 1 indicating busy */ if (RMP_MESSAGE_PRESENT == (IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG & RMP_MASK)) { ret_value = MP_BUSY; } else if (ACK_INT_MASK == (IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG & ACK_INT_MASK)) { ret_value = MP_BUSY; } else { /* * Fill the buffer */ for(i = 0;i < message_size; i++) { IHC[my_hart_id]->HART_IHCC[remote_hart_id]->mesg_out[i] = message[i]; } /* * set the MP bit. This will notify other of incoming hart message */ IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG |= RMP_MESSAGE_PRESENT; /* * report status */ ret_value = MESSAGE_SENT; } return (ret_value); } /***************************************************************************//** * IHC_message_present_poll() * * See miv_ihc.h for details of how to use this * function. */ void IHC_message_present_poll(void) { bool is_ack; uint64_t my_hart_id = read_csr(mhartid); /* * Check all our channels */ uint32_t origin_hart = parse_incoming_hartid((uint32_t)my_hart_id, &is_ack, true); if(origin_hart != NO_CONTEXT_INCOMING_ACK_OR_DATA) { /* * process incoming packet */ rx_message((uint32_t)my_hart_id, origin_hart, IHC[my_hart_id]->local_h_setup.msg_in_handler[origin_hart], is_ack, NULL ); if(is_ack == true) { /* clear the ack */ IHC[my_hart_id]->HART_IHCC[origin_hart]->CTR_REG.CTL_REG &= ~ACK_CLR; } } } /***************************************************************************//** * IHC_context_indirect_isr() * * See miv_ihc.h for details of how to use this * function. */ void IHC_context_indirect_isr(uint32_t * message_storage_ptr) { bool is_ack; uint32_t my_context_hart_id; uint64_t my_hart_id = read_csr(mhartid); IHC_CHANNEL remote_channel; /* * Get the receiving context hart */ my_context_hart_id = IHC_context_to_context_hart_id((uint32_t)my_hart_id); remote_channel = IHC_partner_context_hart_id(my_context_hart_id); if(IHC[my_context_hart_id]->HART_IHCC[0]->version <= 5U) { /* clear the ack and message present if HSS has not cleared */ IHC[my_context_hart_id]->HART_IHCC[0]->CTR_REG.CTL_REG &= ~(ACK_CLR | MP_MASK) ; } if((my_context_hart_id == INVALID_HART_ID) || (remote_channel == INVALID_HART_ID)) { /* HSS hart or no contexts setup */ return; } /* * We know this routine is only called from a context receive, not the HSS. * So we can assume it is the other context is sending us something */ uint32_t origin_hart = parse_incoming_context_msg((uint32_t)my_context_hart_id, remote_channel, &is_ack, false); if(origin_hart != NO_CONTEXT_INCOMING_ACK_OR_DATA) { /* * process incoming packet */ rx_message(my_context_hart_id, origin_hart, IHC[my_context_hart_id]->local_h_setup.msg_in_handler[origin_hart], is_ack, message_storage_ptr ); if(is_ack == true) { /* clear the ack */ IHC[my_context_hart_id]->HART_IHCC[origin_hart]->CTR_REG.CTL_REG &= ~ACK_CLR; } } else { /* * nothing to do */ } } /***************************************************************************//** * parse_incoming_context_msg() * * See miv_ihc.h for details of how to use this * function. */ static uint32_t parse_incoming_context_msg(uint32_t my_hart_id, uint32_t remote_hart_id, bool *is_ack, bool polling) { uint32_t return_hart_id = NO_CONTEXT_INCOMING_ACK_OR_DATA; if(my_hart_id > 5U) return(return_hart_id); if (IHC[my_hart_id]->local_h_setup.connected_harts & (0x01U << remote_hart_id)) { uint32_t test_int = (0x01U << ((remote_hart_id * 2) + 1)); if(IHC[my_hart_id]->HART_IHCIA->MSG_AVAIL_STAT.MSG_AVAIL & test_int) { if (polling == true) { return_hart_id = remote_hart_id; *is_ack = true; return(return_hart_id); } else if(IHC[my_hart_id]->local_h_setup.connected_hart_ints & test_int) { return_hart_id = remote_hart_id; *is_ack = true; return(return_hart_id); } } test_int = (0x01U << (remote_hart_id * 2)); if(IHC[my_hart_id]->HART_IHCIA->MSG_AVAIL_STAT.MSG_AVAIL & test_int) { if (polling == true) { return_hart_id = remote_hart_id; *is_ack = false; return(return_hart_id); } else if(((IHC[my_hart_id]->local_h_setup.connected_hart_ints & test_int) == test_int ) ) { return_hart_id = remote_hart_id; *is_ack = false; return(return_hart_id); } } } return(return_hart_id); } /***************************************************************************//** * IHC_context_to_context_hart_id() * * See miv_ihc.h for details of how to use this * function. */ uint32_t IHC_context_to_context_hart_id(IHC_CHANNEL channel) { uint32_t hart = INVALID_HART_ID; if(channel <= IHC_CHANNEL_TO_HART4) { if ( (1U<local_h_setup.msg_in_handler[origin_hart] */ static void message_present_isr(void) { bool is_ack; uint64_t my_hart_id = read_csr(mhartid); /* * Check all our channels */ uint32_t origin_hart = parse_incoming_hartid((uint32_t)my_hart_id, &is_ack, false); if(origin_hart != NO_CONTEXT_INCOMING_ACK_OR_DATA) { /* * process incoming packet */ rx_message((uint32_t)my_hart_id, origin_hart, IHC[my_hart_id]->local_h_setup.msg_in_handler[origin_hart], is_ack, NULL ); if(is_ack == true) { /* clear the ack */ IHC[my_hart_id]->HART_IHCC[origin_hart]->CTR_REG.CTL_REG &= ~ACK_CLR; } } } /** * rx_message() * Called on receipt of message * @param remote_hart_id * @param handle_incoming This is a point to a function that is provided by * upper layer. It will read/copy the incoming message. * @return */ static uint32_t rx_message(uint32_t my_hart_id, uint32_t remote_hart_id, QUEUE_IHC_INCOMING handle_incoming, bool is_ack, uint32_t * message_storage_ptr) { uint32_t ret_value = NO_MESSAGE_RX; uint32_t message_size = IHC[my_hart_id]->HART_IHCC[remote_hart_id]->size_msg; if (is_ack == true) { handle_incoming(remote_hart_id, (uint32_t *)&IHC[my_hart_id]->HART_IHCC[remote_hart_id]->mesg_in[0U], message_size, is_ack, message_storage_ptr); } else if (MP_MESSAGE_PRESENT == (IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG & MP_MASK)) { /* * check if we have a message */ handle_incoming(remote_hart_id, (uint32_t *)&IHC[my_hart_id]->HART_IHCC[remote_hart_id]->mesg_in[0U], message_size, is_ack, message_storage_ptr); { /* * set MP to 0 * Note this generates an interrupt on the other hart if it has RMPIE * bit set in the control register */ volatile uint32_t temp = IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG & ~MP_MASK; /* Check if ACKIE_EN is set*/ if(temp & ACKIE_EN) { temp |= ACK_INT; } IHC[my_hart_id]->HART_IHCC[remote_hart_id]->CTR_REG.CTL_REG = temp; ret_value = MESSAGE_RX; } } else { /* * report status */ ret_value = NO_MESSAGE_RX; } return (ret_value); } /** * parse_incoming_hartid() * determine origin hartID * @param my_hart_id my hart id * @param is_ack Are we an ack? * @param polling Are we polling true/false * @return returns hart ID of incoming message */ static uint32_t parse_incoming_hartid(uint32_t my_hart_id, bool *is_ack, bool polling) { uint32_t hart_id = 0U; uint32_t return_hart_id = NO_CONTEXT_INCOMING_ACK_OR_DATA; while(hart_id < 5U) { if (IHC[my_hart_id]->local_h_setup.connected_harts & (0x01U << hart_id)) { uint32_t test_int = (0x01U << ((hart_id * 2) + 1)); if(IHC[my_hart_id]->HART_IHCIA->MSG_AVAIL_STAT.MSG_AVAIL & test_int) { if (polling == true) { return_hart_id = hart_id; *is_ack = true; break; } else if(IHC[my_hart_id]->local_h_setup.connected_hart_ints & test_int) { return_hart_id = hart_id; *is_ack = true; break; } } test_int = (0x01U << (hart_id * 2)); if(IHC[my_hart_id]->HART_IHCIA->MSG_AVAIL_STAT.MSG_AVAIL & test_int) { if (polling == true) { return_hart_id = hart_id; *is_ack = false; break; } else if(((IHC[my_hart_id]->local_h_setup.connected_hart_ints & test_int) == test_int ) ) { return_hart_id = hart_id; *is_ack = false; break; } } } hart_id++; } return(return_hart_id); } /***************************************************************************//** * lowest_hart_in_context based on Libero settings() * * See miv_ihc.h for details of how to use this * function. */ static uint32_t lowest_hart_in_context(uint32_t mask) { uint32_t lowest_hart = 0u; if(mask == LIBERO_SETTING_CONTEXT_A_HART_EN ) { lowest_hart = (uint32_t) __builtin_ffs(LIBERO_SETTING_CONTEXT_A_HART_EN); } else { lowest_hart = (uint32_t) __builtin_ffs(LIBERO_SETTING_CONTEXT_B_HART_EN); } if(lowest_hart) return lowest_hart - 1u; else return 0u; } hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc.h000066400000000000000000001013121432224323300265070ustar00rootroot00000000000000/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Bare metal driver for the Mi-V Inter Hart Communication (IHC) subsystem * */ /*=========================================================================*//** @mainpage PolarFire FPGA-IP Mi-V Inter Hart Communication Bare Metal Driver. ============================================================================== Introduction ============================================================================== The Bare metal Mi-V-IHC driver facilitates the use of the Mi-V IHC FPGA-subsystem which allows inter hart/processor communication as part of a HW/SW stack. ============================================================================== Definition of terms ============================================================================== Terms definition - Channel A-B This refers to the communications connection between any two Harts or contexts. ( Note: A Context refers to a collection of harts. Member harts of a context are defined in the MSS Configurator.) - Mi-V Inter Hart Communication Channel (IHCC) This is the IP core for each channel. It has an A and a B side. Each side is configured from the hart associated with each side using the apb bus. - Mi-V Inter Hart Communication Interrupt Aggregator (IHCIA) IP This is the Interrupt Aggregator Core, one for each hart. It takes inputs from the Mi-V IHCC's and generates an interrupt to the connected hart based on the programmed configuration. - Mi-V Inter Hart Communication (IHC) subsystem This is the collection of Mi-V IHCC's and Mi-V IHCIA's which form the Inter hart Communications subsystem. ============================================================================== Driver and IP version ============================================================================== The driver version can be found in the following two places: - The constants section of the User Guide - In the miv_ihc_version.h file IP version - Each module used in the Mi-V IHC contains a read only version register. This can be read to determine the module version. The register is at offset zero from the base of the channel. ============================================================================== Hardware Flow Dependencies ============================================================================== The Mi-V IHC IP must be present in your FPGA design and connected to one of the fabric interface connections. The base addresses of the IP must be mapped as designed. If the default addressing is not used, the base addresses listed in miv_ihc_add_mapping.h must be edited to reflect the base addresses used in the Libero design. Likewise if the connected interrupts deviate from default, the mappings must be updated in the miv_ihc_config.h file to reflect the Libero design. Note that the address mapping is divided into five regions to allow easy use of PMPs to restrict access to memory regions from harts that are not required for that hart. Each Mi-V IHCC has a register set associated with its A and B side, each of which appears in a separate address space associated with the connected core. Below is a simplified view of the Mi-V IHC subsytem. ``` ^ ^ ^ ^ ^ | | | | | +-----------------------------------------------------------------------------------------+ | | Int to hart0 | Int to hart1 | Int to hart2 | Int to hart3 | Int to hart4 | | | | | | | | | +--+--------+ +--+--------+ +--+--------+ +--+--------+ +--+--------+ | | | MiV IHCIA | | MiV IHCIA | | MiV IHCIA | | MiV IHCIA | | MiV IHCIA | | | | hart0 | | hart1 | | hart2 | | hart3 | | hart4 | | | +---+-------+ +^--^-------+ +^--^---^---+ +--------^--+ +---^-^---^-+ | | ^ | | | | | | | | | | | | +--------+ | +---------+ | | | | | | | | | | | | +----+ | | | | | | | +-+---+-+ +--+--+-+ | +-----+-+ +------++ | | | | | | IHCC | | IHCC | | | IHCC | | IHCC +---------+ | | | | | 0<->1 | | 1<->2 | | | 2<->4 +----+ | 3<->4 | | | | | +-------+ +-------+ | +-------+ | +-------+ | | | | | +----------------------+ | | | +-------+ +-------+ | +-------+ | | | | IHCC | | IHCC | +--+ IHCC +-------------------------------+ | | | 0<->2 | | 1<->3 | | 2<->4 | | | +-------+ +-------+ +-------+ | | | | +-------+ +-------+ Mi-V IHC - Inter Hart Communication subsytem | | | IHCC | | IHCC | Not all connections are shown for | | | 0<->3 | | 1<->4 | reasons of clarity | | +-------+ +-------+ | | | | +-------+ | | | IHCC | | | | 0<->4 | | | +-------+ | | | +-----------------------------------------------------------------------------------------+ ``` ============================================================================== Theory of Operation ============================================================================== The Mi-V IHC subsystem facilitates sending messages between independent software contexts in an AMP system. API functions are provided for the following: - Initialization and configuration functions - Polled transmit and receive functions - Interrupt driven transmit and receive functions -------------------------------- Initialization and Configuration -------------------------------- At start-up, one hart should be designated to initialize the Mi-V IHC and set the default values. This hart must have access to the full memory range. In the Microchip software ecosystem, the HSS, running on E51 monitor core carries out this function. Local contexts initialize local channels. Examples of initialization are given in the functions descriptions. A drawing of an example start-up showing the order of the functions used is shown below: ``` +----------------+ | | | monitor hart | Example start-up | | +-------+--------+ | +--------v---------+ |IHC_global_init()| +--------+---------+ | +-----------v--------------+ +----------------+---------------------------------+--------------------------------+---------------------------------+ |IHC_local_context_init() | | | | | | +-----------+--------------+ | | | | | ^ | | | | | +-----------+--------------+ | +-----------v--------------+ +-------------v------------+ +-------------v------------+ +--------------v-----------+ |IHC_local_remote_config() | | |IHC_local_context_init() | |IHC_local_context_init() | |IHC_local_context_init() | |IHC_local_context_init() | | channel 0 <> 1 config | | +--------------------------+ +-------------+------------+ +-------------+------------+ +--------------+-----------+ +--------------------------+ | | | | | | +--------------------------+ +-------------v------------+ +-------------v------------+ +--------------v-----------+ +-----------v--------------+ | |IHC_local_remote_config()| |IHC_local_remote_config()| |IHC_local_remote_config()| |IHC_local_remote_config()| |IHC_local_remote_config() | | | channel 1 <> 0 config | | channel 1 <> 0 config | | channel 1 <> 0 config | | channel 4 <> 0 config | | channel 0 <> 2 config | | +--------------------------+ +-------------+------------+ +-------------+------------+ +--------------+-----------+ +--------------------------+ | | | | | | +--------------------------+ v v +--------------v-----------+ +-----------v--------------+ | |IHC_local_remote_config()| |IHC_local_remote_config()| |IHC_local_remote_config() | | | channel A <> B config | | channel B <> A config | | channel 0 <> 3 config | | +--------------------------+ +--------------+-----------+ +--------------------------+ | | | | | v v +-----------v--------------+ | |IHC_local_remote_config() | | | channel 0 <> 4 config | | +--------------------------+ | | | +-----------v---------------+ | | Start other harts/contexts+--+ +-----------+---------------+ | v ``` -------------------------------------- Polled Transmit and Receive Operations -------------------------------------- See the function description for message_present_poll(void) below. Note that one side of a channel can be polled and at the same time, the other side can be interrupt driven. This is the case on hart0 where the HSS running on hart0 polls the incoming messages. The outgoing messages from hart0 generate local interrupt to the far side ( hart 1 to 4 ) via Mi-V IHC IP. --------------------------- Interrupt Driven Operation --------------------------- On start-up the driver uses the function IHC_local_remote_config() to register an interrupt handler for each incoming channel being configured. Below is a bare metal example of handling an incoming message: ``` +-------------------------+ | registered function for | | incoming channel A<>B | +-----------------+-------+ +-------------------------+ ^ | registered function for | | | incoming channel 0<>4 | | +----+--------------------+ | ^ | | Bare metal application | +------------------------------------------+ | Bare metal Driver | | | | | | | +----+-------------------------+--+ | miv_ihc_hart4_int() | | | | parses IP and calls registered | | interrupt associated with the | | channel | +--------+------------------------+ ^ | | | Interrupt from Mi-V IHCIA + to hart4 ``` ============================================================================== Files used in the Mi-V IHC ============================================================================== Below are the names along with a brief description of each file used in the Mi-V IHC bare metal driver. They are grouped into two sections. The fixed files in the driver folder, and configuration files which are edited to configure for particular use case and it is recommended to place them under the boards directory in the recommended program structure for a bare metal project( See the associated example project or HSS). -------------------------------- Driver files -------------------------------- These files are found in ``` src/platform/drivers/fpga_ip/miv_ihc/ ``` |file name | detail | |---------------------------| -----------------------------------------------| | **miv_ihc_defines.h** | defines required by configuration files | | **miv_ihc_regs.h** | defines related to hardware | | **miv_ihc.h** | software and API defines | | **miv_ihc_version.h** | Contains the version to the software driver | | **miv_ihc.c** | All code including API functions | -------------------------------- Configuration files -------------------------------- These files are found in ``` src/boards/your-board/platform-config/drivers-config/fpga_ip/miv_ihc/ ``` |file name | detail | |-------------------------------| --------------------------------------------------| | **miv_ihc_add_mapping.h** | address Mi-V IHC is instantiated in Libero design | | **miv_ihc_config.h** | Configures channels used in software design | Please note when using the Mi-V IHC, the configuration files must be referenced in the mss_sw_config.h file, to include them in the project. See the example project. *//*=========================================================================*/ #ifndef __MSS_MIV_IHC_H_ #define __MSS_MIV_IHC_H_ 1 #include "miv_ihc_regs.h" #ifdef __cplusplus extern "C" { #endif extern IHC_TypeDef * IHC[]; /*-------------------------------------------------------------------------*//** ## Interrupt mapping table Choose the interrupt mapping used in you system Please see defines in miv_ihc.h for the default defines. The default values below are over-written with those in the miv_ihc_add_mapping.h file if it this is present in the boards directory. |driver interrupt name |default mapped fabric interrupt in the ref. design | |---------------------------------| -----------------------------------------| | **IHCIA_hart0_INT** | fabric_f2h_63_plic_IRQHandler | | **IHCIA_hart1_INT** | fabric_f2h_62_plic_IRQHandler | | **IHCIA_hart2_INT** | fabric_f2h_61_plic_IRQHandler | | **IHCIA_hart3_INT** | fabric_f2h_60_plic_IRQHandler | | **IHCIA_hart4_INT** | fabric_f2h_59_plic_IRQHandler | */ #ifndef IHCIA_hart0_IRQHandler #define IHCIA_hart0_IRQHandler fabric_f2h_63_plic_IRQHandler #endif #ifndef IHCIA_hart1_IRQHandler #define IHCIA_hart1_IRQHandler fabric_f2h_62_plic_IRQHandler #endif #ifndef IHCIA_hart2_IRQHandler #define IHCIA_hart2_IRQHandler fabric_f2h_61_plic_IRQHandler #endif #ifndef IHCIA_hart3_IRQHandler #define IHCIA_hart3_IRQHandler fabric_f2h_60_plic_IRQHandler #endif #ifndef IHCIA_hart4_IRQHandler #define IHCIA_hart4_IRQHandler fabric_f2h_59_plic_IRQHandler #endif #ifndef IHCIA_hart0_INT #define IHCIA_hart0_INT PLIC_F2M_63_INT_OFFSET #endif #ifndef IHCIA_hart1_INT #define IHCIA_hart1_INT PLIC_F2M_62_INT_OFFSET #endif #ifndef IHCIA_hart2_INT #define IHCIA_hart2_INT PLIC_F2M_61_INT_OFFSET #endif #ifndef IHCIA_hart3_INT #define IHCIA_hart3_INT PLIC_F2M_60_INT_OFFSET #endif #ifndef IHCIA_hart4_INT #define IHCIA_hart4_INT PLIC_F2M_59_INT_OFFSET #endif /*-------------------------------------------------------------------------*//** ## Channel definitions Choose the interrupt mapping used in you system Please see miv_ihc_regs.h for the defaults The default values below are over-written with those in the miv_ihc_add_mapping.h file if it this is present in the platform directory. |value | channel |comment | |------|------------------------------| -------------------------------------| | 0 | **IHC_CHANNEL_TO_HART0** | channel connected to hart 0 | | 1 | **IHC_CHANNEL_TO_HART1** | channel connected to hart 1 | | 2 | **IHC_CHANNEL_TO_HART2** | channel connected to hart 2 | | 3 | **IHC_CHANNEL_TO_HART3** | channel connected to hart 3 | | 4 | **IHC_CHANNEL_TO_HART4** | channel context A | | 6 | **IHC_CHANNEL_TO_CONTEXTB** | channel context B | */ typedef enum IHC_CHANNEL_ { IHC_CHANNEL_TO_HART0 = 0x00, /*!< your hart to hart 0 */ IHC_CHANNEL_TO_HART1 = 0x01, /*!< your hart to hart 1 */ IHC_CHANNEL_TO_HART2 = 0x02, /*!< your hart to hart 2 */ IHC_CHANNEL_TO_HART3 = 0x03, /*!< your hart to hart 3 */ IHC_CHANNEL_TO_HART4 = 0x04, /*!< your hart to hart 4 */ IHC_CHANNEL_TO_CONTEXTA = 0x05, /*!< your hart to context A */ IHC_CHANNEL_TO_CONTEXTB = 0x06, /*!< your hart to context B */ } IHC_CHANNEL; /*-------------------------------------------------------------------------*//** These hold pointers to IP associated with each hart Generally the mapping is fixed between Libero designs to keep thing obvious but it can change. The base addresses are located in the mapping header file. */ extern IHC_TypeDef IHC_H0_IP_GROUP; extern IHC_TypeDef IHC_H1_IP_GROUP; extern IHC_TypeDef IHC_H2_IP_GROUP; extern IHC_TypeDef IHC_H3_IP_GROUP; extern IHC_TypeDef IHC_H4_IP_GROUP; /*--------------------------------Public APIs---------------------------------*/ /*-------------------------------------------------------------------------*//** The IHC_global_init() function initializes the IP. It is the first function called that accesses the Mi-V IHC. It must be called from the monitor hart before other harts try and access the Mi-V IHC. It assumes access to the full memory map. It initializes regs to default values which will later be updated using a local init function called from the Hart using the particular channels related to it hartid in the Mi-V IHC. @param No parameters @return This function does not return a value. @code // Initialization code #include "mss_ihc.h" int main(void) { // The IHC_global_init() function initializes the Mi-V IHC subsystem. // It is the first function called that accesses the Mi-V IHC. it must // be called from the monitor hart before other harts try and access // the Mi-V IHC. It assumes access to the full memory map. // It sets up the base address points to reference the Mi-V IHC // subsystem IHCC and IHCIA IP blocks, and sets registers to default // values. IHC_global_init(); uint32_t local_hartid = HSS_HART_ID; IHC_local_context_init((uint32_t)local_hartid); { uint32_t remote_hart_id = HART1_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART2_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART3_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART4_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } return (0u); } @endcode */ void IHC_global_init ( void ); /*-------------------------------------------------------------------------*//** The IHC_local_context_init() function initializes the IP. It is called from each hart using the Mi-V IHC once on start-up. @param No parameters @return This function does not return a value. @code // Initialization code #include "mss_ihc.h" int main(void) { // The IHC_global_init() function initializes the Mi-V IHC subsystem. // It is the first function called that accesses the Mi-V IHC. it must // be called from the monitor hart before other harts try and access // the Mi-V IHC. It assumes access to the full memory map. // It sets up the base address points to reference the Mi-V IHC // subsystem IHCC and IHCIA IP blocks, and sets registers to default // values. IHC_global_init(); uint32_t local_hartid = HSS_HART_ID; IHC_local_context_init((uint32_t)local_hartid); { uint32_t remote_hart_id = HART1_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART2_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART3_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART4_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } return (0u); } @endcode */ void IHC_local_context_init(uint32_t hart_to_configure); /*-------------------------------------------------------------------------*//** The IIHC_local_remote_config() function initializes the IP. It is called from each hart using the inter hart comms once for every hart ot context the local hart is communicating with. @param No parameters @return This function does not return a value. @code // Initialization code #include "mss_ihc.h" int main(void) { // The IHC_global_init() function initializes the Mi-V IHC subsystem. // It is the first function called that accesses the Mi-V IHC. it must // be called from the monitor hart before other harts try and access // the Mi-V IHC. It assumes access to the full memory map. // It sets up the base address points to reference the Mi-V IHC // subsystem IHCC and IHCIA IP blocks, and sets registers to default // values. IHC_global_init(); uint32_t local_hartid = HSS_HART_ID; IHC_local_context_init((uint32_t)local_hartid); { uint32_t remote_hart_id = HART1_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART2_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART3_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } { uint32_t remote_hart_id = HART4_ID; bool set_mpie_en = true; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, queue_incoming_hss_main, set_mpie_en, set_ack_en); } return (0u); } @endcode */ void IHC_local_remote_config(uint32_t hart_to_configure, uint32_t remote_hart_id, QUEUE_IHC_INCOMING handler, bool set_mpie_en, bool set_ack_en ); /*-------------------------------------------------------------------------*//** The IHC_hart_to_context_or_hart_id() Returns the lowest hart ID of the context the local hart is in. @param channel The channel we want the local hart ID of. @return hartID @code // example code showing use uint32_t my_hart_id = context_to_local_hart_id(channel); uint32_t remote_hart_id = context_to_remote_hart_id(channel); uint32_t message_size = IHC[my_hart_id]->HART_IHC[remote_hart_id]->size_msg; @endcode */ uint32_t IHC_hart_to_context_or_hart_id(IHC_CHANNEL channel); /*-------------------------------------------------------------------------*//** The IHC_context_to_context_hart_id() Returns the lowest hart ID of the context the hart is in. @param channel The channel we want the remote hart ID of. @return hartID @code // example code showing use uint32_t my_hart_id = IHC_partner_context_hart_id(remote_channel); uint32_t remote_hart_id = IHC_context_to_context_hart_id(remote_channel); uint32_t message_size = IHC[my_hart_id]->HART_IHC[remote_hart_id]->size_msg; @endcode */ extern uint32_t IHC_context_to_context_hart_id(IHC_CHANNEL remote_channel); /*-------------------------------------------------------------------------*//** The IHC_partner_context_hart_id() Returns the lowest hart ID of the context the hart is in. @param remote_channel The channel we want the remote hart ID of. @return hartID @code // example code showing use uint32_t my_hart_id = IHC_partner_context_hart_id(remote_channel); uint32_t remote_hart_id = IHC_context_to_context_hart_id(remote_channel); uint32_t message_size = IHC[my_hart_id]->HART_IHC[remote_hart_id]->size_msg; @endcode */ extern uint32_t IHC_partner_context_hart_id(IHC_CHANNEL channel); /*-------------------------------------------------------------------------*//** The IHC_tx_message_from_context() Is used to send a message to a context from a context. @param channel The channel we want the remote hart ID of. @param message Pointer to message being sent @return status hartID @code // example code showing use if ( MESSAGE_SENT == IHC_tx_message_from_context(IHC_CHANNEL_TO_HART0, (uint32_t *)&tx_message_buffer[0])) { // message has been sent } else { // you can try again... @endcode */ extern uint32_t IHC_tx_message_from_context(IHC_CHANNEL channel, uint32_t *message); /*-------------------------------------------------------------------------*//** The IHC_tx_message_from_hart() Is used to send a message from non-context based upper layer (i.e. HSS) when you want to send a message directly to a HART or a context. @param channel The channel we want the remote hart ID of. @param message Pointer to message being sent @return status hartID @code // example code showing use if ( MESSAGE_SENT == IHC_tx_message_from_hart(IHC_CHANNEL_TO_HART0, (uint32_t *)&tx_message_buffer[0])) { // message has been sent } else { // you can try again... @endcode */ extern uint32_t IHC_tx_message_from_hart(IHC_CHANNEL channel, uint32_t *message); /*-------------------------------------------------------------------------*//** The IHC_message_present_poll() When calls parse to see if message present and processes the message with message present handler previous registered using the IHC_local_remote_config() function @param none @return none @code // example code showing use uint32_t local_hartid = HSS_HART_ID; IHC_local_context_init((uint32_t)local_hartid); { uint32_t remote_hart_id = HART1_ID; bool set_mpie_en = false; bool set_ack_en = false; IHC_local_remote_config((uint32_t)local_hartid, remote_hart_id, our_message_handler, set_mpie_en, set_ack_en); } while(1) { // poll for incoming messages // if message present it is handled using our_message_handler() // register earlier, and written by you based on one of the examples // in the example programs bundled with this driver IHC_message_present_poll(); // .. @endcode */ void IHC_message_present_poll(void); /*-------------------------------------------------------------------------*//** The IHC_context_indirect_isr() When called parse to see if message present and processes the message with message present handler previous registered using the IHC_local_remote_config() function. When we call this function we already have worked out our hart ID and have our message storage pointer. One use case is when openSBI handler when called by an upper layer. Below is a simplified flow diagram: ``` +--------------------------+ |Remote Processor Messaging| |(RPMsg) linux driver | | s-mode | +------+------------+----+-+ ^ | ^ | | | delegate to s-mode | | ecall to m-mode handler | | | returns with message pointer | v | +-------------+----+ +--+----+--------------+ |Mi-V IHCIA | | | |fabric interrupt | |HSS_SBI_ECALL_Handler | |openSBI_int_handler |m-mode | |m-mode | | | +---------+--------+ +--+----+--------------+ ^ | ^ | +-------v----+------------------+ MP interrupt | IHC_context_indirect_isr() | | +-------------------------------+ + ``` @param message_storage_ptr where we want to store the incoming message @return none @code // see example application @endcode */ void IHC_context_indirect_isr(uint32_t * message_storage_ptr); #ifdef __cplusplus } #endif #endif /* __MSS_MIV_IHC_H_ */ hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc_add_mapping_reference.h000066400000000000000000000105461432224323300330600ustar00rootroot00000000000000/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IHC driver @section intro_sec Introduction Used to configure the driver with base addresses from your Libero Projext. These addresses will not change unless you change the Libero design IHC subsytem design. This file is used for reference only. When usiing in a project copy to src/boards/your-board/platform-config/drivers_config/fpga-ip/miv_ihc and rename dropping the _reference. @section *//*==========================================================================*/ #ifndef MIV_IHC_ADD_MAPPING_H_ #define MIV_IHC_ADD_MAPPING_H_ #ifndef COMMON_AHB_BASE_ADD #define COMMON_AHB_BASE_ADD 0x50000000UL #endif #ifndef IHC_HO_BASE_OFFSET #define IHC_HO_BASE_OFFSET 0x00000000UL #endif #ifndef IHC_H1_BASE_OFFSET #define IHC_H1_BASE_OFFSET 0x00000500UL #endif #ifndef IHC_H2_BASE_OFFSET #define IHC_H2_BASE_OFFSET 0x00000A00UL #endif #ifndef IHC_H3_BASE_OFFSET #define IHC_H3_BASE_OFFSET 0x00000F00UL #endif #ifndef IHC_H4_BASE_OFFSET #define IHC_H4_BASE_OFFSET 0x00001400UL #endif /************** My Hart 0 ************/ #ifndef IHC_LOCAL_H0_REMOTE_H1 #define IHC_LOCAL_H0_REMOTE_H1 0x50000000 #endif #ifndef IHC_LOCAL_H0_REMOTE_H2 #define IHC_LOCAL_H0_REMOTE_H2 0x50000100 #endif #ifndef IHC_LOCAL_H0_REMOTE_H3 #define IHC_LOCAL_H0_REMOTE_H3 0x50000200 #endif #ifndef IHC_LOCAL_H0_REMOTE_H4 #define IHC_LOCAL_H0_REMOTE_H4 0x50000300 #endif #ifndef IHCIA_LOCAL_H0 #define IHCIA_LOCAL_H0 0x50000400 #endif /************** My Hart 1 ************/ #ifndef IHC_LOCAL_H1_REMOTE_H0 #define IHC_LOCAL_H1_REMOTE_H0 0x50000500 #endif #ifndef IHC_LOCAL_H1_REMOTE_H2 #define IHC_LOCAL_H1_REMOTE_H2 0x50000600 #endif #ifndef IHC_LOCAL_H1_REMOTE_H3 #define IHC_LOCAL_H1_REMOTE_H3 0x50000700 #endif #ifndef IHC_LOCAL_H1_REMOTE_H4 #define IHC_LOCAL_H1_REMOTE_H4 0x50000800 #endif #ifndef IHCIA_LOCAL_H1 #define IHCIA_LOCAL_H1 0x50000900 #endif /************** My Hart 2 ************/ #ifndef IHC_LOCAL_H2_REMOTE_H0 #define IHC_LOCAL_H2_REMOTE_H0 0x50000A00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H1 #define IHC_LOCAL_H2_REMOTE_H1 0x50000B00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H3 #define IHC_LOCAL_H2_REMOTE_H3 0x50000C00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H4 #define IHC_LOCAL_H2_REMOTE_H4 0x50000D00 #endif #ifndef IHCIA_LOCAL_H2 #define IHCIA_LOCAL_H2 0x50000E00 #endif /************** My Hart 3 ************/ #ifndef IHC_LOCAL_H3_REMOTE_H0 #define IHC_LOCAL_H3_REMOTE_H0 0x50000F00 #endif #ifndef IHC_LOCAL_H3_REMOTE_H1 #define IHC_LOCAL_H3_REMOTE_H1 0x50001000 #endif #ifndef IHC_LOCAL_H3_REMOTE_H2 #define IHC_LOCAL_H3_REMOTE_H2 0x50001100 #endif #ifndef IHC_LOCAL_H3_REMOTE_H4 #define IHC_LOCAL_H3_REMOTE_H4 0x50001200 #endif #ifndef IHCIA_LOCAL_H3 #define IHCIA_LOCAL_H3 0x50001300 #endif /************** My Hart 4 ************/ #ifndef IHC_LOCAL_H4_REMOTE_H0 #define IHC_LOCAL_H4_REMOTE_H0 0x50001400 #endif #ifndef IHC_LOCAL_H4_REMOTE_H1 #define IHC_LOCAL_H4_REMOTE_H1 0x50001500 #endif #ifndef IHC_LOCAL_H4_REMOTE_H2 #define IHC_LOCAL_H4_REMOTE_H2 0x50001600 #endif #ifndef IHC_LOCAL_H4_REMOTE_H3 #define IHC_LOCAL_H4_REMOTE_H3 0x50001700 #endif #ifndef IHCIA_LOCAL_H4 #define IHCIA_LOCAL_H4 0x50001800 #endif /*------------------------------------------------------------------------------ * choose the interrupt mapping used in our system * Please see miv_ihc_regs.h for the defaults */ #define IHCIA_hart0_IRQHandler fabric_f2h_63_plic_IRQHandler #define IHCIA_hart1_IRQHandler fabric_f2h_62_plic_IRQHandler #define IHCIA_hart2_IRQHandler fabric_f2h_61_plic_IRQHandler #define IHCIA_hart3_IRQHandler fabric_f2h_60_plic_IRQHandler #define IHCIA_hart4_IRQHandler fabric_f2h_59_plic_IRQHandler #define IHCIA_hart0_INT FABRIC_F2H_63_PLIC #define IHCIA_hart1_INT FABRIC_F2H_62_PLIC #define IHCIA_hart2_INT FABRIC_F2H_61_PLIC #define IHCIA_hart3_INT FABRIC_F2H_60_PLIC #define IHCIA_hart4_INT FABRIC_F2H_59_PLIC #endif /* MIV_IHC_ADD_MAPPING_H_ */ hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc_defines.h000066400000000000000000000054221432224323300302110ustar00rootroot00000000000000/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /* @mainpage Fixed defines for the MiV IHC driver @section The defines in this file are used by the user configuration header and the driver files. The header files need to be included in a project in the following order to allow override of user settings. - miv_ihc_defines.h - miv_ihc_config.h we can override default setting in this file This config file is stored in the boards directory and is called from the mss_sw_config.h file. - miv_ihc_regs.h - miv_ihc.h @section *//*==========================================================================*/ #ifndef MIV_IHC_FIXED_DEFINES_H_ #define MIV_IHC_FIXED_DEFINES_H_ /*------------------------------------------------------------------------------ * hart mask defines */ #define HART0_ID 0U #define HART1_ID 1U #define HART2_ID 2U #define HART3_ID 3U #define HART4_ID 4U #define HART0_MASK 1U #define HART1_MASK 2U #define HART2_MASK 4U #define HART3_MASK 8U #define HART4_MASK 0x10U /*-------------------------------------------------------------------------*//** ## Defines for the INT_EN register in the IHCIA These defines are used to set interrupt enables in the INT_EN register. ### HSS_HART_DEFAULT_INT_EN By default, no interrupts are enabled. ### HSS_HART_MP_INT_EN Enable MP interrupt fopr hart0 ### HSS_HART_ACK_INT_EN Enable ACK interrupt for hart0 ### HART1_MP_INT_EN Enable MP interrupt fopr hart1 ### HART1_ACK_INT_EN Enable ACK interrupt for hart1 ### HART2_MP_INT_EN Enable MP interrupt fopr hart2 ### HART2_ACK_INT_EN Enable ACK interrupt for hart2 ### HART3_MP_INT_EN Enable MP interrupt fopr hart3 ### HART3_ACK_INT_EN Enable ACK interrupt for hart3 ### HART4_MP_INT_EN Enable MP interrupt fopr hart4 ### HART4_ACK_INT_EN Enable ACK interrupt for hart4 */ #define HSS_HART_DEFAULT_INT_EN (0U<<0U) #define HSS_HART_MP_INT_EN (1U<<0U) #define HSS_HART_ACK_INT_EN (1U<<1U) #define HART1_MP_INT_EN (1U<<2U) #define HART1_ACK_INT_EN (1U<<3U) #define HART2_MP_INT_EN (1U<<4U) #define HART2_ACK_INT_EN (1U<<5U) #define HART3_MP_INT_EN (1U<<6U) #define HART3_ACK_INT_EN (1U<<7U) #define HART4_MP_INT_EN (1U<<8U) #define HART4_ACK_INT_EN (1U<<9U) #endif /* MIV_IHC_FIXED_DEFINES_H_ */ hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc_regs.h000066400000000000000000000407001432224323300275320ustar00rootroot00000000000000 /****************************************************************************** * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC MSS MMUART * */ /*-------------------------------------------------------------------------*//** @page ============================================================================== miv_ihc_regs.h ============================================================================== The defines in this file are used by the user configuration header and the driver files. The header files need to be included in a project in the following order to allow over-ride of user settings. - miv_ihc_defines.h - miv_ihc_config.h we can over-ride default setting in this file This config file is stored in the boards directory and is called from the mss_sw_config.h file. - miv_ihc_regs.h - miv_ihc.h */ #ifndef MSS_MIV_IHC_REGS_H_ #define MSS_MIV_IHC_REGS_H_ #ifdef __cplusplus extern "C" { #endif #ifndef __I # define __I const volatile #endif #ifndef __IO # define __IO volatile #endif #ifndef __O # define __O volatile #endif /******************************************************************************* */ /*-------------------------------------------------------------------------*//** ## MiV-IHCC register bit definitions Register Bit definitions of the control register of the MiV-IHCC. | bit position | constant | description | |--------------|-------------------------|-----------------------------| | 0 | **RMP_MESSAGE_PRESENT** | Remote side message present | | 1 | **MP_MESSAGE_PRESENT** | local side message present | | 2 | **MPIE_EN** | Enable MP interrupt | | 3 | **ACK_INT** | Incoming ACK | | 4 | **ACK_CLR** | Clear ACK | | 5 | **ACKIE_EN** | Enable Ack Interrupt | */ #define RMP_MESSAGE_PRESENT (0x01U << 0U) #define MP_MESSAGE_PRESENT (0x01U << 1U) #define MPIE_EN (0x01U << 2U) #define ACK_INT (0x01U << 3U) #define ACK_CLR (0x01U << 4U) #define ACKIE_EN (0x01U << 5U) /* * Control register bit MASKS */ /* 0 => no message, 1 => we set to 1 when sending a message */ #define RMP_MASK (0x01U << 0U) /* 0 => no message, 1 => we have a message. We set to 0 when message read. */ #define MP_MASK (0x01U << 1U) /* Enable Message present Interrupt ( 0-1 ), we have a message */ #define MPIE_MASK (0x01U << 2U) /* 1 => ACK not sent */ #define ACK_INT_MASK (0x01U << 3U) #define IHC_MAX_MESSAGE_SIZE 4U /*-------------------------------------------------------------------------*//** ## Flags return by IHC_tx_message() |value|constant |description | |-----|---------------------------------------------------------| | 0 | **MESSAGE_SENT** | message sent | | 1 | **MESSAGE_RX** | message received | */ #define MESSAGE_SENT 0U #define MP_BUSY 1U /*-------------------------------------------------------------------------*//** ## Flags return by IHC_rx_message() |value|constant |description | |-----|-------------------|----------------------| | 0 | **MESSAGE_RX** | message sent | | 1 | **NO_MESSAGE_RX** | message received | */ #define NO_MESSAGE_RX 0U #define MESSAGE_RX 1UL /***************************************************************************//** Inter hart communication channel control register. The control register of this IP is used to send and indicate packet receipt. ___CTL_REG___: 32 bit register: - _RMP_ - Remote Message Present. - _MP_ - Message present. - _ACK_ - 1 => ACK present - _CLR_ACK_ - Set to 0 to clear ACK - _ACKIE_ - Enable ACK on reading of MP - _reserve28_ - Reserved. */ typedef union{ /*!< IHCC_CTL_REG register definition*/ __IO uint32_t CTL_REG; struct { __IO uint32_t RMP :1; __IO uint32_t MP :1; __IO uint32_t MPIE :1; __IO uint32_t ACK :1; __IO uint32_t CLR_ACK :1; __IO uint32_t ACKIE :1; __IO uint32_t reserve28 :26; } bitfield; } IHCC_CTL_REG_TypeDef; /*------------ IHC_IP register definition -----------*/ #define RESREVED_ADDRESS_SPACE_IHC 0x80 #define IHC_USED__ADDRESS_SIZE 64U /***************************************************************************//** Inter hart communication channel registers. ___version___: IP version, Read only ___CTR_REG___: Control register ___local_hart_id___: The hart ID of the connected hart ___size_msg___: Read only size of the msh buffer in bytes ___unused___: Spare bytes to keep registers aligned ___mesg_in___: Message in ___mesg_out___: Message out ___reserved___: Gap between each IP block is defined here */ typedef struct IHCC_IP_TypeDef_ { __IO uint32_t version; /*!< IP version */ __IO IHCC_CTL_REG_TypeDef CTR_REG; /*!< control reg */ __IO uint32_t local_hart_id; /*!< local_hart_id: my hart id, set at local init */ __I uint32_t size_msg; /*!< Size of msg buffer instantiated in fabric */ __I uint32_t unused[4U]; /*!< not used */ __I uint32_t mesg_in[IHC_MAX_MESSAGE_SIZE]; /*!< message in */ __IO uint32_t mesg_out[IHC_MAX_MESSAGE_SIZE]; /*!< message out */ __I uint8_t reserved[RESREVED_ADDRESS_SPACE_IHC - IHC_USED__ADDRESS_SIZE]; /*!< reserved address space */ } IHCC_IP_TypeDef; /***************************************************************************//** Inter hart communication aggregator MSG_AVAIL register Indicates if message or ack is present from connected Mi-V IHCC. ___MSG_AVAIL___: 32 bit register: - _MP_H0_ - Message Present from hart 0 - _ACK_H0_ - ACK coming from hart 0 - _MP_H1_ - Message Present from hart 1 - _ACK_H1_ - ACK coming from hart 1 - _MP_H2_ - Message Present from hart 2 - _ACK_H2_ - ACK coming from hart 2 - _MP_H3_ - Message Present from hart 3 - _ACK_H3_ - ACK coming from hart 3 - _MP_H4_ - Message Present from hart 4 - _ACK_H4_ - ACK coming from hart 4 - _reserved_ - Reserved. */ typedef union IHCIA_IP_MSG_AVAIL_STAT_TypeDef_{ /*!< IHCIA_IP_MSG_AVAIL_STAT register definition*/ __IO uint32_t MSG_AVAIL; struct { __I uint32_t MP_H0:1; __I uint32_t ACK_H0:1; __I uint32_t MP_H1:1; __I uint32_t ACK_H1:1; __I uint32_t MP_H2:1; __I uint32_t ACK_H2:1; __I uint32_t MP_H3:1; __I uint32_t ACK_H3:1; __I uint32_t MP_H4:1; __I uint32_t ACK_H4:1; __I uint32_t reserved:22; } bitfield; } IHCIA_IP_MSG_AVAIL_STAT_TypeDef; /***************************************************************************//** Inter hart communication aggregator Enables if message or ack interrupt from connected Mi-V IHCC. ___INT_EN___: 32 bit register: - _MP_H0_ - Enable interrupt from Message Present from hart 0 - _ACK_H0_ - Enable interrupt from ACK coming from hart 0 - _MP_H1_ - Enable interrupt from Message Present from hart 1 - _ACK_H1_ - Enable interrupt from ACK coming from hart 1 - _MP_H2_ - Enable interrupt from Message Present from hart 2 - _ACK_H2_ - Enable interrupt from ACK coming from hart 2 - _MP_H3_ - Enable interrupt from Message Present from hart 3 - _ACK_H3_ - Enable interrupt from ACK coming from hart 3 - _MP_H4_ - Enable interrupt from Message Present from hart 4 - _ACK_H4_ - Enable interrupt from ACK coming from hart 4 - _reserved_ - Reserved. */ typedef union IHCIA_IP_INT_EN_TypeDef_ { /*!< IHCIA_IP_INT_EN_TypeDef register definition*/ __IO uint32_t INT_EN; struct { __I uint32_t MP_H0_EN:1; __I uint32_t ACK_H0_EN:1; __I uint32_t MP_H1_EN:1; __I uint32_t ACK_H1_EN:1; __I uint32_t MP_H2_EN:1; __I uint32_t ACK_H2_EN:1; __I uint32_t MP_H3_EN:1; __I uint32_t ACK_H3_EN:1; __I uint32_t MP_H4_EN:1; __I uint32_t ACK_H4_EN:1; __I uint32_t reserved:22; } bitfield; } IHCIA_IP_INT_EN_TypeDef; /***************************************************************************//** Inter hart communication aggregator core registers. The aggregator takes intputs from the IHCC cores and end generates an output which is connected to one of the interrupts on selected hart. ___version___: IP version, Read only ___INT_EN___: enable the interrupts you require ___MSG_AVAIL_STAT___: Register used to see what inputs are high. Gap between each IP block is defined here */ typedef struct IHCIA_IP_TypeDef_ { __IO uint32_t version; __IO IHCIA_IP_INT_EN_TypeDef INT_EN; __I IHCIA_IP_MSG_AVAIL_STAT_TypeDef MSG_AVAIL_STAT; } IHCIA_IP_TypeDef; /***************************************************************************//** QUEUE_IHC_INCOMING Type define of upper layer message available handler. The upper layer registers a function of this type when initialing the driver for each channel registered. */ typedef uint32_t (*QUEUE_IHC_INCOMING)(uint32_t, uint32_t *, uint32_t, bool, uint32_t *); /***************************************************************************//** IHC_DRIVER_HART_INFO_TypeDef Structure used to hold information related to a hart ___connected_harts___: Stores info on which harts are connected to our hart instance ___connected_hart_ints___: What remotte harts will generate an interrupt ___context_hart___: Out local hart ID. ___padding__: Keeps members aligned ___msg_in_handler[5]___: Seperate pointer for each remote hart incomimg handler */ typedef struct IHC_DRIVER_HART_INFO_TypeDef_ { uint32_t connected_harts; uint32_t connected_hart_ints; uint32_t context_hart; uint32_t padding; QUEUE_IHC_INCOMING msg_in_handler[5U]; } IHC_DRIVER_HART_INFO_TypeDef; /***************************************************************************//** IHC cluster definition Structure holds pointers to IHC cluster for a hart. This structure is Initialized on startup with the base addresses from from the miv_ihc_add_mapping.h file which is populated with base addresses from the Libero design if non-default. otherwise the base addresses from this file will be used if mivihc_add_mapping.h is not present ___HART_IHC[5]___: A IHC for each remote hart ___interrupt_aggregator___: One aggregator for each hart */ typedef struct IHC_TypeDef_ { __IO IHCC_IP_TypeDef *HART_IHCC[5U]; /*!< hart0-4 ihc registers */ __IO IHCIA_IP_TypeDef *HART_IHCIA; IHC_DRIVER_HART_INFO_TypeDef local_h_setup; } IHC_TypeDef; /*-------------------------------------------------------------------------*//** ## Base address definitions Default base address defines. These are used if the file core_ihc_add_mapping.h does not exist. |local hart | base address | Name | |-----------|------------------| --------------------------------------------| | 0 | 0x50000000UL | **IHC_LOCAL_H0_REMOTE_H1** | | 0 | 0x50000100UL | **IHC_LOCAL_H0_REMOTE_H2** | | 0 | 0x50000200UL | **IHC_LOCAL_H0_REMOTE_H3** | | 0 | 0x50000300UL | **IHC_LOCAL_H0_REMOTE_H4** | | 0 | 0x50000400UL | **IHCIA_LOCAL_H0** | |-----------|---------------- | --------------------------------------------| | 1 | 0x50000500UL | **IHC_LOCAL_H1_REMOTE_H0** | | 1 | 0x50000600UL | **IHC_LOCAL_H1_REMOTE_H2** | | 1 | 0x50000700UL | **IHC_LOCAL_H1_REMOTE_H3** | | 1 | 0x50000800UL | **IHC_LOCAL_H1_REMOTE_H4** | | 1 | 0x50000900UL | **IHCIA_LOCAL_H1** | |-----------|---------------- | --------------------------------------------| | 2 | 0x50000A00UL | **IHC_LOCAL_H2_REMOTE_H0** | | 2 | 0x50000B00UL | **IHC_LOCAL_H2_REMOTE_H1** | | 2 | 0x50000C00UL | **IHC_LOCAL_H2_REMOTE_H3** | | 2 | 0x50000D00UL | **IHC_LOCAL_H2_REMOTE_H4** | | 2 | 0x50000E00UL | **IHCIA_LOCAL_H2** | |-----------|---------------- | --------------------------------------------| | 3 | 0x50000F00UL | **IHC_LOCAL_H3_REMOTE_H0** | | 3 | 0x50001000UL | **IHC_LOCAL_H3_REMOTE_H1** | | 3 | 0x50002000UL | **IHC_LOCAL_H3_REMOTE_H2** | | 3 | 0x50003000UL | **IHC_LOCAL_H3_REMOTE_H4** | | 3 | 0x50004000UL | **IHCIA_LOCAL_H3** | |-----------|---------------- | --------------------------------------------| | 4 | 0x50005000UL | **IHC_LOCAL_H4_REMOTE_H0** | | 4 | 0x50006000UL | **IHC_LOCAL_H4_REMOTE_H1** | | 4 | 0x50007000UL | **IHC_LOCAL_H4_REMOTE_H2** | | 4 | 0x50008000UL | **IHC_LOCAL_H4_REMOTE_H3** | | 4 | 0x50009000UL | **IHCIA_LOCAL_H4** | */ /************** My Hart 0 ************/ #ifndef IHC_LOCAL_H0_REMOTE_H1 #define IHC_LOCAL_H0_REMOTE_H1 0x50000000 #endif #ifndef IHC_LOCAL_H0_REMOTE_H2 #define IHC_LOCAL_H0_REMOTE_H2 0x50000100 #endif #ifndef IHC_LOCAL_H0_REMOTE_H3 #define IHC_LOCAL_H0_REMOTE_H3 0x50000200 #endif #ifndef IHC_LOCAL_H0_REMOTE_H4 #define IHC_LOCAL_H0_REMOTE_H4 0x50000300 #endif #ifndef IHCIA_LOCAL_H0 #define IHCIA_LOCAL_H0 0x50000400 #endif /************** My Hart 1 ************/ #ifndef IHC_LOCAL_H1_REMOTE_H0 #define IHC_LOCAL_H1_REMOTE_H0 0x50000500 #endif #ifndef IHC_LOCAL_H1_REMOTE_H2 #define IHC_LOCAL_H1_REMOTE_H2 0x50000600 #endif #ifndef IHC_LOCAL_H1_REMOTE_H3 #define IHC_LOCAL_H1_REMOTE_H3 0x50000700 #endif #ifndef IHC_LOCAL_H1_REMOTE_H4 #define IHC_LOCAL_H1_REMOTE_H4 0x50000800 #endif #ifndef IHCIA_LOCAL_H1 #define IHCIA_LOCAL_H1 0x50000900 #endif /************** My Hart 2 ************/ #ifndef IHC_LOCAL_H2_REMOTE_H0 #define IHC_LOCAL_H2_REMOTE_H0 0x50000A00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H1 #define IHC_LOCAL_H2_REMOTE_H1 0x50000B00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H3 #define IHC_LOCAL_H2_REMOTE_H3 0x50000C00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H4 #define IHC_LOCAL_H2_REMOTE_H4 0x50000D00 #endif #ifndef IHCIA_LOCAL_H2 #define IHCIA_LOCAL_H2 0x50000E00 #endif /************** My Hart 3 ************/ #ifndef IHC_LOCAL_H3_REMOTE_H0 #define IHC_LOCAL_H3_REMOTE_H0 0x50000F00 #endif #ifndef IHC_LOCAL_H3_REMOTE_H1 #define IHC_LOCAL_H3_REMOTE_H1 0x50001000 #endif #ifndef IHC_LOCAL_H3_REMOTE_H2 #define IHC_LOCAL_H3_REMOTE_H2 0x50001100 #endif #ifndef IHC_LOCAL_H3_REMOTE_H4 #define IHC_LOCAL_H3_REMOTE_H4 0x50001200 #endif #ifndef IHCIA_LOCAL_H3 #define IHCIA_LOCAL_H3 0x50001300 #endif /************** My Hart 4 ************/ #ifndef IHC_LOCAL_H4_REMOTE_H0 #define IHC_LOCAL_H4_REMOTE_H0 0x50001400 #endif #ifndef IHC_LOCAL_H4_REMOTE_H1 #define IHC_LOCAL_H4_REMOTE_H1 0x50001500 #endif #ifndef IHC_LOCAL_H4_REMOTE_H2 #define IHC_LOCAL_H4_REMOTE_H2 0x50001600 #endif #ifndef IHC_LOCAL_H4_REMOTE_H3 #define IHC_LOCAL_H4_REMOTE_H3 0x50001700 #endif #ifndef IHCIA_LOCAL_H4 #define IHCIA_LOCAL_H4 0x50001800 #endif #ifdef __cplusplus } #endif #endif /* MSS_MIV_IHC_REGS_H_ */ hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc_version.h000066400000000000000000000043001432224323300302530ustar00rootroot00000000000000#ifndef MIV_IHC_VERSION_H #define MIV_IHC_VERSION_H /******************************************************************************* * Copyright 2021-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * */ /******************************************************************************* * @file miv_ihc_version.h * @author Microchip-FPGA Embedded Systems Solutions * @brief Version file miv Inter Hart Communication driver * */ #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** ## Version of the MiV Inter Hart Communication driver |constant|Value| |-------------------------------------------------| -------------------------| | **MIV_IHC_VERSION_MAJOR** | **0** | | **MIV_IHC_VERSION_MINOR** | **1** | | **MIV_IHC_VERSION_MINOR** | **1** | */ #define MIV_IHC_VERSION_MAJOR 0 #define MIV_IHC_VERSION_MINOR 1 #define MIV_IHC_VERSION_PATCH 1 #ifdef __cplusplus } #endif #endif /* end MIV_IHC_VERSION_H */ hart-software-services-2022.10/baremetal/drivers/micron_mt25q/000077500000000000000000000000001432224323300242165ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/micron_mt25q/micron_mt25q.c000066400000000000000000000623611432224323300267110ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Driver for MICRON_MT25Q QSPI flash memory. * This driver uses the MPFS MSS QSPI driver interface. * * * N25Q256A; size 256Mb (32MBytes), Monolithic device, 2 segments of 128Mb each. * MT25Q; size 1Gbits(128MBytes), * * Micron's DTR transfers are no supported by the MSS QSPI controller. * 4 byte addressing mode is enabled. All commands requiring address field must * transmit 4 bytes address. * */ #include "drivers/micron_mt25q/micron_mt25q.h" #include "drivers/mss/mss_mmuart/mss_uart.h" /*Following constant must be defined if you want to use the interrupt mode transfers provided by the MSS QSPI driver. Comment this out to use the polling mode transfers.*/ //#define USE_QSPI_INTERRUPT 1u #ifdef __cplusplus extern "C" { #endif #ifdef USE_QSPI_INTERRUPT #define QSPI_TRANSFER_BLOCK(num_addr_bytes, tx_buffer, tx_byte_size, rd_buffer, rd_byte_size, num_idle_cycles) \ {\ MSS_QSPI_irq_transfer_block((num_addr_bytes), (tx_buffer), (tx_byte_size), (rd_buffer), (rd_byte_size), (num_idle_cycles));\ if((tx_buffer && !rd_buffer)) \ {wait_for_tx_complete();} \ if((rd_buffer && !tx_buffer)) \ {wait_for_tx_complete();} \ if((tx_buffer && rd_byte_size && rd_buffer && tx_byte_size)) \ {wait_for_rx_complete();\ wait_for_tx_complete(); \ } \ } #else #define QSPI_TRANSFER_BLOCK(num_addr_bytes, tx_buffer, tx_byte_size, rd_buffer, rd_byte_size, num_idle_cycles) \ MSS_QSPI_polled_transfer_block((num_addr_bytes), (tx_buffer), (tx_byte_size), (rd_buffer), (rd_byte_size), (num_idle_cycles)); #endif #define PAGE_LENGTH 256u #define MICRON_RESET_ENABLE 0x66 #define MICRON_RESET_MEMORY 0x99 #define MICRON_READ_ID_OPCODE 0x9F #define MICRON_MIO_READ_ID_OPCODE 0xAF #define MICRON_READ_DISCOVERY 0x5A #define MICRON_READ 0x03 #define MICRON_FAST_READ 0x0B #define MICRON_DUALO_FAST_READ 0x3B #define MICRON_DUALIO_FAST_READ 0xBB #define MICRON_QUADO_FAST_READ 0x6B #define MICRON_QUADIO_FAST_READ 0xEB #define MICRON_QUADIO_WORD_READ 0xE7 #define MICRON_4BYTE_READ 0x13 #define MICRON_4BYTE_FAST_READ 0x0C #define MICRON_4BYTE_DUALO_FAST_READ 0x3C #define MICRON_4BYTE_DUALIO_FAST_READ 0xBC #define MICRON_4BYTE_QUADO_FAST_READ 0x6C #define MICRON_4BYTE_QUADIO_FAST_READ 0xEC #define MICRON_WRITE_ENABLE 0x06 #define MICRON_WRITE_DISABLE 0x04 #define MICRON_READ_STATUS_REG 0x05 #define MICRON_READ_FLAG_STATUS_REG 0x70 #define MICRON_READ_NV_CONFIG_REG 0xB5 #define MICRON_READ_V_CONFIG_REG 0x85 #define MICRON_READ_ENH_V_CONFIG_REG 0x65 #define MICRON_READ_EXT_ADDR_REG 0xC8 #define MICRON_READ_GEN_PURPOSE_READ_REG 0x96 #define MICRON_WR_STATUS_REG 0x01 #define MICRON_WR_NV_CONFIG_REG 0xB1 #define MICRON_WR_V_CONFIG_REG 0x81 #define MICRON_WR_ENH_V_CONFIG_REG 0x61 #define MICRON_WR_EXT_ADDR_REG 0xC5 #define MICRON_CLR_FLAG_STATUS_REG 0x50 #define MICRON_PAGE_PROGRAM 0x02 #define MICRON_DUAL_INPUT_FAST_PROG 0xA2 #define MICRON_EXT_DUAL_INPUT_FAST_PROG 0xD2 #define MICRON_QUAD_INPUT_FAST_PROG 0x32 #define MICRON_EXT_QUAD_INPUT_FAST_PROG 0x38 #define MICRON_4BYTE_PAGE_PROG 0x12 #define MICRON_4BYTE_QUAD_INPUT_FAST_PROG 0x34 #define MICRON_4BYTE_QUAD_INPUT_EXT_FAST_PROG 0x3E #define MICRON_32KB_SUBSECTOR_ERASE 0x52 #define MICRON_4KB_SUBSECTOR_ERASE 0x20 #define MICRON_SECTOR_ERASE 0xD8 #define MICRON_DIE_ERASE 0xC4 #define MICRON_BULK_ERASE 0xC7 #define MICRON_4BYTE_SECTOR_ERASE 0xDC #define MICRON_4BYTE_4KB_SUBSECTOR_ERASE 0x21 #define MICRON_4BYTE_32KB_SUBSECTOR_ERASE 0x5C #define MICRON_ENTER_4BYTE_ADDR_MODE 0xB7 #define MICRON_EXIT_4BYTE_ADDR_MODE 0xE9 #define MICRON_ENTER_QUAD_IO_MODE 0x35 #define MICRON_RESET_QUAD_IO_MODE 0xF5 #define MICRON_READ_SECTOR_PROTECTION 0x2D #define MICRON_READ_V_LOCK_BITS 0xE8 #define MICRON_WRITE_V_LOCK_BITS 0xE5 #define MICRON_READ_NV_LOCK_BITS 0xE2 #define MICRON_READ_GLOBAL_FREEZE_BIT 0xA7 #define MICRON_READ_PASSWORD 0x27 #define MICRON_RESET_PROTOCOL 0xFF #define MICRON_JEDEC_ID 0x20u #define FLAGSTATUS_BUSY_MASK 0x80u #define FLAGSTATUS_EFAIL_MASK 0x20u #define FLAGSTATUS_PFAIL_MASK 0x10u mss_qspi_config_t beforexip_qspi_config={0}; mss_qspi_config_t g_qspi_config = {0}; mss_qspi_config_t qspi_config_read={0}; #ifdef NVDEBUG extern uint8_t g_ui_buf[500]; extern mss_uart_instance_t *g_uart; #endif volatile uint8_t g_rx_complete = 0u; volatile uint8_t g_tx_complete = 0u; static volatile uint8_t g_enh_v_val __attribute__ ((aligned (4))) = 0x0u; /******************************************************************************* * Local functions */ static void read_statusreg(uint8_t* rd_buf); static void read_nv_cfgreg(uint8_t* rd_buf); static void read_v_cfgreg(uint8_t* rd_buf); static void read_enh_v_cfgreg(uint8_t* rd_buf); static void read_flagstatusreg(uint8_t* rd_buf); static void enable_4byte_addressing(void); static void disable_4byte_addressing(void); static void device_reset(void); static void write_enh_v_confreg(uint8_t* enh_v_val); static mss_qspi_io_format probe_io_format(void); static mss_qspi_io_format update_io_format(mss_qspi_io_format t_io_format); static uint8_t program_page(uint8_t* buf,uint32_t page,uint32_t len); void transfer_status_handler(uint32_t status); #ifdef USE_QSPI_INTERRUPT void transfer_status_handler(uint32_t status) { if (STTS_RDONE_MASK == (STTS_RDONE_MASK & status)) { g_rx_complete = 1; } else if (STTS_TDONE_MASK == (STTS_TDONE_MASK & status)) { g_tx_complete = 1; } } static void wait_for_tx_complete(void) { while (0u == g_tx_complete); g_tx_complete = 0u; } static void wait_for_rx_complete(void) { while (0u == g_rx_complete); g_rx_complete = 0u; } #endif /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ void Flash_init ( mss_qspi_io_format io_format ) { volatile mss_qspi_io_format t_io_format = MSS_QSPI_NORMAL; MSS_QSPI_init(); #ifdef USE_QSPI_INTERRUPT MSS_QSPI_set_status_handler(transfer_status_handler); #endif g_qspi_config.clk_div = MSS_QSPI_CLK_DIV_30; //Tested OK MICRON_FAST_READ command at MSS_QSPI_CLK_DIV_12 g_qspi_config.sample = MSS_QSPI_SAMPLE_POSAGE_SPICLK; g_qspi_config.spi_mode = MSS_QSPI_MODE3; g_qspi_config.xip = MSS_QSPI_DISABLE; g_qspi_config.io_format = MSS_QSPI_NORMAL; MSS_QSPI_configure(&g_qspi_config); device_reset(); /* Find out the current mode of the flash memory device * and configure qspi controller to that mode.*/ t_io_format = probe_io_format(); g_qspi_config.io_format = t_io_format; MSS_QSPI_configure(&g_qspi_config); /* If the desired IO format is same as the currently configured IO Format * Then we are done. Otherwise configure the Flash and QSPI controller * to the IO format provided by the user. */ if (io_format != t_io_format) { g_qspi_config.io_format = t_io_format; MSS_QSPI_configure(&g_qspi_config); read_enh_v_cfgreg((uint8_t*)&g_enh_v_val); if (io_format == MSS_QSPI_QUAD_FULL) { g_enh_v_val |= 0x40u; /* set the dual mode bit*/ g_enh_v_val &= ~0x80u; /*clear the quad mode bit*/ } else if (io_format == MSS_QSPI_DUAL_FULL) { g_enh_v_val |= 0x80u; /*set the quad mode bit*/ g_enh_v_val &= ~0x40u; /*clear the dual mode but*/ } else { g_enh_v_val |= 0xC0u; /*normal*/ } write_enh_v_confreg((uint8_t*)&g_enh_v_val); read_enh_v_cfgreg((uint8_t*)&g_enh_v_val); } g_qspi_config.io_format = io_format; MSS_QSPI_configure(&g_qspi_config); enable_4byte_addressing(); } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ void Flash_readid ( uint8_t* buf ) { uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_READ_ID_OPCODE}; volatile mss_qspi_io_format t_io_format; t_io_format = g_qspi_config.io_format; if ((t_io_format != MSS_QSPI_QUAD_FULL) && (t_io_format != MSS_QSPI_DUAL_FULL)) { t_io_format = update_io_format(MSS_QSPI_NORMAL); QSPI_TRANSFER_BLOCK(0, command_buf, 0, buf, 3, 0); update_io_format(t_io_format); } else { command_buf[0] = MICRON_MIO_READ_ID_OPCODE; QSPI_TRANSFER_BLOCK(0, command_buf, 0, buf, 3, 0); } } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ void Flash_read ( uint8_t* buf, uint32_t addr, uint32_t len ) { uint8_t dummy_cycles = 0u; uint8_t command_buf[10] __attribute__ ((aligned (4))) = {0u}; command_buf[1] = (addr >> 24u) & 0xFFu; command_buf[2] = (addr >> 16u) & 0xFFu; command_buf[3] = (addr >> 8u) & 0xFFu; command_buf[4] = addr & 0xFFu; switch(g_qspi_config.io_format) { case MSS_QSPI_NORMAL: command_buf[0] = MICRON_4BYTE_FAST_READ; dummy_cycles = 8u; break; case MSS_QSPI_DUAL_EX_RO: command_buf[0] = MICRON_4BYTE_DUALO_FAST_READ; /* 1-1-2 */ dummy_cycles = 8u; break; case MSS_QSPI_QUAD_EX_RO: command_buf[0] = MICRON_4BYTE_QUADO_FAST_READ; /* 1-1-4 */ dummy_cycles = 8u; break; case MSS_QSPI_DUAL_EX_RW: command_buf[0] = MICRON_4BYTE_DUALIO_FAST_READ; /* 1-2-2 */ dummy_cycles = 8u; break; case MSS_QSPI_QUAD_EX_RW: command_buf[0] = MICRON_4BYTE_QUADIO_FAST_READ; /* 1-4-4 */ dummy_cycles = 10u; break; case MSS_QSPI_DUAL_FULL: command_buf[0] = MICRON_4BYTE_FAST_READ; dummy_cycles = 8u; break; case MSS_QSPI_QUAD_FULL: command_buf[0] = MICRON_4BYTE_FAST_READ; dummy_cycles = 10u; /* For Quad mode */ break; default: ASSERT(0); break; } QSPI_TRANSFER_BLOCK(4, command_buf, 0, buf, len, dummy_cycles); } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ uint8_t Flash_program ( uint8_t* buf, uint32_t addr, uint32_t len ) { int32_t remaining_length = (int32_t)len; uint32_t target_offset = addr; uint8_t status = 0xFF; while(remaining_length > 0) { uint32_t page_length; if(remaining_length >= PAGE_LENGTH) { page_length = PAGE_LENGTH; } else { page_length = remaining_length; } status = program_page(buf, target_offset, page_length); remaining_length -= page_length; target_offset += page_length; buf += page_length; } return (status); } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ uint8_t Flash_erase(void) { uint8_t status = 0xFFu; uint8_t command_buf[5] __attribute__ ((aligned (4))) = {MICRON_WRITE_ENABLE}; /*Both Write enable and Die erase can work in all modes*/ /* Write enable command must be executed before erase * WRITE ENABLE 06h 1-0-0 2-0-0 4-0-0 0 no dummy cycles. * */ volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0,0); /* Erase the die. This will write 1 to all bits * DIE ERASE C4h 1-1-0 2-2-0 4-4-0 no dummy cycles * */ command_buf[0] = MICRON_BULK_ERASE; QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0,0); update_io_format(t_io_format); while (1){ read_flagstatusreg(&status); if ((status & FLAGSTATUS_BUSY_MASK) != 0) break; } return(status & FLAGSTATUS_EFAIL_MASK); } uint8_t Flash_sector_erase ( uint32_t addr ) { uint8_t status = 0xFFu; uint8_t command_buf[5] __attribute__ ((aligned (4))) = {MICRON_WRITE_ENABLE}; /*Both Write enable and Die erase can work in all modes*/ /* Write enable command must be executed before erase * WRITE ENABLE 06h 1-0-0 2-0-0 4-0-0 0 no dummy cycles. * */ volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0,0); /* Erase the die. This will write 1 to all bits * DIE ERASE C4h 1-1-0 2-2-0 4-4-0 no dummy cycles * */ command_buf[0] = MICRON_SECTOR_ERASE; command_buf[1] = (addr >> 24u) & 0xFFu; command_buf[2] = (addr >> 16u) & 0xFFu; command_buf[3] = (addr >> 8u) & 0xFFu; command_buf[4] = addr & 0xFFu; QSPI_TRANSFER_BLOCK(4, command_buf, 0, (uint8_t*)0, 0,0); update_io_format(t_io_format); while (1){ read_flagstatusreg(&status); if ((status & FLAGSTATUS_BUSY_MASK) != 0) break; } return(status & FLAGSTATUS_EFAIL_MASK); } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ void Flash_enter_xip ( void ) { disable_4byte_addressing(); uint8_t command_buf[5] __attribute__ ((aligned (4))) = {MICRON_WRITE_ENABLE}; uint32_t temp; QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0, 0); command_buf[0] = MICRON_WR_V_CONFIG_REG; command_buf[1] = 0xF3u; /*Enable XIP*/ /*Enable XIP by writing to volatile configuration register*/ QSPI_TRANSFER_BLOCK(0, command_buf, 1, (uint8_t*)0, 0, 0); /*Drive XIP confirmation using FAST read and keeping DQ0 to 0 during idle cycle*/ command_buf[0] = MICRON_FAST_READ; command_buf[1] = 0x00u; command_buf[2] = 0x00u; command_buf[3] = 0x00u; /*Following command must be sent in polling method only. Using interrupt method is not possible here because, after sending this command flash memory immediately goes into the XIP mode and reading the status register in the IRQ returns the flash memory value instead of register value and this will not allow interrupt to be processed properly.*/ if ((MSS_QSPI_QUAD_FULL == g_qspi_config.io_format) || (MSS_QSPI_QUAD_EX_RW == g_qspi_config.io_format) || (MSS_QSPI_QUAD_EX_RO == g_qspi_config.io_format)) { QSPI_TRANSFER_BLOCK(3, command_buf, 1, (uint8_t*)&temp, 4, 10); } else { QSPI_TRANSFER_BLOCK(3, command_buf, 1, (uint8_t*)&temp, 4, 8); } MSS_QSPI_get_config(&beforexip_qspi_config); /*Force the XIP to work correctly, we must use QSPI_SAMPLE_NEGAGE_SPICLK per spec*/ beforexip_qspi_config.sample = MSS_QSPI_SAMPLE_NEGAGE_SPICLK; beforexip_qspi_config.xip = MSS_QSPI_ENABLE; MSS_QSPI_configure(&beforexip_qspi_config); } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ void Flash_read_status_regs ( uint8_t* buf ) { read_statusreg(&buf[0]); read_nv_cfgreg(&buf[1]); /* 2bytes */ read_v_cfgreg(&buf[3]); read_enh_v_cfgreg(&buf[4]); read_flagstatusreg(&buf[5]); } /***************************************************************************//** * See micron_mt25q.h for details of how to use this function. */ void Flash_exit_xip ( void ) { uint8_t command_buf[5] __attribute__ ((aligned (4))) = {MICRON_FAST_READ}; uint32_t temp = 0u; beforexip_qspi_config.sample = MSS_QSPI_SAMPLE_POSAGE_SPICLK; beforexip_qspi_config.xip = MSS_QSPI_DISABLE; MSS_QSPI_configure(&beforexip_qspi_config); /* Drive XIP confirmation bit using FAST read and keeping DQ0 to 1 during * idle cycle this will exit the XIP*/ command_buf[0] = MICRON_FAST_READ; command_buf[1] = 0x00u; command_buf[2] = 0x00u; command_buf[3] = 0xFFu; QSPI_TRANSFER_BLOCK(3, command_buf, 0, (uint8_t*)&temp, 1, 8); enable_4byte_addressing(); } void Flash_clr_flagstatusreg ( void ) { const uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_CLR_FLAG_STATUS_REG}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); QSPI_TRANSFER_BLOCK(0, command_buf, 0, 0, 0,0); update_io_format(t_io_format); } /******************************************************************************* * Local functions */ static void read_statusreg ( uint8_t* rd_buf ) { const uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_READ_STATUS_REG}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); QSPI_TRANSFER_BLOCK(0, command_buf, 0, rd_buf, 1,0); update_io_format(t_io_format); } static void enable_4byte_addressing ( void ) { uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_WRITE_ENABLE}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /* Write enable command must be executed before writing extended addr reg. */ QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0, 0); command_buf[0] = MICRON_ENTER_4BYTE_ADDR_MODE; /* This command works for all modes. No Dummy cycles */ QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0, 0); update_io_format(t_io_format); } static void disable_4byte_addressing ( void ) { uint8_t command_buf[2] __attribute__ ((aligned (4))) = {MICRON_WRITE_ENABLE}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /* Write enable command must be executed before writing extended addr reg. */ QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0, 0); command_buf[0] = MICRON_EXIT_4BYTE_ADDR_MODE; /* This command works for all modes. No Dummy cycles */ QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0, 0); update_io_format(t_io_format); } static void device_reset(void) { uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_RESET_ENABLE}; QSPI_TRANSFER_BLOCK(0, (void *)command_buf, 0, 0, 0,0); for(volatile uint32_t idx =0u; idx < 1000u ; idx++); /* delay */ command_buf[0] = MICRON_RESET_MEMORY; QSPI_TRANSFER_BLOCK(0, (void *)command_buf, 0, 0, 0,0); for(volatile uint32_t idx =0u; idx < 1000u ; idx++); /* delay */ } static void read_nv_cfgreg ( uint8_t* rd_buf ) { uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_READ_NV_CONFIG_REG}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /*This command works for all modes. No Dummy cycles*/ QSPI_TRANSFER_BLOCK(0, command_buf, 0, rd_buf, 2,0); update_io_format(t_io_format); } static void read_v_cfgreg ( uint8_t* rd_buf ) { uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_READ_V_CONFIG_REG}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /*This command works for all modes. No Dummy cycles*/ QSPI_TRANSFER_BLOCK(0, command_buf, 0, rd_buf, 2,0); update_io_format(t_io_format); } static void read_enh_v_cfgreg ( uint8_t* rd_buf ) { const uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_READ_ENH_V_CONFIG_REG}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /*This command works for all modes. No Dummy cycles*/ QSPI_TRANSFER_BLOCK(0, command_buf, 0, rd_buf, 1,0); update_io_format(t_io_format); } static void write_enh_v_confreg ( uint8_t* enh_v_val ) { uint8_t command_buf[2] __attribute__ ((aligned (4))) = {MICRON_WRITE_ENABLE}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /*execute Write enable command again for writing the data*/ QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0, 0); command_buf[0] = MICRON_WR_ENH_V_CONFIG_REG; command_buf[1] = *enh_v_val; /*This command works for all modes. No Dummy cycles*/ QSPI_TRANSFER_BLOCK(0, command_buf, 1, (uint8_t*)0, 0, 0); update_io_format(t_io_format); } static void read_flagstatusreg ( uint8_t* rd_buf ) { const uint8_t command_buf[1] __attribute__ ((aligned (4))) = {MICRON_READ_FLAG_STATUS_REG}; volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /*This command works for all modes. No Dummy cycles*/ QSPI_TRANSFER_BLOCK(0, command_buf, 0, rd_buf, 1,0); update_io_format(t_io_format); } static mss_qspi_io_format update_io_format ( mss_qspi_io_format io_format ) { volatile mss_qspi_io_format t_io_format; t_io_format = g_qspi_config.io_format; if ((t_io_format != MSS_QSPI_QUAD_FULL) && (t_io_format != MSS_QSPI_DUAL_FULL)) { if (t_io_format != io_format) { g_qspi_config.io_format = io_format; MSS_QSPI_configure(&g_qspi_config); } } return t_io_format; } static mss_qspi_io_format probe_io_format ( void ) { volatile uint8_t device_id __attribute__ ((aligned (4))) = 0x0u; mss_qspi_io_format io_format = MSS_QSPI_NORMAL; for(uint8_t idx = 0u; idx < 8u; idx++) { g_qspi_config.io_format = (MSS_QSPI_QUAD_FULL - idx); MSS_QSPI_configure(&g_qspi_config); Flash_readid((uint8_t*)&device_id); if (MICRON_JEDEC_ID == device_id) { io_format = (MSS_QSPI_QUAD_FULL - idx); break; } } return(io_format); } /* Any address within the page is valid. * If len -> PAGE_LENGTH : * Bytes more than PAGE_LENGTH are ignored * If addr -> page start addr and len > more than remaining bytes in the page : * Bytes overflowing the page boundary are ignored * if len < pag_size : * Only len bytes are modified, rest remain unchanged. */ static uint8_t program_page ( uint8_t* buf, uint32_t addr, uint32_t len ) { uint8_t status = 0u; uint8_t command_buf[300] __attribute__ ((aligned (4))) = {0}; uint32_t length = len; uint32_t offset = addr % PAGE_LENGTH; if (len > PAGE_LENGTH) { length = PAGE_LENGTH; } if (offset && ((length + offset) > PAGE_LENGTH)) { length = PAGE_LENGTH - offset; } volatile mss_qspi_io_format t_io_format; t_io_format = update_io_format(MSS_QSPI_NORMAL); /*execute Write enable command again for writing the data*/ command_buf[0] = MICRON_WRITE_ENABLE; QSPI_TRANSFER_BLOCK(0, command_buf, 0, (uint8_t*)0, 0,0); update_io_format(t_io_format); command_buf[1] = (addr >> 24) & 0xFFu; command_buf[2] = (addr >> 16) & 0xFFu; command_buf[3] = (addr >> 8) & 0xFFu; command_buf[4] = addr & 0xFFu; for (uint16_t idx=0; idx< length;idx++) { command_buf[5 + idx] = *(uint8_t*)(buf+idx); } /* Dummy cycles for all program commands are 0. * DUAL EX_RO and DUAL EX_RW commands dont have 4 BYTE in their name but * they take 4 byte address when Flash is configured in 4byte mode. * Refer command set in the flash memory datasheet*/ switch(g_qspi_config.io_format) { case MSS_QSPI_NORMAL : command_buf[0] = MICRON_4BYTE_PAGE_PROG; break; case MSS_QSPI_DUAL_EX_RO : command_buf[0] = MICRON_DUAL_INPUT_FAST_PROG; /* 1-1-2 */ break; case MSS_QSPI_QUAD_EX_RO : Flash_init(MSS_QSPI_QUAD_EX_RW); command_buf[0] = 0x38; /* 1-1-4 */ break; case MSS_QSPI_DUAL_EX_RW : command_buf[0] = MICRON_EXT_DUAL_INPUT_FAST_PROG; /* 1-2-2 */ break; case MSS_QSPI_QUAD_EX_RW : command_buf[0] = MICRON_4BYTE_QUAD_INPUT_EXT_FAST_PROG; /* 1-4-4 */ break; case MSS_QSPI_DUAL_FULL : command_buf[0] = MICRON_4BYTE_PAGE_PROG; break; case MSS_QSPI_QUAD_FULL : command_buf[0] = MICRON_4BYTE_PAGE_PROG; break; default: ASSERT(0); break; } QSPI_TRANSFER_BLOCK(4, command_buf, length, (uint8_t*)0u, 0u, 0u); while (1){ read_flagstatusreg(&status); if ((status & FLAGSTATUS_BUSY_MASK) != 0) break; } return(status & FLAGSTATUS_PFAIL_MASK); } #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/micron_mt25q/micron_mt25q.h000066400000000000000000000161031432224323300267070ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2019 - 2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Driver for MICRON N25Q QSPI flash memory. * This driver uses the MPFS MSS QSPI driver interface. */ #ifndef MSS_MICRON_MT25Q_H_ #define MSS_MICRON_MT25Q_H_ #include #include "drivers/mss/mss_qspi/mss_qspi.h" #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** The Flash_init() function initializes the MSS QSPI and the flash memory to normal SPI operations. The g_qspi_config.io_format is used for the read/write operations to choose the Flash memory commands accordingly. This function must be called before calling any other function provided by this driver. @param io_format The io_format parameter provides the SPI IO format that needs to be used for read/write operations. @return This function does not returns any value @example ##### Example1 Example @code @endcode */ void Flash_init ( mss_qspi_io_format io_format ); /*-------------------------------------------------------------------------*//** The Flash_readid() function returns first 1 byte of data of the device JEDEC ID. @param buf The rd_buf parameter provides a pointer to the buffer in which the driver will copy the JEDEC ID data. The buffer must be at least 1 bytes long. @return This function does not returns any value @example ##### Example1 Example @code @endcode */ void Flash_readid ( uint8_t* buf ); /*-------------------------------------------------------------------------*//** The Flash_read() function reads data from the flash memory. @param buf The buf parameter is a pointer to the buffer in which the driver will copy the data read from the flash memory. @param addr The addr parameter is the address in the flash memory from which the driver will read the data. @param len The len parameter is the number of 8-bit bytes that will be read from the flash memory starting with the address indicated by the addr parameter. @return This function does not returns any value @example ##### Example1 Example @code @endcode */ void Flash_read ( uint8_t* buf, uint32_t addr, uint32_t len ); /*-------------------------------------------------------------------------*//** The Flash_erase() function erases the complete device. @return This function returns a non-zero value if there was an error during erase operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_erase ( void ); /*-------------------------------------------------------------------------*//** The Flash_sector_erase() function erases the given sector. @return This function returns a non-zero value if there was an error during erase operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_sector_erase ( uint32_t addr ); /*-------------------------------------------------------------------------*//** The Flash_program() function writes data into the flash memory. @param buf The rd_buf parameter provides a pointer to the buffer from which the data needs to be written into the flash memory. @param addr The addr parameter is an address in the flash memory to which the data will be written to. @param len The len parameter indicates the number of 8-bit bytes that will be written to the flash memory starting from the address indicated by the addr parameter. @return This function returns a non-zero value if there was an error during program operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_program ( uint8_t* buf, uint32_t addr, uint32_t len ); /*-------------------------------------------------------------------------*//** The Flash_read_status_regs() function reads all three status registers @param buf The buf parameter is a pointer to the buffer in which the driver will copy the status register values. The buffer should be large enough to store 6 8-bit bytes. The sequence is - Status register - Non-volatile configuration registers (2 bytes) - Volatile configuration registers - Enhanced volatile configuration register - Flag status register @return This function does not return any value. @example ##### Example1 Example @code @endcode */ void Flash_read_status_regs ( uint8_t * buf ); /*-------------------------------------------------------------------------*//** The Flash_enter_xip() function puts the flash memory into the XIP mode. To exit XIP, use Flash_exit_xip() function or reset the device. After entering into the XIP mode, any AHB access to MSS QSPI register space will result into reading a byte from the flash memory over QSPI interface. The XIP mode uses 3 byte addressing. @return This function does not return any value. @example ##### Example1 Example @code @endcode */ void Flash_enter_xip ( void ); /*-------------------------------------------------------------------------*//** The Flash_exit_xip() function brings the Flash memory out of the XIP mode. @return This function does not return any value. @example ##### Example1 Example @code @endcode */ void Flash_exit_xip ( void ); /*-------------------------------------------------------------------------*//** The Flash_clr_flagstatusreg() function can be used in case there were errors in erase/program operations. This function will clear the error status so that subsequent erase/program operations can be initiated. @return This function does not return any value. @example ##### Example1 Example @code @endcode */ void Flash_clr_flagstatusreg ( void ); #ifdef __cplusplus } #endif #endif /* MSS_MICRON_MT25Q_H_*/ hart-software-services-2022.10/baremetal/drivers/mss/000077500000000000000000000000001432224323300225015ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/000077500000000000000000000000001432224323300241545ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_common_cif.c000066400000000000000000000654211432224323300301740ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF driver * * USB-CIF driver implementation: * This source file implements MSS USB Interrupt handler functions. This file * also implements core interface function for the logical layer to control * the MSS USB core. These interface functions are independent of the USB mode. * */ #include "mss_usb_common_cif.h" #include "mss_assert.h" #include "mss_usb_common_reg_io.h" #include "mss_usb_core_regs.h" #include "mss_plic.h" #ifdef MSS_USB_HOST_ENABLED #include "mss_usb_host_cif.h" #include "mss_usb_host_reg_io.h" #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED static uint8_t MSS_USB_CIF_host_rx_errchk(mss_usb_ep_num_t ep_num); static uint8_t MSS_USB_CIF_host_tx_errchk(mss_usb_ep_num_t ep_num); #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_DEVICE_ENABLED static uint8_t MSS_USB_CIF_device_rx_errchk(mss_usb_ep_num_t ep_num); static uint8_t MSS_USB_CIF_device_tx_errchk(mss_usb_ep_num_t ep_num); #endif /* MSS_USB_HOST_ENABLED */ /***************************************************************************//** * Global variables shared by mss_usb_device_cif.c and mss_usb_common_cif.c */ #ifdef MSS_USB_DEVICE_ENABLED extern mss_usbd_cb_t g_mss_usbd_cb; extern volatile mss_usbd_cep_state_t cep_state; #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_HOST_ENABLED extern mss_usbh_cb_t g_mss_usbh_cb; #endif /* MSS_USB_HOST_ENABLED */ /***************************************************************************//** * Private functions declarations of USB-CIF. ******************************************************************************/ static void MSS_USB_CIF_handle_cep_irq ( void ); static void MSS_USB_CIF_handle_tx_ep_irq ( uint16_t irq_num ); static void MSS_USB_CIF_handle_rx_ep_irq ( uint16_t irq_num ); /***************************************************************************//** * Main USB interrupt handler. It checks for TX/RX endpoint interrupts and USB * system level interrupts and calls the appropriate routine. */ uint8_t PLIC_usb_mc_IRQHandler ( void ) { volatile uint8_t usb_irq; volatile uint16_t tx_ep_irq; volatile uint16_t rx_ep_irq; volatile uint8_t role; usb_irq = MSS_USB_CIF_read_irq_reg(); tx_ep_irq = MSS_USB_CIF_read_tx_ep_irq_reg(); rx_ep_irq = MSS_USB_CIF_read_rx_ep_irq_reg(); /* When operating in Host mode, on detecting Disconnect event, Disconnect Interrupt occurs but the HostMode bit in DevCtl is also cleared. Hence moving Disconnect handling out of get_mode condition. In the event of Disconnection, The decision is made based on the B-Device bit(DevCtl-D7). */ if (usb_irq & DISCONNECT_IRQ_MASK) { role = MSS_USB_CIF_get_role(); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_DEVICE_ROLE_DEVICE_B == role) { MSS_USB_CIF_enable_usbirq(RESET_IRQ_MASK); g_mss_usbd_cb.usbd_disconnect(); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_DEVICE_ROLE_DEVICE_A == role) { /*In Host mode, On removing the attached B-device the session bit somehow remains set. This bit need to be cleared otherwise RESET interrupt is not occurring when B-Device is connected after removing A-Device*/ if (MSS_USB_CIF_is_session_on()) { MSS_USB_CIF_stop_session(); } MSS_USBH_CIF_read_vbus_level(); g_mss_usbh_cb.usbh_disconnect(); } #endif /* MSS_USB_HOST_ENABLED */ } #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { if (usb_irq & RESUME_IRQ_MASK) { g_mss_usbd_cb.usbd_resume(); } if (usb_irq & SUSPEND_IRQ_MASK) { g_mss_usbd_cb.usbd_suspend(); } if (usb_irq & RESET_IRQ_MASK) { MSS_USB_CIF_set_index_reg(MSS_USB_CEP); MSS_USB_CIF_enable_usbirq(DISCONNECT_IRQ_MASK | SUSPEND_IRQ_MASK); cep_state = MSS_USB_CTRL_EP_IDLE; MSS_USB_CIF_clr_usb_irq_reg(); MSS_USB_CIF_cep_clr_setupend(); MSS_USB_CIF_cep_clr_stall_sent(); g_mss_usbd_cb.usbd_reset(); } } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { role = MSS_USB_CIF_get_role(); if (usb_irq & RESUME_IRQ_MASK) { /* Resume interrupt in Host mode means Remote Wakeup request */ } /* Vbus_err and session request interrupts are valid only in A device */ if (MSS_USB_DEVICE_ROLE_DEVICE_A == role) { if (usb_irq & SESSION_REQUEST_IRQ_MASK) { /* This means SRP initiated by Target device. */ } if (usb_irq & VBUS_ERROR_IRQ_MASK) { /* Power management */ MSS_USBH_CIF_read_vbus_level(); } } if (usb_irq & CONNECT_IRQ_MASK) { MSS_USBH_CIF_handle_connect_irq(); } if (usb_irq & BABBLE_IRQ_MASK) { /* Not supported yet */ } #if 0 /* SOF interrupt is not processed */ if (usb_irq & SOF_IRQ_MASK) { g_mss_usbd_cb.usb_device_sof(0); } #endif /* SOF interrupt is not processed */ } #endif /* MSS_USB_HOST_ENABLED */ if (tx_ep_irq & 0x0001u) { /* handle EP0 IRQ */ MSS_USB_CIF_handle_cep_irq(); } if (tx_ep_irq & 0xFFFEu) /* EP0 is handled above */ { /* Handle TX EP here, pass on the EP numbers.Mask EP0 bit */ tx_ep_irq &= 0xFFFEu; MSS_USB_CIF_handle_tx_ep_irq(tx_ep_irq); } if (rx_ep_irq & 0xFFFEu) /* bit0 is not defined */ { /* Handle RX EP here, pass on the EP numbers */ MSS_USB_CIF_handle_rx_ep_irq(rx_ep_irq); } return EXT_IRQ_KEEP_ENABLED; } /***************************************************************************//** * Routine to handle the interrupt on Control Endpoint.(EP0) */ static void MSS_USB_CIF_handle_cep_irq ( void ) { uint8_t status = 0u; MSS_USB_CIF_set_index_reg(MSS_USB_CEP); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { if (MSS_USB_CIF_cep_is_stall_sent()) { status |= CTRL_EP_STALL_ERROR; MSS_USB_CIF_cep_clr_stall_sent(); g_mss_usbd_cb.usbd_cep_setup(status); } else { if (MSS_USB_CIF_cep_is_setupend()) { MSS_USB_CIF_cep_clr_setupend(); if (!MSS_USB_CIF_cep_is_rxpktrdy()) { status |= CTRL_EP_SETUP_END_ERROR; } else { status &= ~CTRL_EP_SETUP_END_ERROR; } g_mss_usbd_cb.usbd_cep_setup(status); } else { if (cep_state == MSS_USB_CTRL_EP_IDLE) { if (MSS_USB_CIF_cep_is_rxpktrdy()) { g_mss_usbd_cb.usbd_cep_setup(status); } } else if (cep_state == MSS_USB_CTRL_EP_TX) { g_mss_usbd_cb.usbd_cep_tx_complete(status); } else if (cep_state == MSS_USB_CTRL_EP_RX) { if (MSS_USB_CIF_cep_is_rxpktrdy()) { g_mss_usbd_cb.usbd_cep_rx(status); } } else { ASSERT(0); } } } } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { if (MSS_USBH_CIF_cep_is_rxstall_err()) { status |= MSS_USB_EP_STALL_RCVD; MSS_USBH_CIF_cep_clr_rxstall_err(); } if (MSS_USBH_CIF_cep_is_retry_err()) { status |= MSS_USB_EP_NO_RESPONSE; MSS_USBH_CIF_cep_clr_retry_err(); } if (MSS_USBH_CIF_cep_is_naktimeout_err()) { status |= MSS_USB_EP_NAK_TOUT; MSS_USBH_CIF_cep_clr_naktimeout_err(); } if (status == 0u) /* No error was found */ { status = MSS_USB_EP_TXN_SUCCESS; } g_mss_usbh_cb.usbh_cep(status); } #endif /* MSS_USB_HOST_ENABLED */ } /***************************************************************************//** * Routine to handle the interrupt on TX_EP */ static void MSS_USB_CIF_handle_tx_ep_irq ( uint16_t irq_num ) { mss_usb_ep_num_t ep_num = MSS_USB_TX_EP_1; uint8_t status = 0u; while (irq_num) { irq_num >>= 1u; /*EP1 starts from D1*/ if (irq_num & MSS_USB_WORD_BIT_0_MASK) { MSS_USB_CIF_tx_ep_disable_irq(ep_num); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_device_tx_errchk(ep_num); g_mss_usbd_cb.usbd_ep_tx_complete(ep_num,status); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_host_tx_errchk(ep_num); g_mss_usbh_cb.usbh_tx_complete((uint8_t)ep_num, status); } #endif /* MSS_USB_HOST_ENABLED */ MSS_USB_CIF_tx_ep_enable_irq(ep_num); } status = 0u; /*resetting for next EP status*/ ++ep_num; } } /***************************************************************************//** * Routine to handle the interrupt on RX EP */ static void MSS_USB_CIF_handle_rx_ep_irq ( uint16_t irq_num ) { mss_usb_ep_num_t ep_num = MSS_USB_RX_EP_1; uint8_t status = 0u; while (irq_num) { irq_num >>= 1u; /*EP1 starts from D1*/ if (irq_num & MSS_USB_WORD_BIT_0_MASK) { MSS_USB_CIF_rx_ep_disable_irq(ep_num); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_device_rx_errchk(ep_num); g_mss_usbd_cb.usbd_ep_rx(ep_num, status); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_host_rx_errchk(ep_num); g_mss_usbh_cb.usbh_rx((uint8_t)ep_num, status); } #endif /* MSS_USB_HOST_ENABLED */ MSS_USB_CIF_rx_ep_enable_irq(ep_num); } status = 0u; /*resetting for next EP status*/ ++ep_num; } } /***************************************************************************//** * Handler for DMA interrupt. Checks for the DMA channel on which interrupt has * Occurred and corresponding EP number then calls-back to upper layer to indicate * the event. */ uint8_t PLIC_usb_dma_IRQHandler(void) { mss_usb_dma_channel_t dma_channel= MSS_USB_DMA_CHANNEL1; uint8_t status = 0; mss_usb_dma_dir_t dma_dir; mss_usb_ep_num_t ep_num; uint8_t dma_irq; uint32_t increamented_addr=0; dma_irq = MSS_USB_CIF_dma_read_irq(); while (dma_irq) { if (dma_irq & MSS_USB_BYTE_BIT_0_MASK) { /* DMA Transfer for this channel is complete.Clear Start_transfer bit */ MSS_USB_CIF_dma_stop_xfr(dma_channel); ep_num = (mss_usb_ep_num_t)MSS_USB_CIF_dma_get_epnum(dma_channel); dma_dir = (mss_usb_dma_dir_t)MSS_USB_CIF_dma_get_dir(dma_channel); if (MSS_USB_CIF_dma_is_bus_err(dma_channel)) { status |=DMA_XFR_ERROR; MSS_USB_CIF_dma_clr_bus_err(dma_channel); } else { increamented_addr = MSS_USB_CIF_dma_read_addr(dma_channel); if (MSS_USB_DMA_READ == dma_dir) /*TX EP*/ { if (MSS_USB_CIF_tx_ep_is_dma_enabled(ep_num)) { MSS_USB_CIF_tx_ep_disable_dma(ep_num); } } #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { /* Call the host mode logical layer driver callback function */ g_mss_usbh_cb.usbh_dma_handler(ep_num, dma_dir, status, increamented_addr); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { /* Call the device mode logical layer driver callback function */ g_mss_usbd_cb.usbd_dma_handler(ep_num, dma_dir, status, increamented_addr); } #endif /* MSS_USB_DEVICE_ENABLED */ } } dma_channel++; dma_irq >>= 1u; } return EXT_IRQ_KEEP_ENABLED; } /***************************************************************************//** * Prepares the RX EP for receiving data as per parameters provided by upper layer */ void MSS_USB_CIF_rx_ep_read_prepare ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length ) { /* * Fixed Buffer overwriting issue found with printer driver and issue with * interrupt transfer with DMA by moving the location of interrupt enable * function. */ if (DMA_ENABLE == dma_enable) { /* Make sure that address is Modulo-4.Bits D0-D1 are read only.*/ ASSERT(!(((ptrdiff_t)buf_addr) & 0x00000002U)); MSS_USB_CIF_dma_write_addr(dma_channel, (ptrdiff_t)buf_addr); /* * DMA Count register will be loaded after receive interrupt occurs. * Mode need to be set every time since M1 to M0 transition might have * happened for "short packet". */ if (MSS_USB_XFR_BULK == xfr_type) { MSS_USB_CIF_rx_ep_set_dma_mode1(ep_num); MSS_USB_CIF_rx_ep_set_autoclr(ep_num); MSS_USB_CIF_rx_ep_enable_dma(ep_num); MSS_USB_CIF_dma_write_count(dma_channel, xfr_length); /* Handling single NULL packet reception */ if (0u != xfr_length ) { MSS_USB_CIF_dma_start_xfr(dma_channel); } } else { MSS_USB_CIF_rx_ep_clr_autoclr(ep_num); MSS_USB_CIF_rx_ep_set_dma_mode0(ep_num); MSS_USB_CIF_rx_ep_disable_dma(ep_num); } } } /***************************************************************************//** * Writes packet on TX EP */ void MSS_USB_CIF_ep_write_pkt ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length, uint32_t txn_length ) { if (ep_num && (buf_addr != 0)) { if (DMA_ENABLE == dma_enable) { /* Make sure that address is Modulo-4.Bits D0-D1 are read only.*/ ASSERT(!(((ptrdiff_t)buf_addr) & 0x00000002u)); MSS_USB_CIF_dma_write_addr(dma_channel,(ptrdiff_t)(buf_addr)); if (MSS_USB_XFR_BULK == xfr_type) { MSS_USB_CIF_tx_ep_enable_dma(ep_num); /* * DMA-m1 will take care of transferring 'xfr_length' data * as IN packets arrive. * DMA interrupt will occur when all TxMaxPkt size packets * are transferred. */ MSS_USB_CIF_dma_write_count(dma_channel, xfr_length); } else { /* * DMA Enable bit in TxCSR is not needed. If set,TX EP * Interrupt will not occur. */ MSS_USB_CIF_tx_ep_disable_dma(ep_num); /* Transfer only one packet with DMA-m0 */ MSS_USB_CIF_dma_write_count(dma_channel, txn_length); } /* * This will start DMA transfer. * TODO: For Null transfer DMA is not needed, but not setting * TxPktRdy bit here, is not invoking EP interrupt. * EP interrupt does get called when Null DMA transfer is done. */ MSS_USB_CIF_dma_start_xfr(dma_channel); /* * DMA interrupt will occur when all bytes are written to FIFO * TxPktRdy should be set when the DMA interrupt occurs. */ } else /* no DMA */ { MSS_USB_CIF_load_tx_fifo(ep_num, buf_addr, txn_length); MSS_USB_CIF_tx_ep_set_txpktrdy(ep_num); } } } /***************************************************************************//** * Configures DMA for data transfer operations. */ void MSS_USB_CIF_configure_ep_dma ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_dir_t dma_dir, mss_usb_dma_mode_t dma_mode, mss_usb_dma_burst_mode_t burst_mode, mss_usb_ep_num_t ep_num, uint32_t buf_addr ) { MSS_USB_CIF_dma_assign_to_epnum(dma_channel, ep_num); MSS_USB_CIF_dma_set_dir(dma_channel, dma_dir); MSS_USB_CIF_dma_set_mode(dma_channel, dma_mode); MSS_USB_CIF_dma_set_burst_mode(dma_channel, burst_mode); MSS_USB_CIF_dma_write_addr(dma_channel, buf_addr); MSS_USB_CIF_dma_enable_irq(dma_channel); } /***************************************************************************//** * Configures the TX EP for data transfer operations as per the parameters * provided by upper layer. */ void MSS_USB_CIF_tx_ep_configure ( mss_usb_ep_t* core_ep ) { uint8_t dpb = 1u; mss_usb_dma_mode_t mode; if (DPB_ENABLE == core_ep->dpb_enable) { dpb = 2u; } MSS_USB_CIF_tx_ep_set_fifo_size(core_ep->num, ((core_ep->fifo_size) / dpb), core_ep->dpb_enable); MSS_USB_CIF_tx_ep_set_fifo_addr(core_ep->num, core_ep->fifo_addr); if (DPB_ENABLE == core_ep->dpb_enable) { MSS_USB_enable_tx_ep_dpb(core_ep->num); } else if (DPB_DISABLE == core_ep->dpb_enable) { MSS_USB_disable_tx_ep_dpb(core_ep->num); } else { ASSERT(0); } MSS_USB_CIF_tx_ep_set_max_pkt(core_ep->num, core_ep->xfr_type, core_ep->max_pkt_size, core_ep->num_usb_pkt); MSS_USB_CIF_tx_ep_clr_data_tog(core_ep->num); if (DMA_ENABLE == core_ep->dma_enable) { if (MSS_USB_XFR_BULK == core_ep->xfr_type ) { MSS_USB_CIF_tx_ep_set_dma_mode1(core_ep->num); MSS_USB_CIF_tx_ep_enable_dma(core_ep->num); mode = MSS_USB_DMA_MODE1; } else { /* * DMA_ENable bit in TXCSRL is not required to be set for m0. if it * is set TX interrupt would not occur. */ MSS_USB_CIF_tx_ep_set_dma_mode0(core_ep->num); MSS_USB_CIF_tx_ep_disable_dma(core_ep->num); mode = MSS_USB_DMA_MODE0; } MSS_USB_CIF_configure_ep_dma(core_ep->dma_channel, MSS_USB_DMA_READ, mode, MSS_USB_DMA_BURST_MODE3, core_ep->num, (ptrdiff_t)(core_ep->buf_addr)); } MSS_USB_CIF_tx_ep_enable_irq(core_ep->num); } /***************************************************************************//** * Configures the RX EP for data transfer operations as per the parameters * provided by upper layer. */ void MSS_USB_CIF_rx_ep_configure ( mss_usb_ep_t* core_ep ) { uint8_t dpb = 1u; mss_usb_dma_mode_t mode; if (DPB_ENABLE == core_ep->dpb_enable) { dpb = 2u; } MSS_USB_CIF_rx_ep_set_fifo_size(core_ep->num, ((core_ep->fifo_size) / dpb), core_ep->dpb_enable); MSS_USB_CIF_rx_ep_set_fifo_addr(core_ep->num, core_ep->fifo_addr); if (DPB_ENABLE == core_ep->dpb_enable) { MSS_USB_CIF_enable_rx_ep_dpb(core_ep->num); } else if (DPB_DISABLE == core_ep->dpb_enable) { MSS_USB_CIF_disable_rx_ep_dpb(core_ep->num); } else { ASSERT(0); } MSS_USB_CIF_rx_ep_set_max_pkt(core_ep->num, core_ep->xfr_type, core_ep->max_pkt_size, core_ep->num_usb_pkt); MSS_USB_CIF_rx_ep_clr_data_tog(core_ep->num); MSS_USB_CIF_rx_ep_clr_rxpktrdy(core_ep->num); if (DMA_ENABLE == core_ep->dma_enable) { if (MSS_USB_XFR_BULK == core_ep->xfr_type) { MSS_USB_CIF_rx_ep_set_dma_mode1(core_ep->num); MSS_USB_CIF_rx_ep_enable_dma(core_ep->num); mode = MSS_USB_DMA_MODE1; } else { /* * DMA_ENable bit in RXCSRL is not required to be set in m0. if it is * set RX interrupt would not occur. */ MSS_USB_CIF_rx_ep_set_dma_mode0(core_ep->num); MSS_USB_CIF_rx_ep_disable_dma(core_ep->num); mode = MSS_USB_DMA_MODE0; } MSS_USB_CIF_configure_ep_dma(core_ep->dma_channel, MSS_USB_DMA_WRITE, mode, MSS_USB_DMA_BURST_MODE3, core_ep->num, (ptrdiff_t)(core_ep->buf_addr)); } MSS_USB_CIF_rx_ep_enable_irq(core_ep->num); } /***************************************************************************//** * Starts sending Test packet as specified in the USB2.0 * This is USB-IF certification requirement. */ void MSS_USB_CIF_start_testpacket(void) { // uint8_t test_pkt[53] = // { // 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, // 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xEEU, // 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xFEU, 0xFFU, // 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, // 0xFFU, 0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFCU, // 0x7EU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0x7EU // }; // MSS_USB_CIF_load_tx_fifo(MSS_USB_CEP, test_pkt, 53u); // MSS_USB_CIF_start_testpacket_bit(); // MSS_USB_CIF_cep_set_txpktrdy(); // MSS_USB_CIF_cep_disable_irq(); } #ifdef MSS_USB_HOST_ENABLED static uint8_t MSS_USB_CIF_host_rx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0u; if (MSS_USBH_CIF_rx_ep_is_rxpktrdy(ep_num)) { status = 0u; } if (MSS_USBH_CIF_rx_ep_is_rxstall_err(ep_num)) { status |= MSS_USB_EP_STALL_RCVD; MSS_USBH_CIF_rx_ep_clr_rxstall_err(ep_num); } if (MSS_USBH_CIF_rx_ep_is_naktimeout_err(ep_num)) { status |= MSS_USB_EP_NAK_TOUT; /* Not clearing NAKTIMEOUT error here. Application may want to abort * transfer. Clearing it here makes Scheduler keep trying the transfer */ } if (MSS_USBH_CIF_rx_ep_is_retry_err(ep_num)) { status |= MSS_USB_EP_NO_RESPONSE; MSS_USBH_CIF_rx_ep_clr_retry_err(ep_num); } return (status); } static uint8_t MSS_USB_CIF_host_tx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0; if (MSS_USBH_CIF_tx_ep_is_retry_err(ep_num)) { status |= MSS_USB_EP_NO_RESPONSE; MSS_USBH_CIF_tx_ep_clr_retry_err(ep_num); } if (MSS_USBH_CIF_tx_ep_is_rxstall_err(ep_num)) { status |= MSS_USB_EP_STALL_RCVD; MSS_USBH_CIF_tx_ep_clr_rxstall_err(ep_num); } if (MSS_USBH_CIF_tx_ep_is_naktimeout_err(ep_num)) { status |= MSS_USB_EP_NAK_TOUT; /* Not clearing NAKTIMEOUT error here. Application may want to abort * transfer. Clearing it here makes Scheduler keep trying the transfer */ } return(status); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_DEVICE_ENABLED static uint8_t MSS_USB_CIF_device_rx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0u; if (MSS_USB_CIF_rx_ep_is_overrun(ep_num)) { status |= RX_EP_OVER_RUN_ERROR; MSS_USB_CIF_rx_ep_clr_overrun(ep_num); } if (MSS_USB_CIF_rx_ep_is_stall_sent_bit(ep_num)) { status |= RX_EP_STALL_ERROR; /* * "sent stall" bit should be cleared."Send Stall" bit is still set. * it should be cleared via Clear feature command or reset" */ MSS_USB_CIF_rx_ep_clr_stall_sent_bit(ep_num); } if (MSS_USB_CIF_rx_ep_is_dataerr(ep_num)) { /* This error will be cleared when RxPktRdy bit is cleared. */ status |= RX_EP_DATA_ERROR; } #if 0 /* * PID error and INCOMP error should be checked only in ISO transfers. * This should be moved to logical layer */ if (MSS_USB_CIF_rx_ep_is_piderr(ep_num)) { status |= RX_EP_PID_ERROR; /* Data sheet doesn't mention about how this error bit is cleared * Assuming that this will be cleared when RxPKTRdy is cleared.*/ } if (MSS_USB_CIF_rx_ep_is_isoincomp(ep_num)) { status |= RX_EP_ISO_INCOMP_ERROR; /* This error will be cleared when RxPktRdy bit is cleared.*/ } #endif /* if 0 */ return(status); } static uint8_t MSS_USB_CIF_device_tx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0u; if (MSS_USB_CIF_tx_ep_is_underrun(ep_num)) { /* Under-run errors should happen only for ISO endpoints.*/ status |= TX_EP_UNDER_RUN_ERROR; MSS_USB_CIF_tx_ep_clr_underrun(ep_num); } if (MSS_USB_CIF_tx_ep_is_stall_sent_bit(ep_num)) { status |= TX_EP_STALL_ERROR; MSS_USB_CIF_tx_ep_clr_stall_sent_bit(ep_num); } return(status); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_common_cif.h000066400000000000000000000371601432224323300302000ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF driver * * USB-CIF driver public API. * */ #ifndef __MSS_USB_COMMON_CIF_H_ #define __MSS_USB_COMMON_CIF_H_ #include "mss_usb_config.h" #include "mss_usb_core_regs.h" #define __INLINE inline #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** Constant values internally used by the driver. */ #define CEP_MAX_PKT_SIZE 64u #define SETUP_PKT_SIZE 8u #define DPB_DISABLE 0u #define DPB_ENABLE 1u #ifdef MSS_USB_HOST_ENABLED #define SUSPENDM_DISABLE 0x0000u #define SUSPENDM_ENABLE 0x0001u #endif #define MSS_USB_WORD_BIT_0_MASK 0x0001u #define MSS_USB_BYTE_BIT_0_MASK 0x01u #define MSS_USB_BOOLEAN_FALSE 0x00u #define MSS_USB_BOOLEAN_TRUE 0x01u #define TX_EP_UNDER_RUN_ERROR 0x01u #define TX_EP_STALL_ERROR 0x02u #define RX_EP_OVER_RUN_ERROR 0x01u #define RX_EP_STALL_ERROR 0x02u #define RX_EP_DATA_ERROR 0x04u #define RX_EP_PID_ERROR 0x06u #define RX_EP_ISO_INCOMP_ERROR 0x08u #define CTRL_EP_SETUP_END_ERROR 0x01u #define CTRL_EP_STALL_ERROR 0x02u #define DMA_XFR_ERROR 0x40u #define MIN_EP_FIFO_SZ 0x0008u #define EP_FIFO_ADDR_STEP 0x0008u #define DMA_DISABLE 0u #define DMA_ENABLE 1u #define NO_ZLP_TO_XFR 0u #define ADD_ZLP_TO_XFR 1u /*-------------------------------------------------------------------------*//** INTRUSBE register - USB interrupts masks */ #define SUSPEND_IRQ_MASK 0x01u #define RESUME_IRQ_MASK 0x02u #define RESET_IRQ_MASK 0x04u /*Device mode*/ #define BABBLE_IRQ_MASK 0x04u /*Host mode*/ #define SOF_IRQ_MASK 0x08u #define CONNECT_IRQ_MASK 0x10u #define DISCONNECT_IRQ_MASK 0x20u #define SESSION_REQUEST_IRQ_MASK 0x40u #define VBUS_ERROR_IRQ_MASK 0x80u /*-------------------------------------------------------------------------*//** Types which can be used by LDL layer or the application. */ typedef enum { MSS_USB_XFR_CONTROL, MSS_USB_XFR_ISO, MSS_USB_XFR_BULK, MSS_USB_XFR_INTERRUPT, MSS_USB_XFR_HB_INTERRUPT, MSS_USB_XFR_HB_ISO } mss_usb_xfr_type_t; typedef enum { MSS_USB_DEVICE_HS, MSS_USB_DEVICE_FS, MSS_USB_DEVICE_LS } mss_usb_device_speed_t; typedef enum { MSS_USB_CEP = 0, MSS_USB_TX_EP_1, MSS_USB_TX_EP_2, MSS_USB_TX_EP_3, MSS_USB_TX_EP_4, MSS_USB_RX_EP_1 = 1, MSS_USB_RX_EP_2, MSS_USB_RX_EP_3, MSS_USB_RX_EP_4 } mss_usb_ep_num_t; typedef enum { MSS_USB_DMA_CHANNEL1, MSS_USB_DMA_CHANNEL2, MSS_USB_DMA_CHANNEL3, MSS_USB_DMA_CHANNEL4, MSS_USB_DMA_CHANNEL_NA } mss_usb_dma_channel_t; /*-------------------------------------------------------------------------*//** Types which are used internally by the driver. */ /* Device mode: states of the device */ typedef enum { MSS_USB_NOT_ATTACHED_STATE, MSS_USB_ATTACHED_STATE, MSS_USB_POWERED_STATE, MSS_USB_DEFAULT_STATE, MSS_USB_ADDRESS_STATE, MSS_USB_CONFIGURED_STATE, MSS_USB_SUSPENDED_STATE } mss_usb_state_t; typedef enum { MSS_USB_CORE_MODE_HOST, MSS_USB_CORE_MODE_DEVICE } mss_usb_core_mode_t; typedef enum { MSS_USB_EP_VALID = 0u, MSS_USB_EP_STALLED, MSS_USB_EP_NAK, MSS_USB_EP_NYET, MSS_USB_CEP_IDLE, MSS_USB_CEP_SETUP, MSS_USB_CEP_TX, MSS_USB_CEP_RX, #ifdef MSS_USB_HOST_ENABLED MSS_USB_CEP_STATUS_AFTER_IN, MSS_USB_CEP_STATUS_AFTER_OUT, MSS_USB_EP_TXN_SUCCESS, MSS_USB_EP_NAK_TOUT, MSS_USB_EP_NO_RESPONSE, MSS_USB_EP_STALL_RCVD, MSS_USB_EP_XFR_SUCCESS, MSS_USB_EP_ABORTED #endif /* MSS_USB_HOST_ENABLED */ } mss_usb_ep_state_t; typedef enum mss_usb_pkt_type { MSS_USB_SETUP_PKT, MSS_USB_IN_DATA_PKT, MSS_USB_OUT_DATA_PKT, MSS_USB_STATUS_PKT_AFTER_IN, MSS_USB_STATUS_PKT_AFTER_OUT }mss_usb_pkt_type_t; /* Type of device - Detected through DevCTL.D7 register bit depending on the type of connector connected to on-board receptacle. */ typedef enum mss_usb_device_role { MSS_USB_DEVICE_ROLE_DEVICE_A, MSS_USB_DEVICE_ROLE_DEVICE_B } mss_usb_device_role_t; typedef enum { MSS_USB_DMA_WRITE, MSS_USB_DMA_READ } mss_usb_dma_dir_t; typedef enum { MSS_USB_DMA_MODE0=0, MSS_USB_DMA_MODE1=1 } mss_usb_dma_mode_t; typedef enum { MSS_USB_DMA_BURST_MODE0 = 0, MSS_USB_DMA_BURST_MODE1, MSS_USB_DMA_BURST_MODE2, MSS_USB_DMA_BURST_MODE3 } mss_usb_dma_burst_mode_t; typedef enum { VBUS_BLOW_SESSIONEND, VBUS_ABV_SESSIONEND_BLOW_AVALID, VBUS_ABV_AVALID_BLOW_VB_VALID, VBUS_ABV_VB_VALID } mss_usb_vbus_level_t; #ifdef MSS_USB_DEVICE_ENABLED typedef enum { MSS_USB_CTRL_EP_IDLE, MSS_USB_CTRL_EP_TX, MSS_USB_CTRL_EP_RX } mss_usbd_cep_state_t; #endif /* MSS_USB_DEVICE_ENABLED */ /*-------------------------------------------------------------------------*//** Data structures of USB-CIFL which are shared with USB-LL. */ typedef struct { /*EP configuration info*/ mss_usb_ep_num_t num; uint8_t dpb_enable; /*0 or 1*/ uint16_t fifo_size; /*number of bytes*/ uint16_t fifo_addr; /*number of bytes*/ uint8_t dma_enable; mss_usb_dma_channel_t dma_channel; uint16_t max_pkt_size; /*Maxpktsize register value*/ uint8_t stall; mss_usb_ep_state_t state; /*EP data Transfer related info*/ mss_usb_xfr_type_t xfr_type; uint32_t add_zlp; /* Number of pkts in one uFrame in case of Interrupt/ISO HB transfers. Number of split packets in case of Bulk transfers.Should always be more than 0. */ uint8_t num_usb_pkt; uint8_t* buf_addr; /* Transfer level info, used mainly for control transfer where the total length of data transfer is prior know through setup transaction In case of bulk transfer with Autospliting/amalgamation, this value is used when length of transfer is bigger than one amalgamated packet. */ uint32_t xfr_length; uint32_t xfr_count; /* Single packet Transaction level info In case of bulk transfer with Autospliting/amalgamation, this value represents the amalgamated packet. */ uint32_t txn_length; uint32_t txn_count; #ifdef MSS_USB_HOST_ENABLED /* Manual toggle enable is required only when dynamic switching of EP is supported. We don't support it. HubAddr and HubPortNum registers are needed for talking to LS/FS devices connected through Hub - We don't support hub connected devices yet. LS/FS device directly connected to SF2 is supported though. */ uint8_t cep_data_dir; uint8_t* cep_cmd_addr; uint8_t disable_ping; /*Depends on target speed*/ uint32_t req_pkt_n; /*No of IN packets*/ /* Interval Must be in terms of frame/uframe. Indicates NAKLIMIT0 register value for EP0. TX/RXInterval register value for TX/RX EP. */ uint32_t interval; /*This index will be used to choose a particular connected device out of the Multiple connected devices when Multiple devices are supported. Currently we support only one device hence this will always evaluate to 0*/ uint8_t tdev_idx; #endif /* MSS_USB_HOST_ENABLED */ }mss_usb_ep_t; /*-------------------------------------------------------------------------*//** Data structures which are used internally by the driver. */ /*Device mode configuration information*/ typedef struct { uint8_t device_addr; uint8_t device_total_interfaces; uint8_t device_total_ep; mss_usb_state_t device_state; mss_usb_state_t device_state_at_suspend; uint8_t device_status; mss_usb_device_speed_t device_speed; /*USB speed in Device mode*/ uint8_t active_config_num; /*SetConfig command*/ uint8_t active_interface_num;/*SetInterface command*/ uint16_t config_feature_status; uint8_t remote_wakeup; } mss_usbd_dev_conf_t; /* Device mode call-back function called from CIF layer */ typedef struct { void (*usbd_ep_rx)( mss_usb_ep_num_t num, uint8_t status ); void (*usbd_ep_tx_complete)( mss_usb_ep_num_t num, uint8_t status ); void (*usbd_cep_setup)( uint8_t status ); void (*usbd_cep_rx)( uint8_t status ); void (*usbd_cep_tx_complete)( uint8_t status ); void (*usbd_sof)( uint8_t status ); void (*usbd_reset)( void ); void (*usbd_suspend)( void ); void (*usbd_resume)( void ); void (*usbd_disconnect)( void ); void (*usbd_dma_handler)(mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val); } mss_usbd_cb_t; /* MSS USB Hardware core information. This is read-only */ typedef struct { uint8_t core_max_nbr_of_tx_ep; uint8_t core_max_nbr_of_rx_ep; uint8_t core_max_nbr_of_dma_chan; uint8_t core_ram_bus_width; uint8_t core_WTCON; uint8_t core_WTID; uint8_t core_VPLEN; uint8_t core_HS_EOF1; uint8_t core_FS_EOF1; uint8_t core_LS_EOF1; uint8_t core_configdata; } mss_usb_core_info_t; /* Internal DMA Configuration data */ typedef struct { uint8_t dma_channel; uint8_t dma_dir; uint8_t dma_assigned_ep; uint8_t dma_mode; uint8_t dma_burst_mode; uint8_t dma_status; } mss_usb_dma_t; /*----------------------------------------------------------------------------*/ /*_------------------------USB-CIF Public APIs--------------------------------*/ /*----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_cep_flush_fifo(void) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 |= CSR0H_DEV_FLUSH_FIFO_MASK; } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_tx_ep_flush_fifo(mss_usb_ep_num_t ep_num) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_FLUSH_FIFO_MASK; } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_rx_ep_flush_fifo(mss_usb_ep_num_t ep_num) { USB->ENDPOINT[ep_num].RX_CSR |= RxCSRL_REG_EPN_FLUSH_FIFO_MASK; } /*-------------------------------------------------------------------------*//** */ static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_fifo_full(mss_usb_ep_num_t ep_num) { return(((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_RX_FIFO_FULL_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** * Enables USB interrupts. */ static __INLINE void MSS_USB_CIF_enable_usbirq(uint8_t irq_mask) { USB->USB_ENABLE |= (irq_mask); } /*-------------------------------------------------------------------------*//** Disables USB interrupts. */ static __INLINE void MSS_USB_CIF_disable_usbirq(uint8_t irq_mask) { USB->USB_ENABLE &= ~(irq_mask); } /*-------------------------------------------------------------------------*//** Indicates that there is at least one byte available to be transmitted from TX FIFO */ static __INLINE uint8_t MSS_USB_CIF_is_txepfifo_notempty(mss_usb_ep_num_t ep_num) { return(((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_TX_FIFO_NE_MASK) ? 1u : 0u)); } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_cep_enable_irq ( void ) { USB->TX_IRQ_ENABLE |= (uint16_t)(TX_IRQ_ENABLE_REG_CEP_MASK); } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_cep_disable_irq ( void ) { USB->TX_IRQ_ENABLE &= (uint16_t)(~TX_IRQ_ENABLE_REG_CEP_MASK); } /*-------------------------------------------------------------------------*//** INDEX register related APIs */ static __INLINE void MSS_USB_CIF_set_index_reg ( uint8_t index ) { USB->INDEX = index; } static __INLINE void MSS_USB_CIF_start_testse0nak(void) { USB->TEST_MODE = TESTMODE_SE0NAK_MASK; } static __INLINE void MSS_USB_CIF_start_testj(void) { USB->TEST_MODE = TESTMODE_TESTJ_MASK; } static __INLINE void MSS_USB_CIF_start_testk(void) { USB->TEST_MODE = TESTMODE_TESTK_MASK; } static __INLINE void MSS_USB_CIF_start_testpacket_bit(void) { USB->TEST_MODE = TESTMODE_TESTPACKET_MASK; } static __INLINE void MSS_USB_CIF_start_forcehost_ena(void) { USB->TEST_MODE = TESTMODE_FORCEHOST_MASK | TESTMODE_FORCEHS_MASK; } static __INLINE void MSS_USB_CIF_end_testmode(void) { USB->TEST_MODE = 0x00U; } /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_configure_ep_dma ( mss_usb_dma_channel_t channel, mss_usb_dma_dir_t dir, mss_usb_dma_mode_t dma_mode, mss_usb_dma_burst_mode_t burst_mode, mss_usb_ep_num_t ep_num, uint32_t buf_addr ); /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_tx_ep_configure ( mss_usb_ep_t* core_ep ); /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_rx_ep_configure ( mss_usb_ep_t* core_ep ); /*-------------------------------------------------------------------------*//** Prepares the RX EP for receiving data as per parameters provided by upper layer */ void MSS_USB_CIF_rx_ep_read_prepare ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length ); /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_ep_write_pkt ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length, uint32_t txn_length ); /*-------------------------------------------------------------------------*//** USB2.0 test mode functions */ void MSS_USB_CIF_start_testpacket ( void ); #ifdef __cplusplus } #endif #endif /*__MSS_USB_COMMON_CIF_H_*/ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_common_reg_io.h000066400000000000000000000732401432224323300307020ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF. * * This file provides interfaces to perform register bit level * I\O operations which are independent of USB Device/host mode. * */ #ifndef __MSS_USB_COMMON_REG_IO_H_ #define __MSS_USB_COMMON_REG_IO_H_ #include #include "mss_usb_common_cif.h" #include "mss_usb_core_regs.h" #define __INLINE inline #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** * Common function for DEVICE and HOST mode. */ /*-------------------------------------------------------------------------*//** SOFT_RST register related APIs */ static __INLINE void MSS_USB_CIF_soft_reset ( void ) { volatile uint8_t soft_reset; USB->SOFT_RST = SOFT_RESET_REG_MASK; do { soft_reset = USB->SOFT_RST; } while (soft_reset != 0x00u); } /*-------------------------------------------------------------------------*//** POWER register related APIs */ static __INLINE void MSS_USB_CIF_enable_hs_mode ( void ) { USB->POWER |= POWER_REG_ENABLE_HS_MASK; } static __INLINE void MSS_USB_CIF_disable_hs_mode ( void ) { USB->POWER &= ~POWER_REG_ENABLE_HS_MASK; } /*-------------------------------------------------------------------------*//** Read USB interrupt register to know which interrupt has occurred. */ static __INLINE uint8_t MSS_USB_CIF_read_irq_reg ( void ) { return (USB->USB_IRQ); } /*-------------------------------------------------------------------------*//** EP IRQ related APIs */ /* TX IRQ related APIs */ static __INLINE uint16_t MSS_USB_CIF_read_tx_ep_irq_reg ( void ) { return (USB->TX_IRQ); } static __INLINE uint16_t MSS_USB_CIF_read_rx_ep_irq_reg ( void ) { return (USB->RX_IRQ); } static __INLINE void MSS_USB_CIF_clr_usb_irq_reg ( void ) { USB->USB_IRQ = 0u; } static __INLINE void MSS_USB_CIF_tx_ep_enable_irq ( mss_usb_ep_num_t ep_num ) { USB->TX_IRQ_ENABLE |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num); } static __INLINE void MSS_USB_CIF_tx_ep_disable_irq ( mss_usb_ep_num_t ep_num ) { USB->TX_IRQ_ENABLE &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num)); } static __INLINE void MSS_USB_CIF_tx_ep_disable_irq_all ( void ) { /* Keep D0, CEP interrupt bit unaltered.*/ USB->TX_IRQ_ENABLE = (USB->TX_IRQ_ENABLE & TX_IRQ_ENABLE_REG_CEP_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_enable_irq ( mss_usb_ep_num_t ep_num ) { USB->RX_IRQ_ENABLE |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num); } static __INLINE void MSS_USB_CIF_rx_ep_disable_irq ( mss_usb_ep_num_t ep_num ) { USB->RX_IRQ_ENABLE &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num)); } static __INLINE void MSS_USB_CIF_rx_ep_disable_irq_all ( void ) { USB->RX_IRQ_ENABLE = 0u ; } /*-------------------------------------------------------------------------*//** FRAME register related APIs */ static __INLINE uint16_t MSS_USB_CIF_get_last_frame_nbr ( void ) { return (USB->FRAME); } /*-------------------------------------------------------------------------*//** DEVCTL register related APIs */ static __INLINE mss_usb_core_mode_t MSS_USB_CIF_get_mode ( void ) { return (((USB->DEV_CTRL & DEV_CTRL_HOST_MODE_MASK) ? MSS_USB_CORE_MODE_HOST : MSS_USB_CORE_MODE_DEVICE)); } static __INLINE mss_usb_vbus_level_t MSS_USB_CIF_get_vbus_level ( void ) { uint8_t vbus; mss_usb_vbus_level_t ret_val = VBUS_BLOW_SESSIONEND; vbus = (USB->DEV_CTRL & DEV_CTRL_VBUS_MASK); switch (vbus) { case VBUS_BELOW_SESSION_END: ret_val = VBUS_BLOW_SESSIONEND; break; case VBUS_ABOVE_SESSION_END: ret_val = VBUS_ABV_SESSIONEND_BLOW_AVALID; break; case VBUS_ABOVE_AVALID: ret_val = VBUS_ABV_AVALID_BLOW_VB_VALID; break; case VBUS_ABOVE_VBUS_VALID: ret_val = VBUS_ABV_VB_VALID; break; default: /* Empty */ break; } return ret_val; } static __INLINE mss_usb_device_role_t MSS_USB_CIF_get_role ( void ) { /* TODO:only valid when session bit is set */ return (((USB->DEV_CTRL & DEV_CTRL_B_DEVICE_MASK) ? MSS_USB_DEVICE_ROLE_DEVICE_B : MSS_USB_DEVICE_ROLE_DEVICE_A)); } static __INLINE uint8_t MSS_USB_CIF_is_session_on ( void ) { /* TODO:only valid when session bit is set */ return (((USB->DEV_CTRL & DEV_CTRL_SESSION_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_start_session(void) { USB->DEV_CTRL |= DEV_CTRL_SESSION_MASK; } static __INLINE void MSS_USB_CIF_stop_session(void) { USB->DEV_CTRL &= ~DEV_CTRL_SESSION_MASK; } /*-------------------------------------------------------------------------*//** INDEXED registers */ /*-------------------------------------------------------------------------*//** CSR0L register related APIs */ static __INLINE uint8_t MSS_USB_CIF_cep_is_rxpktrdy ( void ) { return (((USB->INDEXED_CSR.DEVICE_EP0.CSR0 & CSR0L_DEV_RX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_cep_set_txpktrdy ( void ) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 |= CSR0L_DEV_TX_PKT_RDY_MASK; } static __INLINE void MSS_USB_CIF_cep_clr_stall_sent ( void ) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 &= ~CSR0L_DEV_STALL_SENT_MASK; } static __INLINE uint8_t MSS_USB_CIF_cep_is_stall_sent ( void ) { return (((USB->INDEXED_CSR.DEVICE_EP0.CSR0 & CSR0L_DEV_STALL_SENT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_cep_clr_setupend ( void ) { /* Setting SERVICED_SETUP_END bit clears SetupEnd bit */ USB->INDEXED_CSR.DEVICE_EP0.CSR0 |= CSR0L_DEV_SERVICED_SETUP_END_MASK; } static __INLINE uint8_t MSS_USB_CIF_cep_is_setupend ( void ) { return (((USB->INDEXED_CSR.DEVICE_EP0.CSR0 & CSR0L_DEV_SETUP_END_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_cep_reset_csr0_reg ( void ) { /* load the reset value for the register */ USB->INDEXED_CSR.DEVICE_EP0.CSR0 = 0u; } /*-------------------------------------------------------------------------*//** CNTRH0 register related APIs */ static __INLINE uint8_t MSS_USB_CIF_cep_rx_byte_count ( void ) { /* TODO:confirm CSR0.D0 bit before returning */ return (USB->INDEXED_CSR.DEVICE_EP0.COUNT0 & COUNT0_REG_MASK); } /*-------------------------------------------------------------------------*//** TXMAXP register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_max_pkt ( mss_usb_ep_num_t ep_num, mss_usb_xfr_type_t xfr_type, uint16_t max_pkt_size, uint8_t num_usb_pkt ) { /* TODO:make sure that there is no data in FIFO before writing into the maxP reg */ if ((ep_num > MSS_USB_CEP) && ((max_pkt_size % 8) == 0u) && (num_usb_pkt > 0u)) { if((num_usb_pkt > 31u)) { /* not allowed */ } else { USB->ENDPOINT[ep_num].TX_MAX_P = 0u; USB->ENDPOINT[ep_num].TX_MAX_P = num_usb_pkt - 1u; USB->ENDPOINT[ep_num].TX_MAX_P <<= TX_MAX_P_REG_NUM_USB_PKT_SHIFT; USB->ENDPOINT[ep_num].TX_MAX_P |= (max_pkt_size); } } } /*-------------------------------------------------------------------------*//** TXCSRL register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_txpktrdy ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_TX_PKT_RDY_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_txpktrdy ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_TX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_set_send_stall_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_SEND_STALL_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_send_stall_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_REG_EPN_SEND_STALL_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_REG_EPN_STALL_SENT_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { return (uint8_t)(((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_STALL_SENT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_clr_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_CLR_DATA_TOG_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_isoincomp ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_ISO_INCOMP_TX_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** TXCSRH register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_dma_mode1 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_DMA_MODE_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_set_dma_mode0 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_DMA_MODE_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_get_dma_mode ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_REG_EPN_DMA_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_set_force_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_FRC_DAT_TOG_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_force_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_FRC_DAT_TOG_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_enable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_ENABLE_DMA_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_disable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_ENABLE_DMA_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_dma_enabled ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_REG_EPN_ENABLE_DMA_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_set_tx_mode ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_TXRX_MODE_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_set_rx_mode ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_TXRX_MODE_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_enable_iso ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_ENABLE_ISO_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_disable_iso ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_ENABLE_ISO_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_set_autoset ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_autoset ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_autoset ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_underrun ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_UNDERRUN_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_clr_underrun ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_REG_EPN_UNDERRUN_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_csrreg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR = 0x0000U; } /*-------------------------------------------------------------------------*//** RXMAXP register related APIs */ static __INLINE void MSS_USB_CIF_rx_ep_set_max_pkt ( mss_usb_ep_num_t ep_num, mss_usb_xfr_type_t xfr_type, uint16_t max_pkt_size, uint8_t num_usb_pkt ) { /* TODO:make sure that there is no data in FIFO before writing into the maxP reg */ if ((ep_num > MSS_USB_CEP) && (max_pkt_size > 0u) && ((max_pkt_size % 8) == 0u)) { if ((num_usb_pkt > 31u)) { /*not allowed*/ } else { USB->ENDPOINT[ep_num].RX_MAX_P = 0u; USB->ENDPOINT[ep_num].RX_MAX_P = num_usb_pkt - 1u; USB->ENDPOINT[ep_num].RX_MAX_P <<= RX_MAX_P_REG_NUM_USB_PKT_SHIFT; USB->ENDPOINT[ep_num].RX_MAX_P |= (max_pkt_size); } } } /*-------------------------------------------------------------------------*//** RXCSRL register related APIs */ static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_rxpktrdy ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_RX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_rxpktrdy ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RxCSRL_REG_EPN_RX_PKT_RDY_MASK; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_overrun ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_OVERRUN_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_overrun ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_OVERRUN_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_dataerr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_DATA_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_set_send_stall_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_SEND_STALL_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_clr_send_stall_bit ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_SEND_STALL_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_STALL_SENT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_STALL_SENT_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_clr_data_tog ( mss_usb_ep_num_t ep_num ) { /* setting CLR_DAT_TOG bit clears USB Data toggle bit */ USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_CLR_DAT_TOG_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } /*-------------------------------------------------------------------------*//** RXCSRH register related APIs */ static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_isoincomp ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_RX_ISO_INCOMP) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE mss_usb_dma_mode_t MSS_USB_CIF_rx_ep_get_dma_mode ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_DMA_MODE_MASK) ? MSS_USB_DMA_MODE1 : MSS_USB_DMA_MODE0)); } static __INLINE void MSS_USB_CIF_rx_ep_set_dma_mode1 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_DMA_MODE_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_set_dma_mode0 ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_DMA_MODE_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_enable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_ENABLE_DMA_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_disable_dma ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_ENABLE_DMA_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_dma_enabled ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_ENABLE_DMA_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_piderr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_ISO_PID_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_disable_nyet ( mss_usb_ep_num_t ep_num ) { /* Setting BI_DIS_NYET mask disables NYET */ USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_BI_DIS_NYET_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_enable_nyet ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_BI_DIS_NYET_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_disable_iso ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_ENABLE_ISO_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_enable_iso ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_ENABLE_ISO_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_set_autoclr ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_clr_autoclr ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_autoclr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_csrreg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR = 0x0000U; } /*-------------------------------------------------------------------------*//** RXCOUNT register related APIs */ static __INLINE uint16_t MSS_USB_CIF_rx_ep_read_count ( mss_usb_ep_num_t ep_num ) { /* only valid when rxpktrdy is set */ return (USB->ENDPOINT[ep_num].RX_COUNT); } /*-------------------------------------------------------------------------*//** FIFOx register related APIs */ static __INLINE void MSS_USB_CIF_load_tx_fifo ( mss_usb_ep_num_t ep_num, void * in_data, uint32_t length ) { uint32_t idx; uint32_t* temp; uint8_t* temp_8bit; uint16_t words = length / 4; temp = in_data; temp_8bit = in_data; for(idx = 0u; idx < words; ++idx) { USB->FIFO[ep_num].WORD.VALUE = (uint32_t)temp[idx]; } for(idx = (length - (length % 4)); idx < length; ++idx) { USB->FIFO[ep_num].BYTE.VALUE = (uint8_t)temp_8bit[idx]; } } static __INLINE void MSS_USB_CIF_read_rx_fifo ( mss_usb_ep_num_t ep_num, void * out_data, uint32_t length ) { uint32_t idx; volatile uint32_t* temp; uint8_t* temp_8bit; uint16_t words = length / 4; temp = out_data; temp_8bit = out_data; for(idx = 0u; idx < words; ++idx) { temp[idx] = USB->FIFO[ep_num].WORD.VALUE; } for(idx = (length - (length % 4u)); idx < length; ++idx) { temp_8bit[idx] = USB->FIFO[ep_num].BYTE.VALUE; } } static __INLINE uint8_t MSS_USB_CIF_read_rx_fifo_byte ( mss_usb_ep_num_t ep_num ) { return (uint8_t)(USB->FIFO[ep_num].BYTE.VALUE); } static __INLINE uint16_t MSS_USB_CIF_read_rx_fifo_halfword ( mss_usb_ep_num_t ep_num ) { return (uint16_t)(USB->FIFO[ep_num].HALFWORD.VALUE); } static __INLINE uint32_t MSS_USB_CIF_read_rx_fifo_word ( mss_usb_ep_num_t ep_num ) { return (uint32_t)(USB->FIFO[ep_num].WORD.VALUE); } /*-------------------------------------------------------------------------*//** DynFIFOSIZE register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_fifo_size ( mss_usb_ep_num_t ep_num, uint16_t fifo_size, uint8_t dpb ) { uint16_t temp; uint8_t i = 0; /* Valid FIFO sizes are 8,16,32,64,128,512,1024,2048,4096 */ if ((ep_num > MSS_USB_CEP) && (fifo_size >= MIN_EP_FIFO_SZ)) { USB->INDEX = ep_num; temp = (fifo_size / MIN_EP_FIFO_SZ); while (!(temp & MSS_USB_WORD_BIT_0_MASK)) { temp >>= 1u; i++; } USB->TX_FIFO_SIZE = ((dpb << TXFIFOSZ_REG_DPB_SHIFT) | i); } } static __INLINE void MSS_USB_CIF_rx_ep_set_fifo_size ( mss_usb_ep_num_t ep_num, uint16_t fifo_size, uint8_t dpb ) { /* fifo_size is the size in terms of number of bytes.*/ uint16_t temp; uint8_t i = 0u; /* Valid FIFO sizes are 8,16,32,64,128,512,1024,2048,4096 */ if ((ep_num > MSS_USB_CEP) && (fifo_size >= MIN_EP_FIFO_SZ)) { USB->INDEX = ep_num; temp= (fifo_size / MIN_EP_FIFO_SZ); while (!(temp & MSS_USB_WORD_BIT_0_MASK)) { temp >>= 1u; i++; } USB->RX_FIFO_SIZE = ((dpb << RXFIFOSZ_REG_DPB_SHIFT) | i); } } /*-------------------------------------------------------------------------*//** DynFIFOAD register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_fifo_addr ( mss_usb_ep_num_t ep_num, uint16_t addr ) { /* Valid address values are from 0 to FFF8 in steps of 8 */ if (ep_num > MSS_USB_CEP) { USB->INDEX = ep_num; USB->TX_FIFO_ADDR = (addr / EP_FIFO_ADDR_STEP); } } static __INLINE void MSS_USB_CIF_rx_ep_set_fifo_addr ( mss_usb_ep_num_t ep_num, uint16_t addr ) { /* Valid address values are from 0 to FFF8 in steps of 8 */ if (ep_num > MSS_USB_CEP) { USB->INDEX = ep_num; USB->RX_FIFO_ADDR = (addr / EP_FIFO_ADDR_STEP); } } /*-------------------------------------------------------------------------*//** RX_DPKTBUFDIS register related APIs */ static __INLINE void MSS_USB_CIF_disable_rx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->RX_DPBUF_DIS |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << ep_num); } static __INLINE void MSS_USB_CIF_enable_rx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->RX_DPBUF_DIS &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << ep_num)); } /*-------------------------------------------------------------------------*//** TX_DPKTBUFDIS register related APIs */ static __INLINE void MSS_USB_disable_tx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->TX_DPBUF_DIS |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << ep_num); } static __INLINE void MSS_USB_enable_tx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->TX_DPBUF_DIS &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << ep_num)); } /*-------------------------------------------------------------------------*//** DMA_INTR register related APIs */ static __INLINE uint32_t MSS_USB_CIF_dma_read_irq ( void ) { return (USB->DMA_CHANNEL[0].IRQ); } /*-------------------------------------------------------------------------*//** * DMA_CNTL register related APIs */ static __INLINE void MSS_USB_CIF_dma_start_xfr ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL |= DMA_CNTL_REG_START_XFR_MASK; } static __INLINE void MSS_USB_CIF_dma_stop_xfr ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL &= ~DMA_CNTL_REG_START_XFR_MASK; } static __INLINE void MSS_USB_CIF_dma_set_dir ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_dir_t dir ) { /* dir = 1 => DMA read (TX EP) dir = 0 => DMA write (RX EP) */ USB->DMA_CHANNEL[dma_channel].CNTL |= (dir << DMA_CNTL_REG_DMA_DIR_SHIFT); } static __INLINE mss_usb_dma_dir_t MSS_USB_CIF_dma_get_dir ( mss_usb_dma_channel_t dma_channel ) { return(((USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_DIR_MASK) ? MSS_USB_DMA_READ : MSS_USB_DMA_WRITE)); } static __INLINE void MSS_USB_CIF_dma_set_mode ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_mode_t dma_mode ) { USB->DMA_CHANNEL[dma_channel].CNTL |= (dma_mode << DMA_CNTL_REG_DMA_MODE_SHIFT); } static __INLINE mss_usb_dma_mode_t MSS_USB_CIF_dma_get_mode ( mss_usb_dma_channel_t dma_channel ) { return (((USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_MODE_MASK) ? MSS_USB_DMA_MODE1: MSS_USB_DMA_MODE0)); } static __INLINE void MSS_USB_CIF_dma_enable_irq ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL |= DMA_CNTL_REG_ENABLE_DMA_IRQ_MASK; } static __INLINE void MSS_USB_CIF_dma_disable_irq ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL &= ~DMA_CNTL_REG_ENABLE_DMA_IRQ_MASK; } static __INLINE void MSS_USB_CIF_dma_assign_to_epnum ( mss_usb_dma_channel_t dma_channel, mss_usb_ep_num_t ep_num ) { USB->DMA_CHANNEL[dma_channel].CNTL |= ((ep_num << DMA_CNTL_REG_DMA_EP_NUM_SHIFT) & DMA_CNTL_REG_DMA_EP_NUM_MASK); } static __INLINE mss_usb_ep_num_t MSS_USB_CIF_dma_get_epnum ( mss_usb_dma_channel_t dma_channel ) { /* This API will return numbers from 0 to 15, mss_usb_ep_num_t maps it to TX EP numbers. Using DMA DIR, CIF driver should correctly map it as TX EP or RX EP. */ volatile uint8_t ep_num; ep_num = (USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_EP_NUM_MASK); return (mss_usb_ep_num_t)(ep_num >> DMA_CNTL_REG_DMA_EP_NUM_SHIFT); } static __INLINE uint8_t MSS_USB_CIF_dma_is_bus_err ( mss_usb_dma_channel_t dma_channel ) { return (((USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_BUS_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_dma_clr_bus_err ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL &= ~DMA_CNTL_REG_DMA_BUS_ERR_MASK; } static __INLINE void MSS_USB_CIF_dma_set_burst_mode ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_burst_mode_t burst_mode ) { USB->DMA_CHANNEL[dma_channel].CNTL |= ((burst_mode << DMA_CNTL_REG_DMA_BURST_MODE_SHIFT) & DMA_CNTL_REG_DMA_BURST_MODE_MASK); } static __INLINE mss_usb_dma_burst_mode_t MSS_USB_CIF_dma_get_burst_mode ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_burst_mode_t burst_mode ) { uint8_t mode; mode = (USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_BURST_MODE_MASK); return (mss_usb_dma_burst_mode_t)(mode >> DMA_CNTL_REG_DMA_BURST_MODE_SHIFT); } static __INLINE void MSS_USB_CIF_dma_clr_ctrlreg ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL = 0x0000U; } /*-------------------------------------------------------------------------*//** DMA_ADDR register related APIs */ static __INLINE uint32_t MSS_USB_CIF_dma_read_addr ( mss_usb_dma_channel_t dma_channel ) { return (USB->DMA_CHANNEL[dma_channel].ADDR); } static __INLINE void MSS_USB_CIF_dma_write_addr ( mss_usb_dma_channel_t dma_channel, uint32_t addr ) { USB->DMA_CHANNEL[dma_channel].ADDR = addr; } /*-------------------------------------------------------------------------*//** DMA_COUNT register related APIs */ static __INLINE uint32_t MSS_USB_CIF_dma_read_count ( mss_usb_dma_channel_t dma_channel ) { return (USB->DMA_CHANNEL[dma_channel].COUNT); } static __INLINE void MSS_USB_CIF_dma_write_count ( mss_usb_dma_channel_t dma_channel, uint32_t count ) { USB->DMA_CHANNEL[dma_channel].COUNT = count; } #ifdef __cplusplus } #endif #endif /* __MSS_USB_COMMON_REG_IO_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_config.h000066400000000000000000000055151432224323300273330ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC MSS USB Driver Stack * * MSS USB Driver stack configuration parameters. * User must choose the constant definitions in this file to select the mode of * operation. * The constants defined in this file are used by MSS USB driver stack to * function as per configuration. * */ #ifndef __MSS_USB_CONFIG_H_ #define __MSS_USB_CONFIG_H_ /*-------------------------------------------------------------------------*//** User should choose the Mode in which PolarFire SoC MSS USB should operate */ /* #define MSS_USB_OTG_DUAL_ROLE_MODE */ /* #define MSS_USB_OTG_PERIPHERAL_MODE*/ /* Configures the MSS USB Driver Stack to operate in USB Host mode. */ /* #define MSS_USB_OTG_HOST_MODE */ /* Configures the MSS USB Driver Stack to operate in USB Device mode. */ #define MSS_USB_PERIPHERAL_MODE /* Used for internal testing of the driver. Not for Application use. */ /* #define MSS_USB_DEVICE_TEST_MODE */ /*-------------------------------------------------------------------------*//** Definitions Internally generated for use in the Core and logical layer. */ #ifdef MSS_USB_OTG_DUAL_ROLE_MODE #define MSS_USB_HOST_ENABLED #define MSS_USB_DEVICE_ENABLED #define MSS_USB_OTG_SRP_ENABLED #define MSS_USB_OTG_HNP_ENABLED #endif #ifdef MSS_USB_OTG_PERIPHERAL_MODE #define MSS_USB_DEVICE_ENABLED #define MSS_USB_OTG_SRP_ENABLED #endif #ifdef MSS_USB_PERIPHERAL_MODE #define MSS_USB_DEVICE_ENABLED #define MSS_USB_DEVICE_PRINTER #endif #ifdef MSS_USB_OTG_HOST_MODE #define MSS_USB_HOST_ENABLED #define MSS_USB_OTG_SRP_ENABLED #endif #endif /* __MSS_USB_CONFIG_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_core_regs.h000066400000000000000000000457041432224323300300420ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF driver * * * Register bit offset and mask definitions for PolarFire SoC MSS USB. * */ #ifndef __MSS_USB_CORE_REGS_H_ #define __MSS_USB_CORE_REGS_H_ #include #include /****************************************************************************** * Power register */ #define POWER_REG_ENABLE_SUSPENDM_MASK 0x01u #define POWER_REG_SUSPEND_MODE_MASK 0x02u #define POWER_REG_RESUME_SIGNAL_MASK 0x04u #define POWER_REG_BUS_RESET_SIGNAL_MASK 0x08u #define POWER_REG_HS_MODE_MASK 0x10u #define POWER_REG_ENABLE_HS_MASK 0x20u #define POWER_REG_SOFT_CONN_MASK 0x40u #define POWER_REG_ISO_UPDATE_MASK 0x80u /****************************************************************************** * Soft_reset_mask */ #define SOFT_RESET_REG_MASK 0x03u /****************************************************************************** * DevCTL register bit masks */ #define DEV_CTRL_SESSION_MASK 0x01u #define DEV_CTRL_HOST_REQ_MASK 0x02u #define DEV_CTRL_HOST_MODE_MASK 0x04u #define DEV_CTRL_VBUS_MASK 0x18u #define DEV_CTRL_LS_DEV_MASK 0x20u #define DEV_CTRL_FS_DEV_MASK 0x40u #define DEV_CTRL_B_DEVICE_MASK 0x80u #define VBUS_BELOW_SESSION_END 0x00u #define VBUS_ABOVE_SESSION_END 0x08u #define VBUS_ABOVE_AVALID 0x10u #define VBUS_ABOVE_VBUS_VALID 0x18u /****************************************************************************** * CSR0L bit masks (peripheral mode) */ #define CSR0L_DEV_RX_PKT_RDY_MASK 0x0001u #define CSR0L_DEV_TX_PKT_RDY_MASK 0x0002u #define CSR0L_DEV_STALL_SENT_MASK 0x0004u #define CSR0L_DEV_DATA_END_MASK 0x0008u #define CSR0L_DEV_SETUP_END_MASK 0x0010u #define CSR0L_DEV_SEND_STALL_MASK 0x0020u #define CSR0L_DEV_SERVICED_RX_PKT_RDY_MASK 0x0040u #define CSR0L_DEV_SERVICED_SETUP_END_MASK 0x0080u /****************************************************************************** * CSR0H bit masks (peripheral mode) */ #define CSR0H_DEV_FLUSH_FIFO_MASK 0x0100u /****************************************************************************** * COUNT0 register masks */ #define COUNT0_REG_MASK 0x7fu /****************************************************************************** * Endpoint TxMAXP register bit masks */ #define TX_MAX_P_REG_NUM_USB_PKT_SHIFT 11u /****************************************************************************** * Endpoint TxCSRL register bit masks */ #define TxCSRL_REG_EPN_TX_PKT_RDY_MASK 0x0001u #define TxCSRL_REG_EPN_TX_FIFO_NE_MASK 0x0002u #define TxCSRL_REG_EPN_UNDERRUN_MASK 0x0004u #define TxCSRL_REG_EPN_FLUSH_FIFO_MASK 0x0008u #define TxCSRL_REG_EPN_SEND_STALL_MASK 0x0010u #define TxCSRL_REG_EPN_STALL_SENT_MASK 0x0020u #define TxCSRL_REG_EPN_CLR_DATA_TOG_MASK 0x0040u #define TxCSRL_REG_EPN_ISO_INCOMP_TX_MASK 0x0080u /****************************************************************************** * Endpoint TxCSRH register bit masks */ /*D0,D1 are un-used*/ #define TxCSRH_REG_EPN_DMA_MODE_MASK 0x0400u #define TxCSRH_REG_EPN_FRC_DAT_TOG_MASK 0x0800u #define TxCSRH_REG_EPN_ENABLE_DMA_MASK 0x1000u #define TxCSRH_REG_EPN_TXRX_MODE_MASK 0x2000u #define TxCSRH_REG_EPN_ENABLE_ISO_MASK 0x4000u #define TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK 0x8000u /****************************************************************************** * Endpoint TxMAXP register bit masks */ #define RX_MAX_P_REG_NUM_USB_PKT_SHIFT 11u /****************************************************************************** * Endpoint RxCSRL register bit masks */ #define RxCSRL_REG_EPN_RX_PKT_RDY_MASK 0x0001u #define RxCSRL_REG_EPN_RX_FIFO_FULL_MASK 0x0002u #define RxCSRL_REG_EPN_OVERRUN_MASK 0x0004u #define RxCSRL_REG_EPN_DATA_ERR_MASK 0x0008u #define RxCSRL_REG_EPN_FLUSH_FIFO_MASK 0x0010u #define RxCSRL_REG_EPN_SEND_STALL_MASK 0x0020u #define RxCSRL_REG_EPN_STALL_SENT_MASK 0x0040u #define RxCSRL_REG_EPN_CLR_DAT_TOG_MASK 0x0080u /****************************************************************************** * Endpoint RxCSRH register bit masks */ #define RxCSRL_REG_EPN_RX_ISO_INCOMP 0x0100u /*D1,D2 are unused*/ #define RxCSRL_REG_EPN_DMA_MODE_MASK 0x0800u #define RxCSRL_REG_EPN_ISO_PID_ERR_MASK 0x1000u #define RxCSRL_REG_EPN_BI_DIS_NYET_MASK 0x1000u #define RxCSRL_REG_EPN_ENABLE_DMA_MASK 0x2000u #define RxCSRL_REG_EPN_ENABLE_ISO_MASK 0x4000u #define RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK 0x8000u /****************************************************************************** * Endpoint DMA_CNTL register bit masks */ #define DMA_CNTL_REG_START_XFR_MASK 0x00000001u #define DMA_CNTL_REG_DMA_DIR_MASK 0x00000002u #define DMA_CNTL_REG_DMA_MODE_MASK 0x00000004u #define DMA_CNTL_REG_ENABLE_DMA_IRQ_MASK 0x00000008u #define DMA_CNTL_REG_DMA_EP_NUM_MASK 0x000000F0u #define DMA_CNTL_REG_DMA_BUS_ERR_MASK 0x00000100u #define DMA_CNTL_REG_DMA_BURST_MODE_MASK 0x00000600u #define DMA_CNTL_REG_DMA_BURST_MODE_SHIFT 9u #define DMA_CNTL_REG_DMA_EP_NUM_SHIFT 4u #define DMA_CNTL_REG_DMA_DIR_SHIFT 1u #define DMA_CNTL_REG_DMA_MODE_SHIFT 2u /****************************************************************************** * TX Endpoint Fifo size masks */ #define TXFIFOSZ_REG_DPB_SHIFT 4u /****************************************************************************** * RX Endpoint Fifo size masks */ #define RXFIFOSZ_REG_DPB_SHIFT 4u /****************************************************************************** * TX_IRQ_ENABLE register masks */ #define TX_IRQ_ENABLE_REG_CEP_MASK 0x0001u /****************************************************************************** * Host Side register definitions */ /****************************************************************************** * CSR0L bit masks */ #define CSR0L_HOST_RX_PKT_RDY_MASK 0x0001u #define CSR0L_HOST_TX_PKT_RDY_MASK 0x0002u #define CSR0L_HOST_STALL_RCVD_MASK 0x0004u #define CSR0L_HOST_SETUP_PKT_MASK 0x0008u #define CSR0L_HOST_RETRY_ERR_MASK 0x0010u #define CSR0L_HOST_IN_PKT_REQ_MASK 0x0020u #define CSR0L_HOST_STATUS_PKT_MASK 0x0040u #define CSR0L_HOST_NAK_TIMEOUT_MASK 0x0080u /****************************************************************************** * CSR0H bit masks */ #define CSR0H_HOST_FLUSH_FIFO_MASK 0x0100u/*Self Clearing*/ #define CSR0H_HOST_DATA_TOG_MASK 0x0200u #define CSR0H_HOST_DATA_TOG_WE_MASK 0x0400u/*Self Clearing*/ #define CSR0H_HOST_DISABLE_PING_MASK 0x0800u /****************************************************************************** * Type0 register bit masks */ #define TYPE0_HOST_MP_TARGET_SPEED_MASK 0xC0u #define TYPE0_HOST_MP_TARGET_SPEED_HIGH 0x40u #define TYPE0_HOST_MP_TARGET_SPEED_FULL 0x80u #define TYPE0_HOST_MP_TARGET_SPEED_LOW 0xC0u #define TYPE0_HOST_MP_TARGET_SPEED_SELF 0x00u #define TYPE0_HOST_MP_TARGET_SPEED_SHIFT 6u /****************************************************************************** * NAKLIMIT0 register bit masks */ #define NAKLIMIT0_REG_MASK 0x00u /****************************************************************************** * Endpoint TxCSRL register bit masks */ #define TxCSRL_HOST_EPN_TX_PKT_RDY_MASK 0x0001u #define TxCSRL_HOST_EPN_TX_FIFO_NE_MASK 0x0002u #define TxCSRL_HOST_EPN_RESPONSE_ERR_MASK 0x0004u #define TxCSRL_HOST_EPN_FLUSH_FIFO_MASK 0x0008u #define TxCSRL_HOST_EPN_SETUP_PKT_MASK 0x0010u #define TxCSRL_HOST_EPN_STALL_RCVD_MASK 0x0020u #define TxCSRL_HOST_EPN_CLR_DATA_TOG_MASK 0x0040u #define TxCSRL_HOST_EPN_NAK_TIMEOUT_MASK 0x0080u /****************************************************************************** * Endpoint TxCSRH register bit masks */ #define TxCSRH_HOST_EPN_DATA_TOG_MASK 0x0100u #define TxCSRH_HOST_EPN_DATA_TOG_WE_MASK 0x0200u #define TxCSRH_HOST_EPN_DMA_MODE_MASK 0x0400u #define TxCSRH_HOST_EPN_FRC_DATA_TOG_MASK 0x0800u #define TxCSRH_HOST_EPN_ENABLE_DMA_MASK 0x1000u #define TxCSRH_HOST_EPN_TXRX_MODE_MASK 0x2000u /*D6 is unused*/ #define TxCSRH_HOST_EPN_ENABLE_AUTOSET_MASK 0x8000u /****************************************************************************** * Endpoint RxCSRL register bit masks */ #define RXCSRL_HOST_EPN_RX_PKT_RDY_MASK 0x0001u #define RXCSRL_HOST_EPN_RX_FIFO_FULL_MASK 0x0002u #define RXCSRL_HOST_EPN_RESPONSE_ERR_MASK 0x0004u #define RXCSRL_HOST_EPN_NAK_TIMEOUT_ERR_MASK 0x0008u #define RXCSRL_HOST_EPN_FLUSH_FIFO_MASK 0x0010u #define RXCSRL_HOST_EPN_IN_PKT_REQ_MASK 0x0020u #define RXCSRL_HOST_EPN_STALL_RCVD_MASK 0x0040u #define RXCSRL_HOST_EPN_CLR_DATA_TOG_MASK 0x0080u /****************************************************************************** * Endpoint RxCSRH register bit masks */ #define RXCSRH_HOST_EPN_RX_ISO_INCOMP 0x0100u #define RXCSRH_HOST_EPN_DATA_TOG_MASK 0x0200u #define RXCSRH_HOST_EPN_DATA_TOG_WE_MASK 0x0400u #define RXCSRH_HOST_EPN_DMA_MODE_MASK 0x0800u #define RXCSRH_HOST_EPN_PID_ERR_MASK 0x1000u #define RXCSRH_HOST_EPN_ENABLE_DMA_MASK 0x2000u #define RXCSRH_HOST_EPN_ENABLE_AUTOREQ_MASK 0x4000u #define RXCSRH_HOST_EPN_ENABLE_AUTOCLR_MASK 0x8000u /****************************************************************************** * TXType register bit masks */ #define TXTYPE_HOST_TARGET_EP_NUM_MASK 0x0Fu #define TXTYPE_HOST_TARGET_EP_PROTOCOL_MASK 0x30u #define TXTYPE_HOST_TARGET_EP_SPEED_MASK 0xC0u #define TXTYPE_HOST_TARGET_EP_NUM_SHIFT 0u #define TXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT 4u #define TXTYPE_HOST_TARGET_EP_SPEED_SHIFT 6u /****************************************************************************** TXINTERVAL register bit masks */ #define TXINTERVAL_HOST_REG_MASK 0x00 /****************************************************************************** TXType register bit masks */ #define RXTYPE_HOST_TARGET_EP_NUM_MASK 0x0Fu #define RXTYPE_HOST_TARGET_EP_PROTOCOL_MASK 0x30u #define RXTYPE_HOST_TARGET_EP_SPEED_MASK 0xC0u #define RXTYPE_HOST_TARGET_EP_NUM_SHIFT 0u #define RXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT 4u #define RXTYPE_HOST_TARGET_EP_SPEED_SHIFT 6u /****************************************************************************** RXINTERVAL register bit masks */ #define RXINTERVAL_HOST_REG_MASK 0x00u /****************************************************************************** TX/RXFUNCTIONADDR register bit masks */ #define TARGET_DEVICE_ADDR_MASK 0x7Fu /****************************************************************************** TX/RXHUBADDR register bit masks */ #define TARGET_DEVICE_HUB_ADDR_MASK 0x7Fu #define TARGET_DEVICE_HUB_MT_MASK 0x10u #define TARGET_DEVICE_HUB_MT_SHIFT 7u /****************************************************************************** TX/RXHUBPORT register bit masks */ #define TARGET_DEVICE_HUB_PORT_MASK 0x7Fu /****************************************************************************** TESTMODE register bit masks */ #define TESTMODE_SE0NAK_MASK 0x01u #define TESTMODE_TESTJ_MASK 0x02u #define TESTMODE_TESTK_MASK 0x04u #define TESTMODE_TESTPACKET_MASK 0x08u #define TESTMODE_FORCEHS_MASK 0x10u #define TESTMODE_FORCEFS_MASK 0x20u #define TESTMODE_FIFOACCESS_MASK 0x40u/*Self Clearing*/ #define TESTMODE_FORCEHOST_MASK 0x80u typedef struct { volatile uint16_t TX_MAX_P; volatile uint16_t TX_CSR; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t RX_COUNT; volatile uint8_t TX_TYPE; volatile uint8_t TX_INTERVAL; volatile uint8_t RX_TYPE; volatile uint8_t RX_INTERVAL; volatile uint8_t RESERVED; volatile uint8_t FIFO_SIZE; } USB_endpoint_regs_t; typedef struct { volatile uint8_t TX_FUNC_ADDR; volatile uint8_t UNUSED0; volatile uint8_t TX_HUB_ADDR; volatile uint8_t TX_HUB_PORT; volatile uint8_t RX_FUNC_ADDR; volatile uint8_t UNUSED1; volatile uint8_t RX_HUB_ADDR; volatile uint8_t RX_HUB_PORT; } USB_tar_t; typedef union { struct { volatile uint32_t VALUE; } WORD; struct { volatile uint8_t VALUE; volatile uint8_t RESERVED1; volatile uint8_t RESERVED2; volatile uint8_t RESERVED3; } BYTE; struct { volatile uint16_t VALUE; volatile uint16_t RESERVED; } HALFWORD; } USB_fifo_t; typedef union { struct { volatile uint16_t TX_MAX_P; volatile uint16_t CSR0; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t COUNT0; volatile uint8_t RESERVED0; volatile uint8_t RESERVED1; volatile uint8_t RESERVED2; volatile uint8_t RESERVED3; volatile uint8_t RESERVED4; volatile uint8_t CONFIG_DATA; } DEVICE_EP0; struct { volatile uint16_t TX_MAX_P; volatile uint16_t TX_CSR; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t RX_COUNT; volatile uint8_t RESERVED0; volatile uint8_t RESERVED1; volatile uint8_t RESERVED2; volatile uint8_t RESERVED3; volatile uint8_t RESERVED4; volatile uint8_t FIFO_SIZE; } DEVICE_EPN; struct { volatile uint16_t TX_MAX_P; volatile uint16_t CSR0; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t COUNT0; volatile uint8_t TYPE0; volatile uint8_t NAK_LIMIT0; volatile uint8_t RX_TYPE; volatile uint8_t RX_INTERVAL; volatile uint8_t RESERVED0; volatile uint8_t CONFIG_DATA; } HOST_EP0; struct { volatile uint16_t TX_MAX_P; volatile uint16_t TX_CSR; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t RX_COUNT; volatile uint8_t TX_TYPE; volatile uint8_t TX_INTERVAL; volatile uint8_t RX_TYPE; volatile uint8_t RX_INTERVAL; volatile uint8_t RESERVED0; volatile uint8_t FIFO_SIZE; } HOST_EPN; } USB_indexed_csr_t; typedef struct { volatile uint32_t IRQ; volatile uint32_t CNTL; volatile uint32_t ADDR; volatile uint32_t COUNT; } USB_DMA_channel; typedef struct { /* * Common USB Registers */ volatile uint8_t FADDR; volatile uint8_t POWER; volatile uint16_t TX_IRQ; volatile uint16_t RX_IRQ; volatile uint16_t TX_IRQ_ENABLE; volatile uint16_t RX_IRQ_ENABLE; volatile uint8_t USB_IRQ; volatile uint8_t USB_ENABLE; volatile uint16_t FRAME; volatile uint8_t INDEX; volatile uint8_t TEST_MODE; /* * Indexed CSR */ USB_indexed_csr_t INDEXED_CSR; /* * Endpoint FIFOs */ USB_fifo_t FIFO[16]; /* * OTG, dynamic FIFO and version */ volatile uint8_t DEV_CTRL; volatile uint8_t MISC; volatile uint8_t TX_FIFO_SIZE; volatile uint8_t RX_FIFO_SIZE; volatile uint16_t TX_FIFO_ADDR; volatile uint16_t RX_FIFO_ADDR; volatile uint32_t VBUS_CSR; volatile uint16_t HW_VERSION; volatile uint16_t RESERVED; /* * ULPI and configuration registers */ volatile uint8_t ULPI_VBUS_CTRL; volatile uint8_t ULPI_CARKIT_CTRL; volatile uint8_t ULPI_IRQ_MASK; volatile uint8_t ULPI_IRQ_SRC; volatile uint8_t ULPI_DATA_REG; volatile uint8_t ULPI_ADDR_REG; volatile uint8_t ULPI_CTRL_REG; volatile uint8_t ULPI_RAW_DATA; volatile uint8_t EP_INFO; volatile uint8_t RAM_INFO; volatile uint8_t LINK_INFO; volatile uint8_t VP_LEN; volatile uint8_t HS_EOF1; volatile uint8_t FS_EOF1; volatile uint8_t LS_EOF1; volatile uint8_t SOFT_RST; /* * Target Address registers */ USB_tar_t TAR[16]; /* * Endpoints CSR */ USB_endpoint_regs_t ENDPOINT[16]; /* * DMA */ USB_DMA_channel DMA_CHANNEL[8]; volatile uint32_t RESERVED_EXT[32]; volatile uint32_t RQ_PKT_CNT[16]; volatile uint16_t RX_DPBUF_DIS; volatile uint16_t TX_DPBUF_DIS; volatile uint16_t C_T_UCH; volatile uint16_t C_T_HHSRTN; volatile uint16_t C_T_HSBT; } MSS_USB_TypeDef; #define USB ((MSS_USB_TypeDef *) USB_BASE) #define USB_BASE 0x20201000u #endif /*__MSS_USB_CORE_REGS_H_*/ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device.c000066400000000000000000002122521432224323300273160ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBD driver * * USBD driver implementation: * This source file implements the common functionality of USB device mode, * which includes initialization of MSS USB in device mode, USB standard request * handling, distribution of requests to specific class, interface or endpoints. * */ #include "mss_clint.h" #include "mss_usb_device.h" #include "mss_usb_config.h" #include "mss_usb_common_cif.h" #include "mss_usb_device_cif.h" #include "mss_usb_std_def.h" #include "mss_plic.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_DEVICE_ENABLED #define SETUP_PKT_INIT(); g_setup_pkt.request_type = 0;\ g_setup_pkt.request = 0;\ g_setup_pkt.value = 0;\ g_setup_pkt.index = 0;\ g_setup_pkt.length = 0; /***************************************************************************//** Global variables used within this file. */ /* This structure must be implemented by user application */ mss_usbd_user_descr_cb_t *g_usbd_user_descr_cb; /* This structure must be implemented by USBD-Class driver*/ mss_usbd_class_cb_t *g_usbd_class_cb; /* USB current Speed of operation selected by user*/ static mss_usb_device_speed_t g_usbd_user_speed; /*Status information for SET_FEATURE,GET_FEATURE requests.*/ static uint16_t g_usbd_status; /*Device configuration information*/ static mss_usbd_dev_conf_t g_usbd_dev_conf; /*This structure is used to hold the setup packet received on control endpoint*/ static mss_usbd_setup_pkt_t g_setup_pkt; /*Structure representing each endpoint on MSS USB*/ static mss_usb_ep_t gd_tx_ep[5u]; /*idx = 0: Control Endpoint*/ static mss_usb_ep_t gd_rx_ep[5u]; /* This structure should be implemented for bare testing of the USB transfers, when in the test mode, no other class specific components or enumeration related APIs are called. This mode is only provided for internal customers for testing purpose. */ #ifdef MSS_USB_DEVICE_TEST_MODE extern mss_usbd_user_test_cb_t usbd_test_cb; #endif /***************************************************************************//** Private function declarations for this file (USBD Driver). */ static void mss_usbd_ep_rx_cb(mss_usb_ep_num_t ep_num, uint8_t status); static void mss_usbd_ep_tx_complete_cb(mss_usb_ep_num_t num, uint8_t status); static void mss_usbd_cep_setup_cb(uint8_t status); static void mss_usbd_cep_rx_cb(uint8_t status); static void mss_usbd_cep_tx_complete_cb(uint8_t status); static void mss_usbd_reset_cb(void); static void mss_usbd_sof_cb(uint8_t status); static void mss_usbd_suspend_cb(void); static void mss_usbd_resume_cb(void); static void mss_usbd_disconnect_cb(void); static void mss_usbd_dma_handler_cb(mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val); static uint8_t mss_usbd_class_requests(uint8_t** buf_pp, uint32_t* len_p); static uint8_t mss_usbd_vendor_requests(uint8_t** buf_pp, uint32_t* len_p); static uint8_t mss_usbd_get_descriptor(uint8_t** buf_pp, uint32_t* len_p); static uint8_t mss_usbd_set_address(void); static uint8_t mss_usbd_set_config(void); static uint8_t mss_usbd_get_config(uint8_t** buf_pp, uint32_t* len_p); static uint8_t mss_usbd_get_status(uint8_t** buf_pp, uint32_t* len_p); static uint8_t mss_usbd_set_feature(void); static uint8_t mss_usbd_clr_feature(void); static uint8_t mss_usbd_set_descriptor(void); static uint8_t mss_usbd_std_requests(uint8_t** buf,uint32_t* length); /* This structure implements the callback functions which will be called by the USBD-CIFL layer. */ mss_usbd_cb_t g_mss_usbd_cb = { mss_usbd_ep_rx_cb, mss_usbd_ep_tx_complete_cb, mss_usbd_cep_setup_cb, mss_usbd_cep_rx_cb, mss_usbd_cep_tx_complete_cb, mss_usbd_sof_cb, mss_usbd_reset_cb, mss_usbd_suspend_cb, mss_usbd_resume_cb, mss_usbd_disconnect_cb, mss_usbd_dma_handler_cb }; /***************************************************************************//** Exported functions from this file (USBD Driver) */ /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_init ( mss_usb_device_speed_t speed ) { g_usbd_dev_conf.device_addr = 0x00u; g_usbd_dev_conf.device_total_interfaces = 0x00u; g_usbd_dev_conf.device_total_ep = 0x00u; g_usbd_dev_conf.device_state = MSS_USB_NOT_ATTACHED_STATE; /*store this for usage with DevQual, OtherSpeed requests*/ g_usbd_user_speed = speed; g_usbd_dev_conf.device_speed = speed; gd_tx_ep[MSS_USB_CEP].state = MSS_USB_CEP_IDLE; MSS_USBD_CIF_init(g_usbd_dev_conf.device_speed); MSS_USBD_CIF_dev_connect(); g_usbd_dev_conf.device_state = MSS_USB_POWERED_STATE; } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_set_descr_cb_handler ( mss_usbd_user_descr_cb_t* user_desc_cb ) { g_usbd_user_descr_cb = user_desc_cb; } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_set_class_cb_handler ( mss_usbd_class_cb_t* class_cb ) { g_usbd_class_cb = class_cb; } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_stall ( mss_usb_ep_num_t ep_num ) { gd_tx_ep[ep_num].stall = 1u; MSS_USBD_CIF_tx_ep_stall(ep_num); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_clr_stall ( mss_usb_ep_num_t ep_num ) { MSS_USBD_CIF_tx_ep_clr_stall(ep_num); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_flush_fifo ( mss_usb_ep_num_t ep_num ) { MSS_USB_CIF_tx_ep_flush_fifo(ep_num); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_stall ( mss_usb_ep_num_t ep_num ) { gd_rx_ep[ep_num].stall = 1u; MSS_USBD_CIF_rx_ep_stall(ep_num); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_clr_stall ( mss_usb_ep_num_t ep_num ) { MSS_USBD_CIF_rx_ep_clr_stall(ep_num); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_flush_fifo ( mss_usb_ep_num_t ep_num ) { MSS_USB_CIF_rx_ep_flush_fifo(ep_num); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_cep_flush_fifo ( void ) { MSS_USB_CIF_cep_flush_fifo(); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_cep_configure ( uint8_t max_pkt_size ) { mss_usb_ep_t* cep_ptr = &gd_tx_ep[MSS_USB_CEP]; cep_ptr->num = MSS_USB_CEP; cep_ptr->stall = 0u; cep_ptr->state = MSS_USB_CEP_IDLE; cep_ptr->xfr_type = MSS_USB_XFR_CONTROL; /*FIFO address */ cep_ptr->buf_addr = 0u; cep_ptr->max_pkt_size = max_pkt_size; cep_ptr->txn_length = SETUP_PKT_SIZE; MSS_USBD_CIF_cep_configure(); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_cep_read_prepare ( uint8_t * addr, uint32_t length ) { mss_usb_ep_t* cep_ptr = &gd_tx_ep[MSS_USB_CEP]; cep_ptr->buf_addr = addr; cep_ptr->xfr_length = length; cep_ptr->xfr_count = 0u; cep_ptr->txn_count = 0u; if(cep_ptr->xfr_length > cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = length; } MSS_USBD_CIF_cep_rx_prepare(&gd_tx_ep[MSS_USB_CEP]); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_cep_write ( uint8_t * addr, uint32_t length ) { mss_usb_ep_t* cep_ptr = &gd_tx_ep[MSS_USB_CEP]; cep_ptr->buf_addr = addr; cep_ptr->xfr_length = length; cep_ptr->xfr_count = 0u; cep_ptr->txn_count = 0u; if(cep_ptr->xfr_length > cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = length; } MSS_USBD_CIF_cep_write_pkt(&gd_tx_ep[MSS_USB_CEP]); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_configure ( mss_usb_ep_num_t ep_num, uint16_t fifo_addr, uint16_t fifo_size, /*This is actual size of FIFO independent of DPB*/ uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp ) { uint8_t err_check = USB_SUCCESS; uint16_t std_max_pkt_sz = USB_HS_BULK_MAX_PKT_SIZE; mss_usb_ep_t* txep_ptr = &gd_tx_ep[ep_num]; if(MSS_USB_DEVICE_HS == g_usbd_dev_conf.device_speed) { switch(xfr_type) { case MSS_USB_XFR_BULK: std_max_pkt_sz = USB_HS_BULK_MAX_PKT_SIZE; break; case MSS_USB_XFR_INTERRUPT: std_max_pkt_sz = USB_HS_INTERRUPT_MAX_PKT_SIZE; break; case MSS_USB_XFR_ISO: std_max_pkt_sz = USB_HS_ISO_MAX_PKT_SIZE; break; default: err_check = USB_FAIL; } } else if(MSS_USB_DEVICE_FS == g_usbd_dev_conf.device_speed) { switch(xfr_type) { case MSS_USB_XFR_BULK: std_max_pkt_sz = USB_FS_BULK_MAX_PKT_SIZE; break; case MSS_USB_XFR_INTERRUPT: std_max_pkt_sz = USB_FS_INTERRUPT_MAX_PKT_SIZE; break; case MSS_USB_XFR_ISO: std_max_pkt_sz = USB_FS_ISO_MAX_PKT_SIZE; break; default: err_check = USB_FAIL; } } if(max_pkt_size > std_max_pkt_sz) { err_check = USB_FAIL; } if(fifo_size < max_pkt_size) { err_check = USB_FAIL; } ASSERT(err_check == USB_SUCCESS); if(USB_SUCCESS == err_check) { if((max_pkt_size * 2) <= fifo_size) { txep_ptr->dpb_enable = DPB_ENABLE; } else { txep_ptr->dpb_enable = DPB_DISABLE; } txep_ptr->num = ep_num; txep_ptr->fifo_addr = fifo_addr; txep_ptr->fifo_size = fifo_size; txep_ptr->max_pkt_size = max_pkt_size; txep_ptr->num_usb_pkt = num_usb_pkt; txep_ptr->dma_enable = dma_enable; txep_ptr->dma_channel = dma_channel; txep_ptr->stall = 0u; txep_ptr->state = MSS_USB_EP_VALID; txep_ptr->xfr_type = xfr_type; txep_ptr->buf_addr = 0u; txep_ptr->add_zlp = add_zlp; MSS_USBD_CIF_tx_ep_configure(txep_ptr); } } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_configure ( mss_usb_ep_num_t ep_num, uint16_t fifo_addr, uint16_t fifo_size, /*This is actual size of FIFO independent of DPB*/ uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp ) { uint8_t err_check = USB_SUCCESS; uint16_t std_max_pkt_sz = USB_HS_BULK_MAX_PKT_SIZE; mss_usb_ep_t* rxep_ptr = &gd_rx_ep[ep_num]; if(MSS_USB_DEVICE_HS == g_usbd_dev_conf.device_speed) { switch(xfr_type) { case MSS_USB_XFR_BULK: std_max_pkt_sz = USB_HS_BULK_MAX_PKT_SIZE; break; case MSS_USB_XFR_INTERRUPT: std_max_pkt_sz = USB_HS_INTERRUPT_MAX_PKT_SIZE; break; case MSS_USB_XFR_ISO: std_max_pkt_sz = USB_HS_ISO_MAX_PKT_SIZE; break; default: err_check = USB_FAIL; } } else if(MSS_USB_DEVICE_FS == g_usbd_dev_conf.device_speed) { switch(xfr_type) { case MSS_USB_XFR_BULK: std_max_pkt_sz = USB_FS_BULK_MAX_PKT_SIZE; break; case MSS_USB_XFR_INTERRUPT: std_max_pkt_sz = USB_FS_INTERRUPT_MAX_PKT_SIZE; break; case MSS_USB_XFR_ISO: std_max_pkt_sz = USB_FS_ISO_MAX_PKT_SIZE; break; default: err_check = USB_FAIL; } } if(max_pkt_size > std_max_pkt_sz) { err_check = USB_FAIL; } if(fifo_size < max_pkt_size) { err_check = USB_FAIL; } ASSERT(err_check == USB_SUCCESS); if(USB_SUCCESS == err_check) { if((max_pkt_size * 2u ) <= fifo_size) { rxep_ptr->dpb_enable = DPB_ENABLE; } else { rxep_ptr->dpb_enable = DPB_DISABLE; } rxep_ptr->num = ep_num; rxep_ptr->fifo_addr = fifo_addr; rxep_ptr->fifo_size = fifo_size; rxep_ptr->max_pkt_size = max_pkt_size; rxep_ptr->num_usb_pkt = num_usb_pkt; rxep_ptr->dma_enable = dma_enable; rxep_ptr->dma_channel = dma_channel; rxep_ptr->stall = 0u; rxep_ptr->state = MSS_USB_EP_VALID; rxep_ptr->xfr_type = xfr_type; rxep_ptr->buf_addr = 0u; rxep_ptr->add_zlp = add_zlp; MSS_USBD_CIF_rx_ep_configure(rxep_ptr); } } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_read_prepare ( mss_usb_ep_num_t ep_num, uint8_t * addr, uint32_t length ) { mss_usb_ep_t* rxep_ptr = &gd_rx_ep[ep_num]; ASSERT(ep_num); ASSERT(addr != 0); rxep_ptr->buf_addr = addr; rxep_ptr->xfr_length = length; rxep_ptr->xfr_count = 0u; rxep_ptr->txn_count = 0u; /*HAL_ASSERT when length is 0, address is null or ep number is wrong*/ if(length > 0u) { /* TODO: While using DMA, RxMaxP payload value MUST be an even number when dealing with Multi packet Bulk transaction for proper interrupt generation. This needs to be taken care. */ /* section 8.4.2.3 -- No support for HB in Interrupt transfers. i.e. maximum one packet(num_usb_pkt=1)can be transferred in one frame. */ if(length >= rxep_ptr->max_pkt_size) { rxep_ptr->txn_length = rxep_ptr->max_pkt_size; } else { rxep_ptr->txn_length = length; } } MSS_USB_CIF_rx_ep_read_prepare(rxep_ptr->num, rxep_ptr->buf_addr, rxep_ptr->dma_enable, rxep_ptr->dma_channel, rxep_ptr->xfr_type, rxep_ptr->xfr_length); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_write ( mss_usb_ep_num_t ep_num, uint8_t * addr, uint32_t length ) { uint8_t dpb = 1u; mss_usb_ep_t* txep_ptr = &gd_tx_ep[ep_num]; /* HAL_ASSERT if uneven value for BULK transfers */ ASSERT(ep_num); ASSERT(addr != 0); if((ep_num) && (addr != 0)) { if(DPB_ENABLE == txep_ptr->dpb_enable) { dpb = 2u; } txep_ptr->num = ep_num; txep_ptr->buf_addr = addr; txep_ptr->xfr_length = length; txep_ptr->xfr_count = 0u; txep_ptr->txn_count = 0u; if(MSS_USB_XFR_BULK == txep_ptr->xfr_type) { /* TODO: TxMaxP payload value MUST be an even number when dealing with Multi packet Bulk transaction for proper interrupt generation. This needs to be taken care. */ if(length <= txep_ptr->fifo_size) { txep_ptr->txn_length = length; } else { txep_ptr->txn_length= txep_ptr->fifo_size; } } /* section 8.4.2.3 -- No support for HB in Interrupt transfers. i.e. maximum one packet(num_usb_pkt=1)can be transferred in one frame. */ else if(MSS_USB_XFR_INTERRUPT == txep_ptr->xfr_type) { if(length >= (txep_ptr->max_pkt_size * dpb)) { txep_ptr->txn_length = (txep_ptr->max_pkt_size * dpb); } else { txep_ptr->txn_length = length; } } else if(MSS_USB_XFR_ISO == txep_ptr->xfr_type) { if(length >= (txep_ptr->max_pkt_size * dpb)) { txep_ptr->txn_length = (txep_ptr->max_pkt_size * dpb); } else { txep_ptr->txn_length = length; } } MSS_USB_CIF_ep_write_pkt(txep_ptr->num, txep_ptr->buf_addr, txep_ptr->dma_enable, txep_ptr->dma_channel, txep_ptr->xfr_type, txep_ptr->xfr_length, txep_ptr->txn_length); } } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_get_hwcore_info ( mss_usb_core_info_t* hw_info ) { MSS_USBD_CIF_get_hwcore_info(hw_info); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ uint8_t MSS_USBD_get_dev_address ( void ) { return(MSS_USBD_CIF_get_dev_addr()); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_set_isoupdate ( void ) { MSS_USBD_CIF_set_isoupdate(); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_clr_isoupdate ( void ) { MSS_USBD_CIF_clr_isoupdate(); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ uint8_t MSS_USBD_tx_ep_is_fifo_notempty ( mss_usb_ep_num_t epnum ) { return(MSS_USB_CIF_is_txepfifo_notempty(epnum)); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ uint8_t MSS_USBD_rx_ep_is_fifo_full ( mss_usb_ep_num_t epnum ) { return(MSS_USB_CIF_rx_ep_is_fifo_full(epnum)); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_disable_irq ( mss_usb_ep_num_t epnum ) { MSS_USB_CIF_tx_ep_disable_irq(epnum); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_disable_irq ( mss_usb_ep_num_t epnum ) { MSS_USB_CIF_rx_ep_disable_irq(epnum); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_tx_ep_enable_irq ( mss_usb_ep_num_t epnum ) { MSS_USB_CIF_tx_ep_enable_irq(epnum); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_rx_ep_enable_irq ( mss_usb_ep_num_t epnum ) { MSS_USB_CIF_rx_ep_enable_irq(epnum); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_cep_enable_irq ( void ) { MSS_USB_CIF_cep_enable_irq(); } /***************************************************************************//** See mss_usb_device.h for details of how to use this function. */ void MSS_USBD_cep_disable_irq ( void ) { MSS_USB_CIF_cep_disable_irq(); } /***************************************************************************//** Private functions to this file (USBD Driver) */ /***************************************************************************//** This call-back function is executed on receiving SOF interrupt in Device mode. */ static void mss_usbd_sof_cb ( uint8_t status ) { #ifndef MSS_USB_DEVICE_TEST_MODE #else usbd_test_cb.test_sof(status); #endif } /****************************************************************************** This Callback function is executed when reset interrupt is received when the MSS USB is in device mode. */ static void mss_usbd_reset_cb ( void ) { #ifndef MSS_USB_DEVICE_TEST_MODE g_usbd_dev_conf.device_addr = 0x00u; g_usbd_dev_conf.device_total_interfaces = 0x00u; g_usbd_dev_conf.device_total_ep = 0x00u; g_usbd_dev_conf.device_state = MSS_USB_DEFAULT_STATE; gd_tx_ep[MSS_USB_CEP].state = MSS_USB_CEP_IDLE; g_usbd_dev_conf.remote_wakeup = 0x00u; if(MSS_USBD_CIF_is_hs_mode()) { g_usbd_dev_conf.device_speed = MSS_USB_DEVICE_HS; } else { g_usbd_dev_conf.device_speed = MSS_USB_DEVICE_FS; } SETUP_PKT_INIT(); MSS_USBD_cep_configure(64u); MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); #else usbd_test_cb.test_reset(); #endif } /******************************************************************************* This Callback function is executed when Setup packet is received on Control EP */ static void mss_usbd_cep_setup_cb ( uint8_t status ) { #ifndef MSS_USB_DEVICE_TEST_MODE uint8_t* buf = 0; uint32_t length = 0u; uint8_t result = USB_FAIL; mss_usb_ep_t* cep_ptr = &gd_tx_ep[MSS_USB_CEP]; if(status & (CTRL_EP_SETUP_END_ERROR | CTRL_EP_STALL_ERROR)) { /* EP0 was previously stalled, clear the error condition and prepare for next transaction */ cep_ptr->state = MSS_USB_CEP_IDLE; SETUP_PKT_INIT(); MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); } else { MSS_USBD_CIF_cep_read_pkt(cep_ptr); if(SETUP_PKT_SIZE == cep_ptr->txn_length) { cep_ptr->state = MSS_USB_CEP_SETUP; if(USB_STANDARD_REQUEST == (g_setup_pkt.request_type & USB_STD_REQ_TYPE_MASK)) { result = mss_usbd_std_requests(&buf, &length); } else if(USB_CLASS_REQUEST == (g_setup_pkt.request_type & USB_STD_REQ_TYPE_MASK)) { result = mss_usbd_class_requests(&buf, &length); } else if(USB_VENDOR_REQUEST == (g_setup_pkt.request_type & USB_STD_REQ_TYPE_MASK)) { result = mss_usbd_vendor_requests(&buf, &length); } } else { ASSERT(0);/*in this transaction the txn_length must be SETUP_PKT_SIZE*/ } if(result) //USB_SUCCESS { MSS_USBD_CIF_reset_index_reg(); if(0u == g_setup_pkt.length) { volatile uint32_t delay = 0; MSS_USBD_CIF_cep_end_zdr(); //zdl complete cep_ptr->state = MSS_USB_CEP_IDLE; if(USB_STD_REQ_SET_ADDRESS == g_setup_pkt.request) { //special case SetAddress Request for(delay = 0; delay < 5000 ; delay ++) { asm volatile(""); } MSS_USBD_CIF_set_dev_addr(g_usbd_dev_conf.device_addr); } if((USB_STD_REQ_SET_FEATURE == g_setup_pkt.request) && (USB_STD_FEATURE_TEST_MODE == g_setup_pkt.value)) { //let the current request status phase complete. for(delay = 0; delay < 5000 ; delay ++) { asm volatile(""); } switch(g_setup_pkt.index >> USB_WINDEX_HIBITE_SHIFT) { case USB_TEST_MODE_SELECTOR_TEST_J: MSS_USB_CIF_start_testj(); break; case USB_TEST_MODE_SELECTOR_TEST_K: MSS_USB_CIF_start_testk(); break; case USB_TEST_MODE_SELECTOR_TEST_SE0NAK: MSS_USB_CIF_start_testse0nak(); break; case USB_TEST_MODE_SELECTOR_TEST_PACKET: MSS_USB_CIF_start_testpacket(); break; default: break; } } else { SETUP_PKT_INIT(); MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); } } else { //end of setup phase for Read/Write Req MSS_USBD_CIF_cep_clr_rxpktrdy(); if((g_setup_pkt.request_type & USB_STD_REQ_DATA_DIR_MASK)) { cep_ptr->state = MSS_USB_CEP_TX; if((uint8_t*)0 == buf) { ASSERT(0); } if(length > g_setup_pkt.length) { length = g_setup_pkt.length; } MSS_USBD_cep_write(buf,length); } else { cep_ptr->state = MSS_USB_CEP_RX; MSS_USBD_cep_read_prepare(buf,length); } } } else { cep_ptr->state = MSS_USB_CEP_IDLE; SETUP_PKT_INIT(); /*both servicedrxpktrdy and Sendstall should be set in setup phase*/ MSS_USBD_CIF_cep_stall(); } } #else /*MSS_USB_DEVICE_TEST_MODE*/ usbd_test_cb.test_cep_setup(status); #endif } /******************************************************************************* This Callback function is called when Data packet is received on Control EP. DATAOUT Phase. */ static void mss_usbd_cep_rx_cb ( uint8_t status ) { #ifndef MSS_USB_DEVICE_TEST_MODE uint32_t rem_length; mss_usb_ep_t* cep_ptr = &gd_tx_ep[MSS_USB_CEP]; /* xfr_rem_length should have been setup by the Specific request which needed data to arrive in the Data phase */ if(status & (CTRL_EP_SETUP_END_ERROR | CTRL_EP_STALL_ERROR)) { SETUP_PKT_INIT(); if(0 != g_usbd_class_cb->usbd_class_cep_rx_done) { g_usbd_class_cb->usbd_class_cep_rx_done(status); } cep_ptr->state = MSS_USB_CEP_IDLE; MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); } else { MSS_USBD_CIF_cep_read_pkt(cep_ptr); if(MSS_USB_CEP_RX == cep_ptr->state) { if(cep_ptr->xfr_count == cep_ptr->xfr_length) { /*Call USBD-Class indicating that the desired data is arrived*/ if(0 != g_usbd_class_cb->usbd_class_cep_rx_done) { g_usbd_class_cb->usbd_class_cep_rx_done(status); } MSS_USBD_CIF_reset_index_reg(); SETUP_PKT_INIT(); cep_ptr->state = MSS_USB_CEP_IDLE; MSS_USBD_CIF_cep_end_wdr(); //WriteReq complete MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); } else if(cep_ptr->xfr_count < cep_ptr->xfr_length) { MSS_USBD_CIF_cep_clr_rxpktrdy(); //get more data from host /*Continue to read data on the CEP*/ rem_length = cep_ptr->xfr_length - cep_ptr->xfr_count; if(rem_length >= cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = rem_length; } cep_ptr->txn_count = 0u; MSS_USBD_cep_read_prepare((cep_ptr->buf_addr+cep_ptr->xfr_count), cep_ptr->txn_length); } else { SETUP_PKT_INIT(); cep_ptr->state = MSS_USB_CEP_IDLE; MSS_USBD_CIF_cep_stall(); //Send stall } } else { /*at this stage CEP stage must not be other than MSS_USB_CEP_RX*/ ASSERT(0); } } #else /*MSS_USB_DEVICE_TEST_MODE*/ usbd_test_cb.test_cep_rx(status); #endif } /******************************************************************************* This Callback function is executed when Data packet is sent from control EP. DATAIN phase. */ static void mss_usbd_cep_tx_complete_cb ( uint8_t status ) { #ifndef MSS_USB_DEVICE_TEST_MODE mss_usb_ep_t* cep_ptr = &gd_tx_ep[MSS_USB_CEP]; /* xfr_rem_length should have been setup by the Specific request which needed data to arrive in the Data phase */ if(status & (CTRL_EP_SETUP_END_ERROR | CTRL_EP_STALL_ERROR)) { SETUP_PKT_INIT(); if(0 != g_usbd_class_cb->usbd_class_cep_tx_done) { g_usbd_class_cb->usbd_class_cep_tx_done(status); } cep_ptr->state = MSS_USB_CEP_IDLE; MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); } else { /*Device should be in DATAIN phase.*/ if(MSS_USB_CEP_TX == cep_ptr->state) { if(cep_ptr->xfr_count < cep_ptr->xfr_length) { /*Continue to transmit more data*/ cep_ptr->buf_addr += cep_ptr->txn_count; if((cep_ptr->xfr_length - cep_ptr->xfr_count) >= cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = (cep_ptr->xfr_length - cep_ptr->xfr_count); } /* Reset the txn_count since one transaction out of the transfer is completed now */ cep_ptr->txn_count = 0u; MSS_USBD_CIF_cep_write_pkt(cep_ptr); } else { /*Call USBD-Class indicating that the desired data is sent*/ if(0 != g_usbd_class_cb->usbd_class_cep_tx_done) { g_usbd_class_cb->usbd_class_cep_tx_done(status); } cep_ptr->txn_count = 0u; cep_ptr->xfr_count = 0u; cep_ptr->xfr_length = 0u; cep_ptr->txn_length = 0u; cep_ptr->state = MSS_USB_CEP_IDLE; SETUP_PKT_INIT(); MSS_USBD_CIF_reset_index_reg(); MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, USB_SETUP_PKT_LEN); } } } #else /*MSS_USB_DEVICE_TEST_MODE*/ usbd_test_cb.test_cep_tx_complete(status); #endif } /******************************************************************************* This Call-back function is executed when Data packet is received on RX EP */ static void mss_usbd_ep_rx_cb ( mss_usb_ep_num_t ep_num, uint8_t status ) { uint8_t transfer_complete = 0u; mss_usb_ep_t* rxep_ptr = &gd_rx_ep[ep_num]; uint32_t received_count = 0u; /* While receiving data, xfr_length might be known to application or unknown. When xfr_length is not known, application is expected to provide size of(Receive_buffer) as xfr_length which is big enough to receive unknown data. End of data reception in this case is flagged by reception of short packet or ZLP(when xfr_length = n*maxpktsz). When xfr_length is known(via transport protocol), end of data reception is concluded when xfr_count = xfr_length. No zlp is expected to be received for the case of xfr_length = n*maxpktsz. When DMA-m1 is enabled, the control will return here only once after completion of transfer. */ if(status & (RX_EP_OVER_RUN_ERROR | RX_EP_STALL_ERROR | RX_EP_DATA_ERROR | RX_EP_PID_ERROR | RX_EP_ISO_INCOMP_ERROR)) { transfer_complete = 1; } else { if(MSS_USB_CIF_rx_ep_is_rxpktrdy(ep_num)) { uint32_t increamented_addr; received_count = (uint32_t)MSS_USB_CIF_rx_ep_read_count(ep_num); if(DMA_ENABLE == rxep_ptr->dma_enable) { if(MSS_USB_DMA_MODE1 == (MSS_USB_CIF_rx_ep_get_dma_mode(ep_num))) { /* This means we are in BULK transfer with DMA mode1.... all the rxmaxP size pkts are received and last short pkt need to be read without DMA or by switching to mode 0. After switching mode to 0, this ISR handler is invoked again. Data packet will be read then. MUSB: section 16 */ /*read 'short packet' without DMA*/ MSS_USB_CIF_dma_stop_xfr(rxep_ptr->dma_channel); MSS_USB_CIF_rx_ep_clr_autoclr(ep_num); /*Count number of bytes read so far,since DMA was operating in m1 with Autoclr.*/ increamented_addr = MSS_USB_CIF_dma_read_addr(rxep_ptr->dma_channel); rxep_ptr->xfr_count = (increamented_addr - (ptrdiff_t)(rxep_ptr->buf_addr)); if(received_count) { MSS_USB_CIF_read_rx_fifo(ep_num, (rxep_ptr->buf_addr+rxep_ptr->xfr_count), received_count); rxep_ptr->xfr_count += received_count; } transfer_complete = 1; } else { MSS_USB_CIF_dma_write_count(rxep_ptr->dma_channel, received_count); MSS_USB_CIF_dma_start_xfr(rxep_ptr->dma_channel); transfer_complete = 2u; /*Upper layer cb will be called from DMA ISR*/ } } else // no dma { if(received_count) { MSS_USB_CIF_read_rx_fifo(ep_num, (rxep_ptr->buf_addr+rxep_ptr->xfr_count), received_count); rxep_ptr->txn_count = received_count; rxep_ptr->xfr_count += received_count; } if(MSS_USB_XFR_BULK == rxep_ptr->xfr_type) { if(ADD_ZLP_TO_XFR == rxep_ptr->add_zlp) { if(rxep_ptr->xfr_count < rxep_ptr->xfr_length) { if(rxep_ptr->txn_count < rxep_ptr->max_pkt_size) { transfer_complete = 1; } else { /*receive short pkt.zlp when xfr_length is multiple of wMaxPktsz*/ transfer_complete = 0; } } else if(rxep_ptr->xfr_count == rxep_ptr->xfr_length) { /*buffer is full*/ transfer_complete = 1; } else { /*If xfr_count is more than xfr_lenght then something has seriously gone bad.*/ ASSERT(0); } } else // no zlp { if(rxep_ptr->xfr_count == rxep_ptr->xfr_length) { transfer_complete = 1; } else if(rxep_ptr->xfr_count < rxep_ptr->xfr_length) { transfer_complete = 0; } else { /*If xfr_count is more than xfr_lenght then something has seriously gone bad.*/ ASSERT(0); } } } else { /* For ISO and interrupt transfers, LB-expects only one packet in one transaction HB expects at most 3 packets in one transaction */ if(rxep_ptr->txn_count <= rxep_ptr->max_pkt_size) { transfer_complete = 1; } else { ASSERT(0);/*TODO: replace this with stall EP*/ } } } MSS_USB_CIF_rx_ep_clr_rxpktrdy(ep_num); } } if(transfer_complete == 0) { ASSERT(rxep_ptr->xfr_length >= rxep_ptr->xfr_count); if((rxep_ptr->xfr_length - rxep_ptr->xfr_count) >= rxep_ptr->max_pkt_size) { rxep_ptr->txn_length = rxep_ptr->max_pkt_size; } else { rxep_ptr->txn_length = (rxep_ptr->xfr_length - rxep_ptr->xfr_count); } /* Reset the txn_count since one transaction out of the transfer is completed. */ rxep_ptr->txn_count = 0u; MSS_USB_CIF_rx_ep_read_prepare(rxep_ptr->num, (rxep_ptr->buf_addr + rxep_ptr->xfr_count), rxep_ptr->dma_enable, rxep_ptr->dma_channel, rxep_ptr->xfr_type, rxep_ptr->xfr_length); } else if(transfer_complete == 1) { #ifndef MSS_USB_DEVICE_TEST_MODE if(0 != g_usbd_class_cb->usbd_class_rx_done) { g_usbd_class_cb->usbd_class_rx_done(ep_num, status, rxep_ptr->xfr_count); } #else usbd_test_cb.test_ep_rx(ep_num, status, rxep_ptr->xfr_count); #endif } else { /*Do Nothing. DMA m0 will be handled in DMA_Handler*/ } } /****************************************************************************** This Callback function is executed on transmission complete interrupt event when the MSS USB is in device mode. */ static void mss_usbd_ep_tx_complete_cb ( mss_usb_ep_num_t num, uint8_t status ) { uint8_t transfer_complete = 0u; uint32_t increamented_addr = 0u; mss_usb_ep_t* txep_ptr = &gd_tx_ep[num]; if(status & TX_EP_STALL_ERROR) { transfer_complete = 1u; } else { /* While transmitting data we always know the xfr_length, use it to check if the transfer has ended. DMA Enabled: Mode-m1 is used for Bulk transfer.In this case all the data single or multiple packets is handled by DMA since Autoset bit is set. Control will return here only once when complete data is transmitted. Mode-m0 is used for ISO/Interrupt transfers. In this case single packet should have been given by the application and control will return here only once after the single packet is transmitted. DMA Disabled: For multi-packet bulk transfers, control will reach here after every single packet is transferred. Provide next packet for transmission till the end of data. */ if(DMA_ENABLE == txep_ptr->dma_enable) { increamented_addr = MSS_USB_CIF_dma_read_addr(txep_ptr->dma_channel); txep_ptr->xfr_count = increamented_addr - ((ptrdiff_t)txep_ptr->buf_addr); ASSERT(txep_ptr->xfr_count == txep_ptr->xfr_length); /*TODO: Move the decision to transmit ZLP from CIFL to here*/ transfer_complete = 1u; } else /*DMA_DISABLE*/ { txep_ptr->txn_count = txep_ptr->txn_length; txep_ptr->xfr_count += txep_ptr->txn_length; if(MSS_USB_XFR_BULK == txep_ptr->xfr_type) { if(txep_ptr->xfr_count < txep_ptr->xfr_length) { transfer_complete = 0u; } else if(txep_ptr->xfr_count == txep_ptr->xfr_length) { if(ADD_ZLP_TO_XFR == txep_ptr->add_zlp) { if(0u == txep_ptr->txn_count) { transfer_complete = 1u; } else { if(txep_ptr->txn_count == txep_ptr->max_pkt_size) { transfer_complete = 0u; } else if(txep_ptr->txn_count < txep_ptr->max_pkt_size) { transfer_complete = 1u; } } } else //no zlp { transfer_complete = 1u; } } else { /*If xfr_count is more than xfr_lenght then something has seriously gone bad.*/ ASSERT(0); } } else /*ISO/INTERRUPT XRF*/ { if(txep_ptr->txn_count != txep_ptr->txn_length) { /*The ISO/Interrupt every transfer must be single transaction*/ ASSERT(0); } transfer_complete = 1u; } } } if(1u == transfer_complete) { #ifndef MSS_USB_DEVICE_TEST_MODE if(0 != g_usbd_class_cb->usbd_class_tx_done) { g_usbd_class_cb->usbd_class_tx_done(num, status); } #else /*MSS_USB_DEVICE_TEST_MODE*/ usbd_test_cb.test_ep_tx_complete(num, status); #endif } else { /* Reset the txn_count since one transaction out of the transfer is completed now */ txep_ptr->txn_count = 0u; ASSERT(txep_ptr->xfr_length >= txep_ptr->xfr_count); if((txep_ptr->xfr_length - txep_ptr->xfr_count) >= txep_ptr->max_pkt_size) { txep_ptr->txn_length = txep_ptr->max_pkt_size; } else { txep_ptr->txn_length = (txep_ptr->xfr_length - txep_ptr->xfr_count); } while(MSS_USB_CIF_is_txepfifo_notempty(txep_ptr->num)); MSS_USB_CIF_ep_write_pkt(txep_ptr->num, (txep_ptr->buf_addr + txep_ptr->xfr_count), txep_ptr->dma_enable, txep_ptr->dma_channel, txep_ptr->xfr_type, txep_ptr->xfr_length, txep_ptr->txn_length); } } /******************************************************************************* This Callback function is executed when suspend interrupt is received when the MSS USB is in device mode. */ static void mss_usbd_suspend_cb ( void ) { #ifndef MSS_USB_DEVICE_TEST_MODE MSS_USB_CIF_enable_usbirq(RESUME_IRQ_MASK); g_usbd_dev_conf.device_state_at_suspend = g_usbd_dev_conf.device_state; g_usbd_dev_conf.device_state = MSS_USB_SUSPENDED_STATE; #else /*usbd_test_cb.test_suspend();*/ #endif } /******************************************************************************* This Callback function is executed when resume interrupt is received when the MSS USB is in device mode. */ static void mss_usbd_resume_cb ( void ) { #ifndef MSS_USB_DEVICE_TEST_MODE g_usbd_dev_conf.device_state = g_usbd_dev_conf.device_state_at_suspend; #else usbd_test_cb.test_resume(); #endif } static void mss_usbd_disconnect_cb(void) { #ifndef MSS_USB_DEVICE_TEST_MODE g_usbd_dev_conf.device_state = MSS_USB_NOT_ATTACHED_STATE; MSS_USB_CIF_rx_ep_disable_irq_all(); MSS_USB_CIF_tx_ep_disable_irq_all(); PLIC_EnableIRQ(PLIC_USB_DMA_INT_OFFSET); PLIC_EnableIRQ(PLIC_USB_MC_INT_OFFSET); if(0 != g_usbd_class_cb->usbd_class_release) { g_usbd_class_cb->usbd_class_release(0xFF); } #else usbd_test_cb.test_resume(); #endif } /******************************************************************************* This function processes standard USB requests. */ static uint8_t mss_usbd_std_requests ( uint8_t** buf, uint32_t* length ) { uint8_t result = USB_FAIL; /*TODO:result should be used for all the functions*/ switch(g_setup_pkt.request) { case USB_STD_REQ_GET_DESCRIPTOR: result = mss_usbd_get_descriptor(buf, length); return result; case USB_STD_REQ_SET_ADDRESS: mss_usbd_set_address(); break; case USB_STD_REQ_SET_CONFIG: mss_usbd_set_config(); break; case USB_STD_REQ_GET_CONFIG: mss_usbd_get_config(buf, length); break; case USB_STD_REQ_GET_STATUS: mss_usbd_get_status(buf, length); break; case USB_STD_REQ_SET_FEATURE: result = mss_usbd_set_feature(); return result; case USB_STD_REQ_CLEAR_FEATURE: result = mss_usbd_clr_feature(); return result; case USB_STD_REQ_SET_DESCRIPTOR: mss_usbd_set_descriptor(); break; case USB_STD_REQ_SET_INTERFACE: g_usbd_dev_conf.active_interface_num = (uint8_t)g_setup_pkt.value; return USB_SUCCESS; case USB_STD_REQ_GET_INTERFACE: *buf = &g_usbd_dev_conf.active_interface_num; *length = 1u; return USB_SUCCESS; default: return USB_FAIL; } return USB_SUCCESS; } /******************************************************************************* This function processes USB class requests. */ static uint8_t mss_usbd_class_requests ( uint8_t** buf_pp, uint32_t* len_p ) { if((0 != g_usbd_class_cb->usbd_class_process_request)) { if(USB_SUCCESS == g_usbd_class_cb->usbd_class_process_request(&g_setup_pkt, buf_pp, len_p)) { return USB_SUCCESS; } else { return USB_FAIL; } } else { return USB_FAIL; } } /******************************************************************************* This function processes vendor defined USB requests. */ static uint8_t mss_usbd_vendor_requests ( uint8_t** buf_pp, uint32_t* len_p ) { if((0 != g_usbd_class_cb->usbd_class_process_request)) { if(USB_SUCCESS == g_usbd_class_cb->usbd_class_process_request(&g_setup_pkt, buf_pp, len_p)) { return USB_SUCCESS; } else { return USB_FAIL; } } else { return USB_FAIL; } } static uint8_t mss_usbd_get_descriptor ( uint8_t** buf_pp, uint32_t* len_p ) { if((g_usbd_dev_conf.device_state >= MSS_USB_DEFAULT_STATE) && (USB_STD_REQ_DATA_DIR_IN == (g_setup_pkt.request_type & USB_STD_REQ_DATA_DIR_MASK))) { if(USB_STD_REQ_RECIPIENT_DEVICE == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) { switch(g_setup_pkt.value >> USB_WVALUE_HIBITE_SHIFT) { case USB_DEVICE_DESCRIPTOR_TYPE: /*descriptor Index and Index field should be zero*/ if((0u == ((uint8_t)(g_setup_pkt.value))) && (0u == g_setup_pkt.index) && (0 != g_usbd_user_descr_cb->usbd_device_descriptor)) { *buf_pp = g_usbd_user_descr_cb->usbd_device_descriptor(len_p); return(USB_SUCCESS); } else { return(USB_FAIL); } case USB_STRING_DESCRIPTOR_TYPE: /* * When descriptor index is 0, index field must be 0. * When descriptor index is >0, index field indicates Lang ID */ if(0 != g_usbd_user_descr_cb->usbd_string_descriptor) { *buf_pp = g_usbd_user_descr_cb->usbd_string_descriptor ((uint8_t)g_setup_pkt.value, len_p); return(USB_SUCCESS); } else { return(USB_FAIL); } case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: if(MSS_USB_DEVICE_HS == g_usbd_user_speed) { /*descriptor Index should be zero*/ if((0 == ((uint8_t)(g_setup_pkt.value))) && (0 == g_setup_pkt.index) && (0 != g_usbd_user_descr_cb->usbd_device_qual_descriptor)) { *buf_pp = g_usbd_user_descr_cb->usbd_device_qual_descriptor (g_usbd_dev_conf.device_speed, len_p); return(USB_SUCCESS); } else { return(USB_FAIL); } } else { /*Since User operates USBD at FS, Stall this request*/ return(USB_FAIL); } case USB_CONFIGURATION_DESCRIPTOR_TYPE: if(0 != g_usbd_class_cb->usbd_class_get_descriptor) { *buf_pp = g_usbd_class_cb->usbd_class_get_descriptor (USB_STD_REQ_RECIPIENT_DEVICE, USB_CONFIGURATION_DESCRIPTOR_TYPE, len_p, g_usbd_dev_conf.device_speed); return(USB_SUCCESS); } else { return(USB_FAIL); } case USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE: if(MSS_USB_DEVICE_HS == g_usbd_user_speed) { /*descriptor Index should be zero and Index field should be zero*/ if((0u == ((uint8_t)(g_setup_pkt.value))) && (0u == g_setup_pkt.index)) { if(0 != g_usbd_class_cb->usbd_class_get_descriptor) { *buf_pp = g_usbd_class_cb->usbd_class_get_descriptor (USB_STD_REQ_RECIPIENT_DEVICE, USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE, len_p, g_usbd_dev_conf.device_speed); return(USB_SUCCESS); } else { return(USB_FAIL); } } } else { /*Since User operates USBD at FS, Stall this request*/ return(USB_FAIL); } break; default: return(USB_FAIL); } } else if(USB_STD_REQ_RECIPIENT_INTERFACE == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) { if(0 != g_usbd_class_cb->usbd_class_get_descriptor) { *buf_pp = g_usbd_class_cb->usbd_class_get_descriptor (USB_STD_REQ_RECIPIENT_INTERFACE, g_setup_pkt.value >> USB_WVALUE_HIBITE_SHIFT, len_p, g_usbd_dev_conf.device_speed); return(USB_SUCCESS); } else { return(USB_FAIL); } } else if(USB_STD_REQ_RECIPIENT_ENDPOINT == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) { if((g_setup_pkt.value >> USB_WVALUE_HIBITE_SHIFT) && (0 != g_usbd_class_cb->usbd_class_get_descriptor)) { *buf_pp = g_usbd_class_cb->usbd_class_get_descriptor (USB_STD_REQ_RECIPIENT_ENDPOINT, (g_setup_pkt.value >> USB_WVALUE_HIBITE_SHIFT), len_p, g_usbd_dev_conf.device_speed); return(USB_SUCCESS); } else { return(USB_FAIL); } } } return USB_FAIL; } /****************************************************************************** This function sets the Device address sent by host in the MSS USB register. */ static uint8_t mss_usbd_set_address ( void ) { uint8_t addr; /*USB device address is 7bit only*/ addr = (uint8_t)(g_setup_pkt.value & 0x7Fu); g_usbd_dev_conf.device_addr = addr; addr = (uint8_t)(g_setup_pkt.value & 0x7Fu); /*USB2.0 section 9.4.6*/ if(MSS_USB_CONFIGURED_STATE == g_usbd_dev_conf.device_state) { /*Behaviour not defined by USB2.0, May raise error here*/ return USB_FAIL; } else { if(MSS_USB_DEFAULT_STATE == g_usbd_dev_conf.device_state) { if(0u != addr) { g_usbd_dev_conf.device_state = MSS_USB_ADDRESS_STATE; } } else if(MSS_USB_ADDRESS_STATE == g_usbd_dev_conf.device_state) { if(0u == addr) { g_usbd_dev_conf.device_state = MSS_USB_DEFAULT_STATE; } } /*FADDR register will be updated after Status phase of this Request*/ } return USB_SUCCESS; } /****************************************************************************** This function processes SET_DESCRIPTOR request. */ static uint8_t mss_usbd_set_descriptor ( void ) { return USB_FAIL; } /****************************************************************************** This function processes SET_CONFIGURATION request. */ static uint8_t mss_usbd_set_config ( void ) { uint8_t cfgidx; cfgidx = (uint8_t)g_setup_pkt.value; /*USB2.0 section 9.4.6*/ if(MSS_USB_DEFAULT_STATE == g_usbd_dev_conf.device_state) { /*Undefined behaviour*/ return USB_FAIL; } else { /*This value will be returned in Get_config command*/ g_usbd_dev_conf.active_config_num = cfgidx; if(MSS_USB_ADDRESS_STATE == g_usbd_dev_conf.device_state) { if(cfgidx) { g_usbd_dev_conf.device_state = MSS_USB_CONFIGURED_STATE; if(0 != g_usbd_class_cb->usbd_class_init) { g_usbd_class_cb->usbd_class_init(cfgidx, g_usbd_dev_conf.device_speed); } } } else if(MSS_USB_CONFIGURED_STATE == g_usbd_dev_conf.device_state) { if(0 == cfgidx) { g_usbd_dev_conf.device_state = MSS_USB_ADDRESS_STATE; if(0 != g_usbd_class_cb->usbd_class_release) { g_usbd_class_cb->usbd_class_release(cfgidx); } } else { if(0 != g_usbd_class_cb->usbd_class_init) { g_usbd_class_cb->usbd_class_init(cfgidx, g_usbd_dev_conf.device_speed); } } } } return USB_SUCCESS; } /****************************************************************************** This function processes GET_CONFIGURATION requests */ static uint8_t mss_usbd_get_config ( uint8_t** buf_pp, uint32_t* len_p ) { /*The field value and index must be 0 and length must be 1*/ if((0u == g_setup_pkt.value) && (0u == g_setup_pkt.index) && (1u == g_setup_pkt.length)) { /*This value was set in Set_config command*/ *buf_pp = &g_usbd_dev_conf.active_config_num ; *len_p = 1u; return USB_SUCCESS; } else { return USB_FAIL; } } /****************************************************************************** This function processes GET_STATUS request. */ static uint8_t mss_usbd_get_status ( uint8_t** buf_pp, uint32_t* len_p ) { if(MSS_USB_ADDRESS_STATE == g_usbd_dev_conf.device_state) { /*The field value and index must be 0 and length must be 2*/ if((0u == g_setup_pkt.value) && (0u == g_setup_pkt.index) && (2u == g_setup_pkt.length)) { switch (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK) { case USB_STD_REQ_RECIPIENT_DEVICE: /*SF2 device is always self powered. RemoteWakeup NotSupported*/ g_usbd_status = 0x0001; *buf_pp = (uint8_t*)&g_usbd_status; break; case USB_STD_REQ_RECIPIENT_INTERFACE: /*Reserved by USB2.0*/ g_usbd_status = 0x0000u; *buf_pp = (uint8_t*)&g_usbd_status; break; case USB_STD_REQ_RECIPIENT_ENDPOINT:/*Endpoint halt (stall) status*/ g_usbd_status = ((gd_tx_ep[g_setup_pkt.index].stall) ? 0x0001:0x0000); *buf_pp = (uint8_t*)&g_usbd_status; break; default: return USB_FAIL; } * len_p = sizeof(g_usbd_status); } else { return USB_FAIL; } } else if(MSS_USB_CONFIGURED_STATE == g_usbd_dev_conf.device_state) { if((0u == g_setup_pkt.value) && (2u == g_setup_pkt.length)) { switch (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK) { case USB_STD_REQ_RECIPIENT_DEVICE: /*SF2 device is self powered*/ g_usbd_status = 0x0001; g_usbd_status |= (g_usbd_dev_conf.remote_wakeup << 0x0001u); *buf_pp = (uint8_t*)&g_usbd_status; break; case USB_STD_REQ_RECIPIENT_INTERFACE: if(g_setup_pkt.index <= g_usbd_dev_conf.device_total_interfaces) { g_usbd_status = 0x0000u; /*Reserved by USB2.0*/ *buf_pp = (uint8_t*)&g_usbd_status; } else { return USB_FAIL; } break; case USB_STD_REQ_RECIPIENT_ENDPOINT: if(((uint8_t)(g_setup_pkt.index) & 0x80u)) /* IN,TX endpoint*/ { uint8_t idx = (((uint8_t)(g_setup_pkt.index))& 0x7fu); g_usbd_status = ((gd_tx_ep[idx].stall) ? 0x0001:0x0000) ; *buf_pp = (uint8_t*)&g_usbd_status; } else /*out, rx endpoint*/ { g_usbd_status = ((gd_rx_ep[g_setup_pkt.index].stall) ? 0x0001:0x0000) ; *buf_pp = (uint8_t*)&g_usbd_status; } break; default: return USB_FAIL; } * len_p = sizeof(g_usbd_status); } else { return USB_FAIL; } } else if(MSS_USB_DEFAULT_STATE == g_usbd_dev_conf.device_state) { return USB_FAIL; } return USB_SUCCESS; } /****************************************************************************** This function processes SET_FEATURE request. */ static uint8_t mss_usbd_set_feature ( void ) { uint8_t result = USB_SUCCESS; if(0u == g_setup_pkt.length) { switch(g_setup_pkt.value) { case USB_STD_FEATURE_REMOTE_WAKEUP: if((USB_STD_REQ_RECIPIENT_DEVICE == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) && (g_usbd_dev_conf.device_state > MSS_USB_DEFAULT_STATE)) { /*Enable Remote wakeup capability for the device*/ g_usbd_dev_conf.remote_wakeup = 0x01u; ASSERT(0); //RemoteWakeup Not enabled by Config Descr. } else { result = USB_FAIL; } break; case USB_STD_FEATURE_EP_HALT: if((USB_STD_REQ_RECIPIENT_ENDPOINT == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) && ((uint8_t)(g_setup_pkt.index)) && (MSS_USB_CONFIGURED_STATE == g_usbd_dev_conf.device_state)) { /*8.5.3.4 Control EP should not be implementing HALT feature*/ if(((uint8_t)(g_setup_pkt.index) & 0x80u)) /* IN,TX endpoint*/ { /*Enable HALT*/ gd_tx_ep[(((uint8_t)(g_setup_pkt.index))& 0x7fu)].stall = 0x01; MSS_USBD_CIF_tx_ep_stall((mss_usb_ep_num_t)((((uint8_t)(g_setup_pkt.index)) & 0x7fu))); } else /*out, rx endpoint*/ { /*Enable HALT*/ gd_rx_ep[(uint8_t)(g_setup_pkt.index)].stall = 0x01; MSS_USBD_CIF_rx_ep_stall((mss_usb_ep_num_t)(g_setup_pkt.index)); } } else { result = USB_FAIL; } break; case USB_STD_FEATURE_TEST_MODE: if((USB_STD_REQ_RECIPIENT_DEVICE == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) && ((g_setup_pkt.index & 0xFF) == 0x00)) { result = USB_SUCCESS; } else { result = USB_FAIL; } break; default: result = USB_FAIL; break; } } else { result = USB_FAIL; } return result; } /****************************************************************************** This function processes CLEAR_FEATURE. */ static uint8_t mss_usbd_clr_feature ( void ) { uint8_t result = USB_SUCCESS; /*TestMode Feature cant be cleared by clr_feature.Device power cycle required*/ if((0u == g_setup_pkt.length) && (g_usbd_dev_conf.device_state > MSS_USB_DEFAULT_STATE)) { switch(g_setup_pkt.value) { case USB_STD_FEATURE_REMOTE_WAKEUP: if(USB_STD_REQ_RECIPIENT_DEVICE == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) { /*Disable Remote wakeup capability for the device*/ g_usbd_dev_conf.remote_wakeup = 0x00u; } break; case USB_STD_FEATURE_EP_HALT: if(USB_STD_REQ_RECIPIENT_ENDPOINT == (g_setup_pkt.request_type & USB_STD_REQ_RECIPIENT_MASK)) { /*8.5.3.4 HALT clear can be performed on CEP and Data EP*/ if((uint8_t)(g_setup_pkt.index)) /*Not a control endpoint*/ { if(((uint8_t)(g_setup_pkt.index) & 0x80u)) /* IN,TX endpoint*/ { /*Disable HALT*/ gd_tx_ep[(((uint8_t)(g_setup_pkt.index))& 0x7fu)].stall = 0x00u; MSS_USBD_CIF_tx_ep_clr_stall((mss_usb_ep_num_t)((((uint8_t)(g_setup_pkt.index)) & 0x7fu))); } else /* out, rx endpoint */ { /*Enable HALT*/ gd_rx_ep[(uint8_t)(g_setup_pkt.index)].stall = 0x00u; MSS_USBD_CIF_rx_ep_clr_stall((mss_usb_ep_num_t)(g_setup_pkt.index)); } } else { result = USB_SUCCESS; } } break; default: result = USB_FAIL; break; } } else { result = USB_FAIL; } return result; } static void mss_usbd_dma_handler_cb ( mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val ) { mss_usb_ep_t *ep_ptr = 0; if(DMA_XFR_ERROR == status) { ASSERT(0); } else { if(MSS_USB_DMA_READ == dma_dir) /*TX EP*/ { ep_ptr = &gd_tx_ep[ep_num]; /*EP interrupt wont happen when */ if((MSS_USB_DMA_MODE1 == (MSS_USB_CIF_tx_ep_get_dma_mode(ep_num))) && (NO_ZLP_TO_XFR == ep_ptr->add_zlp) && (ep_ptr->xfr_length) && (!(ep_ptr->xfr_length % ep_ptr->max_pkt_size))) { /* wait till last TxMaxPkt size packet is sent.*/ while(MSS_USB_CIF_tx_ep_is_txpktrdy(ep_num)); ep_ptr->xfr_count = dma_addr_val - (ptrdiff_t)ep_ptr->buf_addr; if(0 != g_usbd_class_cb->usbd_class_tx_done) { /* call-back class driver */ g_usbd_class_cb->usbd_class_tx_done(ep_num, status); } } else { MSS_USB_CIF_tx_ep_set_txpktrdy(ep_num); } } else if(MSS_USB_DMA_WRITE == dma_dir)/*RX EP*/ { ep_ptr = &gd_rx_ep[ep_num]; if((NO_ZLP_TO_XFR == ep_ptr->add_zlp) && (ep_ptr->xfr_length) && (!(ep_ptr->xfr_length % ep_ptr->max_pkt_size))) { ep_ptr->xfr_count = dma_addr_val - (ptrdiff_t)ep_ptr->buf_addr; if(MSS_USB_DMA_MODE0 == (MSS_USB_CIF_rx_ep_get_dma_mode(ep_num))) { MSS_USB_CIF_rx_ep_clr_rxpktrdy(ep_num); } if(0 != g_usbd_class_cb->usbd_class_rx_done) { /* call-back class driver */ g_usbd_class_cb->usbd_class_rx_done(ep_num, status, ep_ptr->xfr_count); } } } } } #endif //MSS_USB_DEVICE_ENABLED #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device.h000066400000000000000000001424121432224323300273230ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBD driver * * USBD driver public API. */ /*=========================================================================*//** @mainpage Smartfusion2 MSS USB driver USBD driver @section intro_sec Introduction The USB Device Driver (USBD) is part of USB-LL layer of the MSS USB driver stack. The USBD driver implements the core functionality of the USB device mode operations. The USBD driver is responsible for the following functionalities. * USB Device Enumeration * USB Standard request handling * USB Suspend, Resume and Reset handling * Endpoint management * USB transfers management * USBD-Class call-back interface * Application call-back interface @section theory_op Theory of Operation The following steps are involved in the operation of MSS USB: * Configuration * Initialization * USBD-Class Interface * Application Interface * Data transfer The USBD driver operation depends on user configuration provided in mss_usb_config.h. Configuration The following parameter must be defined in the mss_usb_config.h file to operate the MSS USB block in the USB device mode. MSS_USB_PERIPHERAL_MODE Configures the MSS USB driver stack to operate in the USB device mode. Initialization The USBD driver must be initialized by calling the MSS_USBD_init() initialization function with a parameter to select Hi Speed (HS) mode or Full Speed (FS) mode. The USB enumeration process is handled internally by this driver. The application only needs to provide the required application specific information (descriptors) by using MSS_USBD_set_desc_cb_handler() and the MSS_USBD_set_class_cb_handler() functions to this driver. Note: The USB low speed operation in device mode is not supported by the MSS USB hardware block. USBD-Class Call-back Interface This driver encapsulates the generic USB protocol functionality from the USB class functionality. The USBD driver needs the USBD-Class driver to implement a set of call-back functions implementing the class specific functionality. This driver provides a data type mss_usbd_class_cb_t which must be implemented by the USBD-Class drivers. This data type is the collection of call-back functions which must be implemented by the USBD-Class driver. Implementing all the elements of this structure may not be necessary for a specific USB class. The USBD-Class driver must define a structure of type mss_usbd_class_cb_t and implement its required elements. The USBD-Class driver must pass a pointer to this structure to the USBD driver using the MSS_USBD_set_class_cb_handler() function. Application Call-back Interface The application is required to provide the device specific descriptors during enumeration process, namely; device descriptor, device Qualifier descriptor and strings descriptors. These functions are elements of data structure of type mss_usbd_user_descr_cb_t. This structure must be defined and all the required elements of this structure must be implemented in the user application source code. The pointer to this structure must be passed to the USBD driver using the MSS_USBD_set_desc_cb_handler() function. Data transfer The USB Device uses 'Endpoints' for data transfer. The transmit endpoint and receive endpoint need to be configured for their respective configuration parameters before using them for data transfer. The functions MSS_USBD_tx_ep_configure() and MSS_USBD_rx_ep_configure() must be used to configure transmit endpoint and receive endpoint respectively. The application must use the MSS_USBD_tx_ep_write() function to start data transmission on a transmit endpoint. This function prepares the driver to transmit data to the Host. However, actual transmission happens on receiving IN packet from the USB Host. This function is non-blocking. The USBD-Class driver will be informed of the data transfer completion by a call of its call-back function. Transfer errors are also communicated to the USB-Class driver by a call to its call-back function. Please refer the USBD-Class interface section above for more details. This driver must first be prepared for it this driver must first be prepared. To receive data from the USB Host. The application must use the MSS_USBD_rx_ep_read_prepare() function for this purpose. This function is non-blocking. The USBD-Class driver will be informed of the reception of data by a call to its call-back function. Receive errors are also communicated to the USB-Class driver by a call to its call-back function. Please refer the USBD-Class Interface section above for more details. The USBD driver supports Bulk transfers using the DMA inside MSS USB or without using the internal DMA. It is advised that the USBD driver is configured to use the internal DMA in order to free up the application from transferring data to/from MSS USB hardware block. However, the internal DMA can access only aligned address. Care must be taken that the buffer address provided to the USBD driver must be modulo-4. This is not a requirement when the MSS USB driver is configured not to use internal DMA. The functions MSS_USBD_tx_ep_stall() or MSS_USBD_rx_ep_stall() function must be used when the USBD-Class driver needs to stall a particular endpoint. The stall condition on an endpoint can be cleared using the MSS_USBD_tx_ep_clr_error() and MSS_USBD_rx_ep_clr_error() functions on respective endpoint. However, note that, different USB classes have different requirement for clearing the stall condition. E.g. MSC device class needs the stall to be cleared by the USB host rather than the firmware running on the MSC device. The control endpoint is significantly different in compared to a transmit endpoint or a receive endpoint. The control endpoint can be used for both transmitting data to the host or receiving data from the host. Separate functions are provided to configure and perform data transfers over control endpoint. The MSS_USBD_cep_configure() function must be used to configure the control endpoint. The function MSS_USBD_cep_write() and MSS_USBD_cep_read_prepare() must be used to transmit and receive data over control endpoint respectively. The stall condition on control endpoint is handled by the USBD driver internally because the control endpoint is shared by the USBD driver and the USBD-Class driver. The USBD-Class driver must provide meaningful return value in the call-back functions related to the control endpoint. The USBD driver will appropriately handle the stall condition on the control endpoint depending on these return values. *//*=========================================================================*/ #ifndef __MSS_USB_DEVICE_H_ #define __MSS_USB_DEVICE_H_ #include "mss_usb_common_cif.h" #include "mss_usb_device_cif.h" #ifdef MSS_USB_DEVICE_ENABLED /***************************************************************************//** Constant values exported from USBD driver ******************************************************************************/ /* The following constants are used to specify whether or not the internal DMA must be used for the data transfers. These values must be used as parameter to the MSS_USBD_tx_ep_configure() and the MSS_USBD_rx_ep_configure() functions. */ #define DMA_DISABLE 0u #define DMA_ENABLE 1u /* The following constants are used to specify whether or not a bulk transfers ends with a zero length packet when transfer size is exact multiple of wMaxPacketSize. These values should be used as parameter to the MSS_USBD_tx_ep_configure() and the MSS_USBD_rx_ep_configure() functions. */ #define NO_ZLP_TO_XFR 0u #define ADD_ZLP_TO_XFR 1u /* The following constants are used as the return values for the call-back functions, implemented by the USBD-Class driver as part of mss_usbd_class_cb_t type, which are called by the USBD driver. The USBD driver uses these values to infer whether or not the call-back function was successfully executed. The current control transfer is stalled if the return value is USB_FAIL. */ #define USB_FAIL 0u #define USB_SUCCESS 1u /***************************************************************************//** Data structures exported by the USBD driver ******************************************************************************/ /***************************************************************************//** mss_usbd_user_descr_cb The mss_usbd_user_descr_cb_t provides the prototype of the structure that must be implemented by the application to provide the call-back functions which will be called by the USBD driver to get the user descriptor information. usbd_device_descriptor The function pointed by the usbd_device_descriptor element will be called when the USB device receives from USB host the GET_DESCRIPTOR command requesting the device descriptor. This function must return a pointer to the device descriptor and provide the length of the descriptor in the return parameter. usbd_device_qual_descriptor The function pointed by the usbd_device_qual_descriptor element will be called when the USB device receives from USB host the GET_DESCRIPTOR command requesting the device qualifier descriptor. This function must return a pointer to the device qualifier descriptor and provide the length of the descriptor in the return parameter. usbd_string_descriptor The function pointed by the usbd_string_descriptor element will be called when the USB device receives from USB host the GET_DESCRIPTOR command requesting specific string descriptor. Requested string descriptor number is provided in parameter index. This function must return a pointer to the requested string descriptor and provide the length of the string descriptor in the return parameter length. */ typedef struct mss_usbd_user_descr_cb { uint8_t* (*usbd_device_descriptor)(uint32_t* length); uint8_t* (*usbd_device_qual_descriptor)(mss_usb_device_speed_t speed, uint32_t* length); uint8_t* (*usbd_string_descriptor)(uint8_t index, uint32_t* length); } mss_usbd_user_descr_cb_t; /***************************************************************************//** mss_usbd_setup_pkt_t The mss_usbd_setup_pkt_t provides the prototype of the structure for the setup packet sent by the host. All the parameters of this structure are as per the standard setup packet defined in the USB2.0 specification. request_type The request_type parameter provides the information on the type of the request sent by the host. The meaning of this parameter is exactly as defined by the USB2.0 specification. request The request parameter is the actual request sent by the host. The meaning of this parameter is exactly as defined by the USB2.0 specification. value The value parameter is the value associated with the request. The meaning of this parameter is exactly as defined by the USB2.0 specification. index The index parameter is the index information associated with the request. The meaning of this parameter is exactly as defined by the USB2.0 specification. length The length parameter provides the length of the data associated with the request. The meaning of this parameter is exactly as defined by the USB2.0 specification. */ typedef struct { uint8_t request_type; uint8_t request; uint16_t value; uint16_t index; uint16_t length; } mss_usbd_setup_pkt_t; /***************************************************************************//** mss_usb_class_cb The mss_usbd_class_cb_t provides the prototype of the structure that must be implemented by the USBD-class driver to provide the call-back functions which will be called by the USBD driver on specific events on the USB bus. usbd_class_init The function pointed by the usbd_class_init element will be called when the USB device receives SET_CONFIGURATION request from USB host with a non-zero cfgidx number. The parameter cfgidx indicates the configuration number that must be set by the USB device. The USB device goes into the MSS_USB_CONFIGURED_STATE on receiving this command. The musb_speed parameter indicates the USB speed at which the MSS USB is operating. The speed of operation is determined during enumeration process. usbd_class_release The function pointed by the usbd_class_release element will be called when the USB device receives SET_CONFIGURATION request from USB host with a cfgidx = 0. The parameter cfgidx indicates the configuration number that must be set by the USB device. The USB device goes into the MSS_USB_ADDRESS_STATE on receiving this command. It will also be called when the device is disconnected from the host. The disconnect event is detected by the USBD driver and is communicated to the class driver using this element by passing the parameter cfgidf = 0xFF. On detecting the disconnect event, the USB device goes into the MSS_USB_NOT_ATTACHED_STATE state. usbd_class_get_descriptor The function pointed by the usbd_class_get_descriptor element will be called when the USB device receives GET_DESCRIPTOR request from the USB host requesting a class specific descriptor. The parameter recipient indicates the intended recipient by the USB host (endpoint, interface or device). The parameter type indicates the type of descriptor requested. The musb_speed parameter indicates the USB speed at which the MSS USB is operating. The speed of operation is determined during enumeration process. The musb_speed parameter must be used to provide speed dependent descriptors. usbd_class_process_request The function pointed by the usbd_class_process_request element will be called when the USB device receives class specific request from USB host. The parameter setup_pkt is the pointer to the setup packet sent by the host. The parameters buf_p and length are used for the data which might be associated with the current setup packet. If the host requests data from the device, the USBD-Class driver must provide the address of the buffer containing the data in buf_p parameter and the length of this buffer in bytes in length parameter. If the host wants to send data to the device then USBD-Class driver must provide the address of the buffer where the data must be placed in buf_p parameter and the size of the buffer in bytes in the length parameter. For the zero data length request the buf_p and the length parameters are not meaningful. usbd_class_tx_done The function pointed by the usbd_class_tx_done element will be called when the data is transferred on previously configured transmit endpoint. The endpoint on which data is transmitted is indicated by parameter num. The parameter status indicates the error status of the transmit transaction. A non-zero status value indicates that there was an error occurred in the last receive transaction. usbd_class_rx_done The function pointed by the usbd_class_rx_done element will be called when data is received on previously configured receive endpoint. The endpoint on which data is received is indicated by parameter num. The parameter status indicates the error status of the receive transaction. A non-zero status value indicates that there was an error occurred in the last receive transaction. The rx_count parameter indicates the number of bytes received in the last receive transaction. usbd_class_cep_tx_done The function pointed by the usbd_class_cep_tx_done element will be called when a data packet is transmitted on the previously configured control endpoint. The data buffer was provided to this driver using the usbd_class_process_request call-back before the usbd_class_cep_tx_done call-back was called. The parameter status indicates error status of the transmit transaction. A non-zero status value indicates that there was error in last transmit transaction. usbd_class_cep_rx_done The function pointed by the usbd_class_cep_rx_done element will be called when a data packet is received on previously configured control endpoint. The received data is stored in the buffer which was previously provided by the usbd_class_process_request call-back before usbd_class_cep_rx_done is called. The parameter status indicates the error status of the receive transaction. A non-zero status value indicates that there was an error occurred in the last receive transaction. */ typedef struct mss_usbd_class_cb { uint8_t(*usbd_class_init)(uint8_t cfgidx, mss_usb_device_speed_t musb_speed); uint8_t(*usbd_class_release)(uint8_t cfgidx); uint8_t*(*usbd_class_get_descriptor)(uint8_t recepient, uint8_t type, uint32_t* length, mss_usb_device_speed_t musb_speed); uint8_t(*usbd_class_process_request)(mss_usbd_setup_pkt_t* setup_pkt, uint8_t** buf_p, uint32_t* length); uint8_t(*usbd_class_tx_done)(mss_usb_ep_num_t num, uint8_t status); uint8_t(*usbd_class_rx_done)(mss_usb_ep_num_t num, uint8_t status, uint32_t rx_count); uint8_t(*usbd_class_cep_tx_done)(uint8_t status); uint8_t(*usbd_class_cep_rx_done)(uint8_t status); } mss_usbd_class_cb_t; /***************************************************************************//** Data structures which are internally used by USBD driver ******************************************************************************/ #ifdef MSS_USB_DEVICE_TEST_MODE typedef struct mss_usbd_user_test_cb { void(*test_ep_rx)(mss_usb_ep_num_t num, uint8_t status, uint32_t rx_count); void(*test_ep_tx_complete)(mss_usb_ep_num_t num, uint8_t status); void(*test_cep_setup)(uint8_t status); void(*test_cep_rx)(uint8_t status); void(*test_cep_tx_complete)(uint8_t status); void(*test_sof)(uint8_t status); void(*test_reset)(void); void(*test_suspend)(void); void(*test_resume)(void); void(*test_disconnect)(void); } mss_usbd_user_test_cb_t; #endif /******************************************************************************* Exported functions from USBD driver ******************************************************************************/ /***************************************************************************//** @brief MSS_USBD_init() The MSS_USBD_init() function must be used to initialize the USB driver in device mode. The desired operating speed is specified as parameter. When selecting MSS_USB_DEVICE_HS, the MSS USB will try to negotiate for high speed during enumeration process. The actual speed of operation depends on the host the device is connected to. If the host is only a full speed host, then MSS USB will appear as a full speed device. This will also be the case when the MSS USB is connected to a host through a USB 1.x hub. Note: When MSS_USB_DEVICE_FS is selected, MSS USB will never negotiate for High speed. It will always appear as a full speed device only. @param speed The speed parameter specifies the USB speed at which the USB driver and the MSS USB core must operate. Valid values for this parameter are MSS_USB_DEVICE_HS MSS_USB_DEVICE_FS @return This function does not return a value. Example: @code MSS_USBD_init(MSS_USB_DEVICE_FS); MSS_USBD_set_descr_cb_handler(&flash_drive_descriptors_cb); @endcode */ void MSS_USBD_init ( mss_usb_device_speed_t speed ); /***************************************************************************//** @brief MSS_USBD_set_descr_cb_handler() The MSS_USBD_set_desc_cb_handler() function must be used to provide the application call-back interface functions to the USBD driver which will be called by this driver to get the USB user descriptor. @param user_desc_cb The user_desc_cb parameter provides the address of the structure of type mss_usbd_user_descriptors_cb_t which is implemented by the class driver or the application. @return This function does not return a value. Example: @code MSS_USBD_init(MSS_USB_DEVICE_FS); MSS_USBD_set_descr_cb_handler(&flash_drive_descriptors_cb); @endcode */ void MSS_USBD_set_descr_cb_handler ( mss_usbd_user_descr_cb_t* user_desc_cb ); /***************************************************************************//** @brief MSS_USBD_set_class_cb_handler() The MSS_USBD_set_class_cb_handler() function must be used to provide the call-back functions to the driver which will be called by this driver to indicate the specific events happening on the USB Bus. @param class_cb The class_cb parameter provides the address of the structure of type mss_usbd_class_cb_t which is implemented by the USBD-Class driver. @return This function does not return a value. Example: @code void MSS_USBD_MSC_init ( mss_usbd_msc_media_t* media_ops, mss_usb_device_speed_t speed ) { g_usbd_msc_media_ops = media_ops; g_usbd_msc_user_speed = speed; MSS_USBD_set_class_cb_handler(&usb_msd_class_cb); } @endcode */ void MSS_USBD_set_class_cb_handler ( mss_usbd_class_cb_t* class_cb ); /***************************************************************************//** @brief MSS_USBD_cep_configure() The MSS_USBD_cep_configure() function is used to configure the control endpoint (EP0) for the control transactions and enables the control endpoint interrupt. Other Properties of the control endpoint are fixed as listed below. Transfer type - Control Transfer. FIFO address - 0x00 FIFO Size - 0x40 (64 decimal) This function must be called before any other function for the control endpoint. @param max_pkt_size The max_pkt_size parameter is the maximum packet size used for control transfer. This value must match with the bMaxPacketSize0 value in the device descriptor. @return This function does not return a value. Example: @code MSS_USBD_cep_configure(64u); MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, 8u); @endcode */ void MSS_USBD_cep_configure ( uint8_t max_pkt_size ); /***************************************************************************//** @brief MSS_USBD_cep_read_prepare() The MSS_USBD_cep_read_prepare() function prepares the previously configured control endpoint to receive data. After calling this function, the USBD driver is ready to read data received on the next OUT packet. This function prepares the MSS USB hardware block to copy the received data into the provided buffer. This function copies the number of bytes specified by the length parameter from the control endpoint RX FIFO. Extra bytes found in the RX FIFO are discarded. @param addr The addr parameter specifies the address of the receive buffer where the data from the RX FIFO is copied by this driver. @param length The length parameter specifies the length of the receive buffer in bytes. @return This function does not return a value. Example: @code MSS_USBD_cep_configure(64u); MSS_USBD_cep_read_prepare((uint8_t*)&g_setup_pkt, 8u); @endcode */ void MSS_USBD_cep_read_prepare ( uint8_t * addr, uint32_t length ); /***************************************************************************//** @brief MSS_USBD_cep_write() The MSS_USBD_cep_write() function loads the control endpoint FIFO with the data from the buffer specified as parameter. The data will be transmitted over USB on receiving the next IN token. If the length parameter value is more than the max_pkt_size parameter for control endpoint then this functions loads number of bytes equal to the max_pkt_size value. The max_pkt_size parameter was provided to this driver using MSS_USBD_cep_configure() function. @param addr The addr parameter specifies the address of the buffer containing the data to be copied to the control endpoint buffer. @param length The length parameter specifies the length of the provided buffer in bytes. @return This function does not return a value. Example: @code MSS_USBD_cep_write(buf, length); @endcode */ void MSS_USBD_cep_write ( uint8_t * addr, uint32_t length ); /***************************************************************************//** @brief MSS_USBD_cep_flush_fifo() The MSS_USBD_cep_flush_fifo() function is used to flush the content of the control endpoint FIFO. This function is typically used to empty the FIFO in case there were errors reported on the last data transaction on control endpoint. @param This function does not take any parameter. @return This function does not return a value. Example: @code MSS_USBD_cep_flush_fifo(); @endcode */ void MSS_USBD_cep_flush_fifo ( void ); /***************************************************************************//** @brief MSS_USBD_cep_enable_irq() The MSS_USBD_cep_enable_irq() function is used to enable the control endpoint interrupt. @param This function does not take any parameter. @return This function does not return a value. Example: @code MSS_USBD_cep_enable_irq(); @endcode */ void MSS_USBD_cep_enable_irq ( void ); /***************************************************************************//** @brief MSS_USBD_cep_disable_irq() The MSS_USBD_cep_disable_irq() function is used to disable the control endpoint interrupt. @param This function does not take any parameter. @return This function does not return a value. Example: @code MSS_USBD_cep_disable_irq(); @endcode */ void MSS_USBD_cep_disable_irq ( void ); /***************************************************************************//** @brief MSS_USBD_tx_ep_configure() The MSS_USBD_tx_ep_configure() function configures the transmit endpoint with the configuration values provided as parameters. After initializing the core, this function must be called before any other function for the desired transmit endpoint. Note: This driver does not make any assumptions on the FIFO size and FIFO address, to provide complete flexibility in configuring the FIFOs. The user is responsible to make sure that the endpoint FIFO does not overlap with other endpoint FIFO space. @param ep_num The ep_num parameter is the endpoint number which is to be configured. The endpoint number must be of the type mss_usb_ep_num_t. @param fifo_addr The fifo_addr parameter is the address of the FIFO in the MSS_USB internal RAM. Valid FIFO address values are from 0x00 to 0xFFF8. The FIFO address must be a multiple of 8. If the value provided is not a multiple of 8, then the immediate lower value which is a multiple of 8 is taken as the FIFO address. E.g. If the provided value is 0x09, the actual value taken by the driver is 0x08. If the provided value is less than 0x08 then the FIFO address is taken as 0x00. @param fifo_size The fifo_size parameter is the endpoint FIFO size in the MSS USB core internal RAM. Valid FIFO size values are 8, 16, 32, 64, 128, 512, 1024, 2048, 4096. The MSS USB core assigns 8 byte FIFO by default if the FIFO size is not configured. @param max_pkt_size The max_pkt_size parameter is the maximum packet size of the USB transfer on this endpoint. This value must be equal to the maximum packet size as mentioned in the endpoint descriptor for this endpoint which is used during enumeration process. Note: This value must be less than or equal to the FIFO size value. @param num_usb_pkt The num_usb_pkt parameter has different meanings for different types of transfers. Low bandwidth ISO/interrupt transfers - This parameter must always be '1u'. This parameter represents the number of packets transferred in one (micro) frame. High bandwidth ISO transfers - This parameter represents the number of packets transferred in one (Micro) frame. In this case, this parameter can have a value of 1, 2 or 3. High bandwidth ISO transfers are not yet implemented. Bulk transfers. - For Bulk transfer this value must always be '1u'. This parameter is used with the auto-amalgamation/auto-split feature where it indicates the number of bulk packets to be auto-amalgamated/auto-split in a bulk transfer. The auto-amalgamation/auto-split feature is not available yet. @param dma_enable The dma_enable parameter specifies whether or not the internal DMA must be used for the data transfer from the provided buffer to the USB FIFO. @param dma_channel The dma_channel parameter specifies the internal DMA channel to be used for the data transfers. The DMA channel will be associated with the selected endpoint. Unique DMA channel must be selected to transfer data on individual endpoints. This parameter is ignored when the dma_enable parameter indicates that the DMA must not be used. @param xfr_type The xfr_type parameter specifies the type of transfer to be performed on the selected endpoint. All other types of transfers (Interrupt, Isochronous, and Bulk) can be selected except control transfer. @param add_zlp The add_zlp parameter indicates whether a zero length packet (ZLP) must be sent if the transfer is an exact multiple of wMaxPacketSize. This parameter is only applicable for Bulk transfers. This parameter is ignored for all other transfer types. @return This function does not return a value. Example: @code uint8_t usbd_hid_init_cb ( uint8_t cfgidx, mss_usb_device_speed_t musb_speed ) { g_tx_complete_status = 1; MSS_USBD_tx_ep_configure(HID_INTR_TX_EP, HID_INTR_TX_EP_FIFO_ADDR, HID_INTR_TX_EP_MAX_PKT_SIZE, HID_INTR_TX_EP_MAX_PKT_SIZE, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL1, MSS_USB_XFR_INTERRUPT, NO_ZLP_TO_XFR); g_usb_hid_state = USBD_HID_CONFIGURED; return SUCCESS; } @endcode */ void MSS_USBD_tx_ep_configure ( mss_usb_ep_num_t ep_num, uint16_t fifo_addr, uint16_t fifo_size, uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp ); /***************************************************************************//** @brief MSS_USBD_tx_ep_write() The MSS_USBD_tx_ep_write() function writes the data provided by the user into the previously configured transmit endpoint FIFO. After calling this function, the data in the endpoint FIFO is transmitted on the USB bus on receiving the next IN token from the USB Host. A callback function will be called to indicate successful data-in transaction after complete data has been transferred. @param ep_num The ep_num parameter specifies the endpoint number on which the data is to be transmitted. @param addr The addr parameter is the address of the buffer provided by the user from which the data is copied to the selected endpoint buffer. @param Length The length parameter specifies the length of the data buffer in bytes. @return This function does not return a value. Example: @code void usbd_msc_send_data ( uint8_t* buf, uint32_t len ) { g_bot_state = BOT_DATA_TX; MSS_USBD_tx_ep_write(MSS_USB_TX_EP_1, buf, len); g_current_command_csw.data_residue -= len; } @endcode */ void MSS_USBD_tx_ep_write ( mss_usb_ep_num_t ep_num, uint8_t * addr, uint32_t length ); /***************************************************************************//** @brief MSS_USBD_tx_ep_stall() The MSS_USBD_tx_ep_stall() function is used to send a stall condition on the specified transmit endpoint. @param ep_num The ep_num parameter specifies the transmit endpoint number which is to be stalled. @return This function does not return a value. Example: @code if(g_current_command_csw.status == SCSI_COMMAND_FAILED) { MSS_USBD_tx_ep_stall(MSS_USB_TX_EP_1); } @endcode */ void MSS_USBD_tx_ep_stall ( mss_usb_ep_num_t ep_num ); /***************************************************************************//** @brief MSS_USBD_tx_ep_clr_stall() The MSS_USBD_tx_ep_clr_stall() function is used to clear a stall condition on the previously stalled transmit endpoint. @param ep_num The ep_num parameter specifies the transmit endpoint number on which the stall condition is to be cleared. @return This function does not return a value. Example: @code MSS_USBD_tx_ep_clr_stall(MSS_USB_TX_EP_1); @endcode */ void MSS_USBD_tx_ep_clr_stall ( mss_usb_ep_num_t ep_num ); /***************************************************************************//** @brief MSS_USBD_tx_ep_flush_fifo() The MSS_USBD_tx_ep_flush_fifo() function is used to flush the content of the specified transmit endpoint FIFO. This function is typically used to flush the Transmit FIFO in case there were errors reported during the last transmit operation on the specified transmit endpoint. @param ep_num The ep_num parameter specifies the transmit endpoint number whose content is to be flushed. @return This function does not return a value. Example: @code MSS_USBD_tx_ep_flush_fifo(MSS_USB_TX_EP_1); @endcode */ void MSS_USBD_tx_ep_flush_fifo ( mss_usb_ep_num_t ep_num ); /***************************************************************************//** @brief MSS_USBD_tx_ep_is_fifo_notempty() The MSS_USBD_tx_ep_fifo_notempty() function is used to know whether or not the transmit endpoint FIFO is empty. @param ep_num The ep_num parameter specifies the transmit endpoint number whose FIFO is to be checked. @return A non zero return value indicates that there is at least one packet in the transmit endpoint FIFO. Example: @code @endcode */ uint8_t MSS_USBD_tx_ep_is_fifo_notempty ( mss_usb_ep_num_t epnum ); /***************************************************************************//** @brief MSS_USBD_tx_ep_enable_irq() The MSS_USBD_tx_ep_enable_irq() function is used to enable interrupt on the selected transmit endpoint. @param ep_num The ep_num parameter specifies the transmit endpoint number on which the interrupt is to be enabled. @return This function does not return a value. Example: @code MSS_USBD_tx_ep_enable_irq(MSS_USB_TX_EP_1); @endcode */ void MSS_USBD_tx_ep_enable_irq ( mss_usb_ep_num_t epnum ); /***************************************************************************//** @brief MSS_USBD_tx_ep_disable_irq() The MSS_USBD_tx_ep_disable_irq() function is used to disable interrupt on the selected transmit endpoint. @param ep_num The ep_num parameter specifies the transmit endpoint number on which the interrupt is to be disabled. @return This function does not return a value. Example: @code MSS_USBD_tx_ep_disable_irq(MSS_USB_TX_EP_1); @endcode */ void MSS_USBD_tx_ep_disable_irq ( mss_usb_ep_num_t epnum ); /***************************************************************************//** @brief MSS_USBD_set_isoupdate() The MSS_USBD_set_isoupdate() function is used to make the transmit endpoint wait for transmitting the data until a SOF packet is received. After calling this function, from the time data is deemed ready, the isochronous transmit endpoint is forced to wait for an SOF token before IN token is received. If IN token is received before an SOF token, then a zero length data packet will be sent. Note: All the transmit endpoint which use isochronous transfers are affected by this function. @param This function does not take any parameters. @return This function does not return a value. Example: @code MSS_USBD_set_isoupdate(); @endcode */ void MSS_USBD_set_isoupdate ( void ); /***************************************************************************//** @brief MSS_USBD_clr_isoupdate() The MSS_USBD_clr_isoupdate() function is used to configure all the isochronous transmit endpoint such that, once the data is deemed ready, isochronous endpoint will not wait for SOF token to arrive before IN token. Data will be transmitted on the next received IN token. This is the default behaviour of an isochronous transmit endpoint. This function has effect only if the endpoint was previously configured by MSS_USBD_set_isoupdate() function. Note: All the transmit endpoint which use Isochronous transfers are affected by this function. @param This function does not take any parameters. @return This function does not return a value. Example: @code MSS_USBD_clr_isoupdate(); @endcode */ void MSS_USBD_clr_isoupdate ( void ); /***************************************************************************//** @brief MSS_USBD_rx_ep_configure() The MSS_USBD_rx_ep_configure() function configures the receive endpoint with the configuration values provided as parameters. After initializing the core, this function must be called before any other function for the desired receive endpoint. Note: This driver does not make any assumptions on the FIFO size and FIFO address to provide complete flexibility in configuring the FIFOs. The User is responsible to make sure that the endpoint FIFO does not overlap with other endpoint FIFO space. @param ep_num The ep_num parameter is the endpoint number on which the USB transfers are to be performed. The endpoint number must be provided using the mss_usb_ep_num_t type. @param fifo_addr The fifo_addr parameter is the address of the FIFO in the internal RAM in the MSS USB core. Valid FIFO address values are from 0x00 to 0xFFF8. The FIFO address must be a multiple of 8. If the provided value is not a multiple of 8, then the immediate lower value which is a multiple of 8 is taken as the FIFO address. E.g. If the provided value is 0x09, the actual value taken by the driver is 0x08. If the provided value is less than 0x08 then the FIFO address is taken as 0x00. @param fifo_size The fifo_size parameter provides the endpoint FIFO size in the MSS USB core internal RAM. The Valid FIFO size values are 8, 16, 32, 64, 128, 512, 1024, 2048, 4096. The MSS USB core assigns 8 byte FIFO by default if the FIFO size is not configured. @param max_pkt_size The max_pkt_size parameter provides the maximum packet size of the USB transfer. This value must be equal to the maximum packet size as mentioned in the endpoint descriptor which is used during enumeration process. Note: This value must be less than or equal to the FIFO size value. @param num_usb_pkt The num_usb_pkt parameter has different meanings for different types of transfers. Low bandwidth ISO/interrupt transfers - This parameter must always be '1u'. This parameter represents the number of packets transferred in one (micro) frame. High bandwidth ISO transfers - This parameter represents the number of packets transferred in one (Micro) frame. In this case, this parameter can have a value of 1 2 or 3. High bandwidth ISO transfers are not yet implemented. Bulk transfers. - For Bulk transfer this value must always be '1u'. This parameter is used with the auto-amalgamation/auto-split feature where it indicates number of bulk packets to be auto-amalgamated/auto-split in bulk transfer. The auto-amalgamation/auto-split feature is implemented but not yet tested. @param dma_enable The dma_enable parameter specifies whether or not the internal DMA must be used for the data transfer from the provided buffer to the USB FIFO. @param dma_channel The dma_channel parameter specifies the internal DMA channel to be used for the data transfers. DMA channel will be associated with the selected endpoint. A unique DMA channel must be selected to transfer data on individual endpoints. This parameter is ignored when dma_enable parameter indicates that the DMA must not be used. @param xfr_type The xfr_type parameter specifies the type of transfer to be performed on the selected endpoint. All types of transfers (Interrupt, Isochronous, and Bulk) can be selected except control transfer. @param add_zlp The add_zlp parameter indicates whether to expect a zero length packet (ZLP) if the transfer is exact multiple of wMaxPacketSize. This parameter is only applicable for Bulk transfers. This parameter is ignored for all other transfer types. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_configure(MSS_USB_RX_EP_1, 0x100u, bulk_rxep_fifo_sz, bulk_rxep_maxpktsz, 1u, DMA_ENABLE, MSS_USB_DMA_CHANNEL1, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR); MSS_USBD_rx_ep_read_prepare(MSS_USB_RX_EP_1, (uint8_t*)&g_bot_cbw, 31u); @endcode */ void MSS_USBD_rx_ep_configure ( mss_usb_ep_num_t ep_num, uint16_t fifo_addr, uint16_t fifo_size, uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp ); /***************************************************************************//** @brief MSS_USBD_rx_ep_read_prepare() The MSS_USBD_rx_ep_read_prepare() function prepares the specified receive endpoint for receiving data over USB. The MSS_USBD_rx_ep_configure() function must be called before calling this function. After calling this function, data will be received on the selected endpoint when the data arrives with the next OUT packet. @param ep_num The ep_num parameter specifies the endpoint number on which the data is to be received. @param addr The addr parameter is the address of the buffer to which the received data is copied from the selected endpoint buffer. @param length The length parameter specifies the length of the buffer in bytes. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_configure(MSS_USB_RX_EP_1, 0x100u, bulk_rxep_fifo_sz, bulk_rxep_maxpktsz, 1u, DMA_ENABLE, MSS_USB_DMA_CHANNEL1, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR); MSS_USBD_rx_ep_read_prepare(MSS_USB_RX_EP_1, (uint8_t*)&g_bot_cbw, 31u); @endcode */ void MSS_USBD_rx_ep_read_prepare ( mss_usb_ep_num_t ep_num, uint8_t* addr, uint32_t length ); /***************************************************************************//** @brief MSS_USBD_rx_ep_stall() The MSS_USBD_rx_ep_stall() function is used to send a stall condition on the specified receive endpoint. @param ep_num The ep_num parameter specifies the receive endpoint number which is to be stalled. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_stall(MSS_USB_RX_EP_1); @endcode */ void MSS_USBD_rx_ep_stall ( mss_usb_ep_num_t ep_num ); /***************************************************************************//** @brief MSS_USBD_rx_ep_clr_stall() The MSS_USBD_rx_ep_clr_stall() function is used to clear a stall condition on the previously stalled receive endpoint. @param ep_num The ep_num parameter specifies the receive endpoint number on which the stall condition is to be cleared. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_clr_stall(MSS_USB_RX_EP_1); @endcode */ void MSS_USBD_rx_ep_clr_stall ( mss_usb_ep_num_t ep_num ); /***************************************************************************//** @brief MSS_USBD_rx_ep_flush_fifo() The MSS_USBD_rx_ep_flush_fifo() function is used to flush the content of the selected receive endpoint FIFO. This function is typically used when there were errors reported with the last USB OUT transaction. @param ep_num The ep_num parameter specifies the receive endpoint number whose content is to be flushed. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_flush_fifo(MSS_USB_RX_EP_1); @endcode */ void MSS_USBD_rx_ep_flush_fifo ( mss_usb_ep_num_t ep_num ); /***************************************************************************//** @brief MSS_USBD_rx_ep_is_fifo_full() The MSS_USBD_rx_ep_is_fifo_full() function is used to find out whether or not selected receive endpoint FIFO is full. @param ep_num The ep_num parameter specifies the receive endpoint number whose FIFO needs to be checked. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_is_fifo_full(MSS_USB_RX_EP_1); @endcode */ uint8_t MSS_USBD_rx_ep_is_fifo_full ( mss_usb_ep_num_t epnum ); /***************************************************************************//** @brief MSS_USBD_rx_ep_enable_irq() The MSS_USBD_rx_ep_enable_irq() function is used to enable interrupt on the specified receive endpoint. @param ep_num The ep_num parameter specifies the receive endpoint number on which the interrupt is to be enabled. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_enable_irq(MSS_USB_RX_EP_1); @endcode */ void MSS_USBD_rx_ep_enable_irq ( mss_usb_ep_num_t epnum ); /***************************************************************************//** @brief MSS_USBD_rx_ep_disable_irq() The MSS_USBD_rx_ep_disable_irq() function is used to disable interrupt on the specified receive endpoint. @param ep_num The ep_num parameter specifies the receive endpoint number on which the interrupt is to be disabled. @return This function does not return a value. Example: @code MSS_USBD_rx_ep_disable_irq(MSS_USB_RX_EP_1); @endcode */ void MSS_USBD_rx_ep_disable_irq ( mss_usb_ep_num_t epnum ); /***************************************************************************//** @brief MSS_USBD_get_dev_address() The MSS_USBD_get_dev_address() function is used to read the current USB address by which the host addresses this device. By default this address is 0x00. This address gets updated during the enumeration process when the USB host assigns a non-zero address to this device using the SET_ADDRESS request. @param This function does not take any parameter. @return This function returns 8-bit value indicating the current USB address to which this device responds over USB. Example: @code MSS_USBD_get_dev_address(); @endcode */ uint8_t MSS_USBD_get_dev_address ( void ); /***************************************************************************//** @brief MSS_USBD_get_hwcore_info() @param @return Example: @code @endcode */ void MSS_USBD_get_hwcore_info ( mss_usb_core_info_t* hw_info ); #endif //MSS_USB_DEVICE_ENABLED #endif /* __MSS_USB_DEVICE_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device_cif.c000066400000000000000000000246411432224323300301420ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USBD-CIF driver * * USBD-CIF driver implementation: * This file implements MSS USB core initialization in device mode and * implements core interface function for the logical layer to control the * MSS USB core in USB Device mode. * */ #include "mss_usb_device_cif.h" #include "mss_usb_core_regs.h" #include "mss_usb_common_cif.h" #include "mss_usb_device_reg_io.h" #include "mss_usb_common_reg_io.h" #include "mss_plic.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_DEVICE_ENABLED /***************************************************************************//** These pointers are used for holding the Receive transfer parameters (Buffer address, length) etc. This pointer will be updated in MSS_USBD_CIF_rx_ep_read_prepare() API and used in MSS_USB_CIF_handle_rx_ep_irq(). */ volatile mss_usbd_cep_state_t cep_state; /***************************************************************************//** EXPORTED APIs ******************************************************************************/ /***************************************************************************//** This function initializes the MSS USB core in Device mode. */ volatile uint32_t reg=0; void MSS_USBD_CIF_init(mss_usb_device_speed_t speed) { cep_state = MSS_USB_CTRL_EP_IDLE; /*TODO: Avoid resetting twice in DualRole mode*/ MSS_USB_CIF_soft_reset(); MSS_USB_CIF_clr_usb_irq_reg(); /*Reset and Resume are by default enabled in INTRUSBE reg after soft reset*/ PLIC_EnableIRQ(PLIC_USB_DMA_INT_OFFSET); PLIC_EnableIRQ(PLIC_USB_MC_INT_OFFSET); MSS_USB_CIF_rx_ep_disable_irq_all(); MSS_USB_CIF_tx_ep_disable_irq_all(); if(MSS_USB_DEVICE_FS == speed) { MSS_USB_CIF_disable_hs_mode(); } /*This was added during Compliance testing. Refer MUSB section 3.8.5*/ USB->C_T_HSBT = 0x01u; } /***************************************************************************//** Provides the information about the MSS USB core configuration */ void MSS_USBD_CIF_get_hwcore_info(mss_usb_core_info_t* hw_core) { MSS_USB_CIF_set_index_reg(MSS_USB_CEP); hw_core->core_max_nbr_of_tx_ep = (USB->EP_INFO & 0x0Fu); /*lower nibble for txep*/ hw_core->core_max_nbr_of_rx_ep = ((USB->EP_INFO & 0xF0u) >> 4u);/*higher nibble for txep*/ hw_core->core_ram_bus_width = (USB->RAM_INFO & 0x0Fu);/*lower nibble for bus width*/ hw_core->core_max_nbr_of_dma_chan = ((USB->RAM_INFO & 0xF0u) >> 4u);/*higher nibble for dma channels*/ hw_core->core_WTCON = ((USB->LINK_INFO & 0xF0u) >> 4u);/*refer musb section 3 . 7 . 3*/ hw_core->core_WTID = (USB->LINK_INFO & 0x0Fu);/*refer musb section 3 . 7 . 3*/ hw_core->core_VPLEN = USB->VP_LEN; hw_core->core_HS_EOF1 = USB->HS_EOF1; hw_core->core_FS_EOF1 = USB->FS_EOF1; hw_core->core_LS_EOF1 = USB->LS_EOF1; hw_core->core_configdata = USB->INDEXED_CSR.DEVICE_EP0.CONFIG_DATA; } /***************************************************************************//** Configures the registers related to TX EP for data transfer operations as per the parameters provided by the upper layer. */ void MSS_USBD_CIF_tx_ep_configure(mss_usb_ep_t* device_ep) { MSS_USB_CIF_tx_ep_clr_csrreg(device_ep->num); //clear previous config, if any MSS_USB_CIF_tx_ep_clr_underrun(device_ep->num); MSS_USB_CIF_tx_ep_clr_send_stall_bit(device_ep->num); MSS_USB_CIF_tx_ep_clr_stall_sent_bit(device_ep->num); switch(device_ep->xfr_type) { case MSS_USB_XFR_INTERRUPT: MSS_USB_CIF_tx_ep_disable_iso(device_ep->num); MSS_USB_CIF_tx_ep_clr_autoset(device_ep->num); break; case MSS_USB_XFR_BULK: MSS_USB_CIF_tx_ep_disable_iso(device_ep->num); if(device_ep->dma_enable == DMA_ENABLE) MSS_USB_CIF_tx_ep_set_autoset(device_ep->num); break; case MSS_USB_XFR_ISO: /*Error check and Data toggle is ignored in ISO transfers*/ MSS_USB_CIF_tx_ep_enable_iso(device_ep->num); MSS_USB_CIF_tx_ep_clr_autoset(device_ep->num); break; default: ASSERT(0); break; } /*Do the common configuration for TX EP*/ MSS_USB_CIF_tx_ep_configure(device_ep); } /***************************************************************************//** Configures the RX EP for data transfer operations as per the parameters provided by upper layer. */ void MSS_USBD_CIF_rx_ep_configure(mss_usb_ep_t* device_ep) { MSS_USB_CIF_rx_ep_clr_csrreg(device_ep->num); //clear previous config, if any MSS_USB_CIF_rx_ep_clr_overrun(device_ep->num); MSS_USB_CIF_rx_ep_clr_stall_sent_bit(device_ep->num); MSS_USB_CIF_rx_ep_clr_send_stall_bit(device_ep->num); switch(device_ep->xfr_type) { case MSS_USB_XFR_INTERRUPT: MSS_USB_CIF_rx_ep_disable_iso(device_ep->num); MSS_USB_CIF_rx_ep_disable_nyet(device_ep->num); MSS_USB_CIF_rx_ep_clr_autoclr(device_ep->num); break; case MSS_USB_XFR_BULK: MSS_USB_CIF_rx_ep_disable_iso(device_ep->num); MSS_USB_CIF_rx_ep_enable_nyet(device_ep->num); MSS_USB_CIF_rx_ep_set_autoclr(device_ep->num); break; case MSS_USB_XFR_ISO: MSS_USB_CIF_rx_ep_clr_autoclr(device_ep->num); MSS_USB_CIF_rx_ep_enable_iso(device_ep->num); MSS_USB_CIF_rx_ep_disable_nyet(device_ep->num); break; default: ASSERT(0); break; } /*Do the common configuration for RX EP*/ MSS_USB_CIF_rx_ep_configure(device_ep); } /***************************************************************************//** Configures the Control EP for data transfer operations. */ void MSS_USBD_CIF_cep_configure(void) { /*Control transfers will be handled without DMA*/ MSS_USB_CIF_set_index_reg(MSS_USB_CEP); MSS_USB_CIF_cep_reset_csr0_reg(); MSS_USB_CIF_cep_enable_irq(); } /***************************************************************************//** Prepares the Control EP for receiving data as per the parameters provided by upper layer */ void MSS_USBD_CIF_cep_rx_prepare(mss_usb_ep_t* device_ep) { if(MSS_USB_CEP_IDLE == device_ep[MSS_USB_CEP].state) { cep_state = MSS_USB_CTRL_EP_IDLE; } else if((MSS_USB_CEP_SETUP == device_ep[MSS_USB_CEP].state) || (MSS_USB_CEP_RX == device_ep[MSS_USB_CEP].state)) { cep_state = MSS_USB_CTRL_EP_RX; } } /***************************************************************************//** Prepares the RX EP for receiving data as per parameters provided by upper layer */ void MSS_USBD_CIF_rx_ep_read_prepare(mss_usb_ep_t* device_ep) { /*Fixed Buffer overwriting issue found with printer driver and issue with interrupt transfer with DMA by moving the location of interrupt enable function*/ if(DMA_ENABLE == device_ep->dma_enable) { /*Make sure that address is Modulo-4.Bits D0-D1 are read only.*/ ASSERT(!(((ptrdiff_t)device_ep->buf_addr) & 0x00000002)); MSS_USB_CIF_dma_write_addr(device_ep->dma_channel, (ptrdiff_t)device_ep->buf_addr); /* DMA Count register will be loaded after receive interrupt occurs. Mode need to be set every time since M1 to M0 transition might have happened for "short packet". */ if(MSS_USB_XFR_BULK == device_ep->xfr_type) { MSS_USB_CIF_rx_ep_set_dma_mode1(device_ep->num); MSS_USB_CIF_rx_ep_set_autoclr(device_ep->num); MSS_USB_CIF_rx_ep_enable_dma(device_ep->num); MSS_USB_CIF_dma_write_count(device_ep->dma_channel, device_ep->xfr_length); MSS_USB_CIF_rx_ep_enable_irq(device_ep->num); /*Handling single NULL packet reception*/ if(0u != device_ep->xfr_length ) { MSS_USB_CIF_dma_start_xfr(device_ep->dma_channel); } } else { MSS_USB_CIF_rx_ep_clr_autoclr(device_ep->num); MSS_USB_CIF_rx_ep_set_dma_mode0(device_ep->num); /*MUSB section 17.4.1*/ MSS_USB_CIF_rx_ep_disable_dma(device_ep->num); MSS_USB_CIF_rx_ep_enable_irq(device_ep->num); } } else { MSS_USB_CIF_rx_ep_enable_irq(device_ep->num); } } /***************************************************************************//** Writes a data packet on EP0 in device mode(control endpoint). */ void MSS_USBD_CIF_cep_write_pkt(mss_usb_ep_t* device_ep) { if(device_ep->num == MSS_USB_CEP) { /* null buffer, xfr type, transaction type */ if((0 != device_ep->buf_addr) && (MSS_USB_XFR_CONTROL == device_ep->xfr_type)) { MSS_USB_CIF_load_tx_fifo(device_ep->num, device_ep->buf_addr, device_ep->txn_length); device_ep->txn_count = device_ep->txn_length; device_ep->xfr_count += device_ep->txn_length; } if(MSS_USB_CEP_TX == device_ep->state) { cep_state = MSS_USB_CTRL_EP_TX; } if(device_ep->xfr_count < device_ep->xfr_length) { MSS_USB_CIF_cep_set_txpktrdy(); } else if(device_ep->xfr_count >= device_ep->xfr_length) { MSS_USBD_CIF_cep_end_rdr(); } } } /***************************************************************************//** Reads data packet arrived on EP0 in device mode(control endpoint). */ void MSS_USBD_CIF_cep_read_pkt(mss_usb_ep_t* device_ep) { volatile uint16_t received_count = 0u; MSS_USB_CIF_set_index_reg(MSS_USB_CEP); if((MSS_USB_CEP == device_ep->num) && (0 != device_ep->buf_addr)) { /*TODO: check stalled, null buffer, transfer type, transaction type */ received_count = MSS_USB_CIF_cep_rx_byte_count(); MSS_USB_CIF_read_rx_fifo(MSS_USB_CEP, device_ep->buf_addr, received_count); device_ep->xfr_count += received_count; device_ep->txn_count = received_count; } } #endif //MSS_USB_DEVICE_ENABLED #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device_cif.h000066400000000000000000000124251432224323300301440ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USBD-CIF driver * * USBD-CIF driver public API. * */ #ifndef __MSS_USB_DEVICE_CIF_H_ #define __MSS_USB_DEVICE_CIF_H_ #include "mss_usb_core_regs.h" #include "mss_usb_common_reg_io.h" #include "mss_usb_device_reg_io.h" #include "mss_usb_common_cif.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_DEVICE_ENABLED /******************************************************************************* Exported APIs from USBD-CIF */ void MSS_USBD_CIF_get_hwcore_info(mss_usb_core_info_t* hw_core); /* DeviceInfo register related APIs */ /*lint -e20 -e522 -e10 -e40 -e63 -e35 -e26 -e78*/ static __INLINE void MSS_USBD_CIF_set_dev_addr(uint8_t addr) { USB->FADDR = addr; } static __INLINE uint8_t MSS_USBD_CIF_get_dev_addr(void) { return(USB->FADDR); } static __INLINE void MSS_USBD_CIF_force_resume(void) { MSS_USBD_CIF_resume_gen(); } /*ISO INEP Will wait for SOF packet after TxPktRdy is set*/ static __INLINE void MSS_USBD_CIF_set_isoupdate(void) { USB->POWER |= POWER_REG_ISO_UPDATE_MASK; } /*ISO INEP Will NOT wait for SOF packet after TxPktRdy is set*/ static __INLINE void MSS_USBD_CIF_clr_isoupdate(void) { USB->POWER &= ~POWER_REG_ISO_UPDATE_MASK; } static __INLINE void MSS_USBD_CIF_rx_ep_clr_stall(mss_usb_ep_num_t ep_num) { MSS_USB_CIF_rx_ep_clr_send_stall_bit(ep_num); /*TODO: Confirm...this is required for clear feature command*/ MSS_USB_CIF_rx_ep_clr_data_tog(ep_num); } static __INLINE void MSS_USBD_CIF_rx_ep_stall(mss_usb_ep_num_t ep_num) { MSS_USB_CIF_rx_ep_set_send_stall_bit(ep_num); } static __INLINE void MSS_USBD_CIF_tx_ep_clr_stall(mss_usb_ep_num_t ep_num) { MSS_USB_CIF_tx_ep_clr_send_stall_bit(ep_num); /* TODO: Confirm...this is required for clear feature command Lakeview page:62 */ MSS_USB_CIF_tx_ep_clr_data_tog(ep_num); } static __INLINE void MSS_USBD_CIF_tx_ep_stall(mss_usb_ep_num_t ep_num) { MSS_USB_CIF_tx_ep_set_send_stall_bit(ep_num); } /* Soft connect -- D+ and D- lines are connected to the bus Valid in Device mode only. */ static __INLINE void MSS_USBD_CIF_dev_connect(void) { USB->POWER |= POWER_REG_SOFT_CONN_MASK; } static __INLINE void MSS_USBD_CIF_dev_disconnect(void) { USB->POWER &= ~POWER_REG_SOFT_CONN_MASK; } /* In Device mode, only FS or HS are possible. In Host mode, becomes valid after reset bit is cleared. Remains valid till session ends */ static __INLINE uint8_t MSS_USBD_CIF_is_hs_mode(void) { return(((USB->POWER & POWER_REG_HS_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBD_CIF_cep_end_zdr(void) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 = (CSR0L_DEV_SERVICED_RX_PKT_RDY_MASK | CSR0L_DEV_DATA_END_MASK); } static __INLINE void MSS_USBD_CIF_cep_clr_rxpktrdy(void) { /*Setting SERVICED_RX_PKT_RDY clears RxPktRdy bit*/ USB->INDEXED_CSR.DEVICE_EP0.CSR0 = CSR0L_DEV_SERVICED_RX_PKT_RDY_MASK; } static __INLINE void MSS_USBD_CIF_cep_stall(void) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 = (CSR0L_DEV_SEND_STALL_MASK | CSR0L_DEV_SERVICED_RX_PKT_RDY_MASK); } /*write Data Req, host writing on device (USB OUT) */ static __INLINE void MSS_USBD_CIF_cep_end_wdr(void) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 = (CSR0L_DEV_SERVICED_RX_PKT_RDY_MASK | CSR0L_DEV_DATA_END_MASK); } /*Read Data Req, host reading from device (USB IN)*/ /*Taken care by MSS_USBD_CIF_cep_write_pkt TODO: Check with Different Optimization levels*/ static __INLINE void MSS_USBD_CIF_cep_end_rdr(void) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 = (CSR0L_DEV_TX_PKT_RDY_MASK | CSR0L_DEV_DATA_END_MASK); } static __INLINE void MSS_USBD_CIF_reset_index_reg(void) { USB->INDEX = 0u; } /*lint -restore */ /***************************************************************************//** */ void MSS_USBD_CIF_init(mss_usb_device_speed_t speed); /***************************************************************************//** */ void MSS_USBD_CIF_cep_configure(void); /***************************************************************************//** */ void MSS_USBD_CIF_cep_rx_prepare(mss_usb_ep_t* device_ep); /***************************************************************************//** */ void MSS_USBD_CIF_rx_ep_read_prepare(mss_usb_ep_t* device_ep); /***************************************************************************//** */ void MSS_USBD_CIF_cep_read_pkt(mss_usb_ep_t* device_ep); /***************************************************************************//** */ void MSS_USBD_CIF_cep_write_pkt(mss_usb_ep_t* device_ep); /***************************************************************************//** */ void MSS_USBD_CIF_tx_ep_configure(mss_usb_ep_t* device_ep); /***************************************************************************//** */ void MSS_USBD_CIF_rx_ep_configure(mss_usb_ep_t* device_ep); #endif //MSS_USB_DEVICE_ENABLED #ifdef __cplusplus } #endif #endif /* __MSS_USB_DEVICE_CIF_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device_msd.c000066400000000000000000001754361432224323300301750ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBD-MSC class driver. * * USBD-MSC class driver implementation: * This source file implements Mass storage class functionality. * BoT with Transparent SCSI command set is implemented. * */ #include "mss_plic.h" #include "mss_usb_device.h" #include "mss_usb_device_msd.h" #include "mss_assert.h" #include "mss_usb_std_def.h" #include "mss_clint.h" #ifdef __cplusplus extern "C" { #endif #define MSC_CLASS_BULK_RX_EP MSS_USB_RX_EP_1 #define MSC_CLASS_BULK_TX_EP MSS_USB_TX_EP_1 #define MSC_CLASS_INTERFACE_NUM 0x00 /*HS Operation values*/ #define MSC_TX_EP_FIFO_SIZE_HS 512 #define MSC_RX_EP_FIFO_SIZE_HS 512 /*Values should be same as described in ep descriptors*/ #define MSC_TX_EP_MAX_PKT_SIZE_HS 512 #define MSC_RX_EP_MAX_PKT_SIZE_HS 512 /*LS Operation values*/ #define MSC_TX_EP_FIFO_SIZE_FS 64 #define MSC_RX_EP_FIFO_SIZE_FS 64 /*Values should be same as described in ep descriptors*/ #define MSC_TX_EP_MAX_PKT_SIZE_FS 64 #define MSC_RX_EP_MAX_PKT_SIZE_FS 64 #define G_BOT_CBW_INIT() g_bot_cbw.signature = 0;\ g_bot_cbw.tag = 0;\ g_bot_cbw.xfr_length = 0;\ g_bot_cbw.flags = 0;\ g_bot_cbw.lun = 0;\ g_bot_cbw.cmd_length = 0;\ g_bot_cbw.cmd_block[0]=(uint8_t)0;\ g_bot_cbw.cmd_block[1]=(uint8_t)0;\ g_bot_cbw.cmd_block[2]=(uint8_t)0;\ g_bot_cbw.cmd_block[3]=(uint8_t)0;\ g_bot_cbw.cmd_block[4]=(uint8_t)0;\ g_bot_cbw.cmd_block[5]=(uint8_t)0;\ g_bot_cbw.cmd_block[6]=(uint8_t)0;\ g_bot_cbw.cmd_block[7]=(uint8_t)0;\ g_bot_cbw.cmd_block[8]=(uint8_t)0;\ g_bot_cbw.cmd_block[9]=(uint8_t)0;\ g_bot_cbw.cmd_block[10]=(uint8_t)0;\ g_bot_cbw.cmd_block[11]=(uint8_t)0;\ g_bot_cbw.cmd_block[12]=(uint8_t)0;\ g_bot_cbw.cmd_block[13]=(uint8_t)0;\ g_bot_cbw.cmd_block[14]=(uint8_t)0;\ g_bot_cbw.cmd_block[15]=(uint8_t)0; #define CB_PASS 0x01u #define CB_NOT_SUPPORTED 0x02u #define CB_INTERNAL_ERROR 0x03u #define CB_LENGTH_MISMATCH 0x04u #define CB_DATA_DIR_MISMATCH 0x05u #define CB_MOREDATA 0x06u #define CB_LESSDATA 0x07u #define CB_INVALID_LUN 0x08u #define CB_INVALID_CDB_FIELD 0x09u #define CB_INVALID_CBW 0x0Au #define CB_DATAPHASE_ERROR 0x0Bu #define MSCD_CONF_DESCR_DESCTYPE_IDX 1u /***************************************************************************//** Local functions used by USBD-MSC class driver. */ static uint8_t usbd_msc_process_cbw(mss_usb_msc_cbw_t * cbw); static void usbd_msc_prepare_sense_data(uint8_t lun, uint8_t skey, uint8_t asc); static void usbd_msc_abort_cbw(uint8_t lun); static void usbd_msc_bot_fsm(uint8_t status, uint32_t rx_count); static void usbd_msc_send_data(uint8_t* buf, uint32_t len); static void usbd_msc_receive_data(uint8_t* buf, uint32_t len); static void usbd_msc_send_csw(void); static void usbd_msc_stallin_sendstatus(void); static void usbd_msc_stallout_sendstatus(void); static uint8_t usbd_msc_process_read_10(void); static uint8_t usbd_msc_process_write_10(void); static uint8_t usbd_msc_process_inquiry(void); static uint8_t usbd_msc_process_read_capacity_10(void); /***************************************************************************//** Implementations of Call-back functions used by USBD. */ static uint8_t* usbd_msc_get_descriptor_cb(uint8_t recipient, uint8_t type, uint32_t* length, mss_usb_device_speed_t musb_speed); static uint8_t usbd_msc_init_cb(uint8_t cfgidx, mss_usb_device_speed_t musb_speed); static uint8_t usbd_msc_release_cb(uint8_t cfgidx); static uint8_t usbd_msc_tx_complete_cb(mss_usb_ep_num_t num, uint8_t status); static uint8_t usbd_msc_rx_cb(mss_usb_ep_num_t num, uint8_t status, uint32_t rx_count); static uint8_t usbd_msc_process_request_cb(mss_usbd_setup_pkt_t* setup_pkt, uint8_t** buf_pp, uint32_t* length); /******************************************************************************* Global variables used by USBD-MSC class driver. */ /*Buffer for responding to GET_MAX_LUN*/ uint8_t get_max_lun_response[] __attribute__ ((aligned (4))) = {0x00u}; /* Buffer for responding to READ_FORMAT CAPACITIES command. Values will be provided by Apps. Driver Does not store Values for All the LUNs. Values of the The LUN on which last USB_MSC_SCSI_READ_FORMAT_CAPACITIES command was executed will be there in this buffer. */ uint8_t format_capacity_list[12] __attribute__ ((aligned (4))) = {0}; /* Buffer for responding to READ_CAPACITY_10 command. Values will be provided by Apps. Driver retains values for all the supported LUN and uses them to calculate valid address range for that LUN. */ mss_usbd_msc_lun_capacity_t lun_capacity[4] __attribute__ ((aligned (4)))= {{0},{0},{0},{0}}; /* Buffer to respond to USB_MSC_SCSI_MODE_SENSE_6 command. Values are generated by driver.Same values are returned for all supported LUNs. */ uint8_t mode_sense_response[4] __attribute__ ((aligned (4))) = {0x03u, 0x00u, 0x00u, 0x00u}; /* The g_sense_response is used to respond to REQUEST_SENSE request. Value of this variable is changed depending on the type of failure while responding to the host request. */ mss_usbd_msc_scsi_sense_resp_t g_sense_response __attribute__ ((aligned (4))) = {0xF0,0,0,{0},0x0b,{0},0,{0}}; /* The g_bot_cbw is used to store the current CBW sent by the the host as a BOT request. */ mss_usb_msc_cbw_t g_bot_cbw __attribute__ ((aligned (4))); /* The g_current_command_csw structure is used to provide the status of the command. The Values of the elements of this structure are updated according to the state of the driver,success/Failure of the command and type of failure. */ mss_usbd_msc_csw_t g_current_command_csw __attribute__ ((aligned (4))) = {USB_MSC_BOT_CSW_SIGNATURE, 0, 0, SCSI_COMMAND_PASS}; /*****************************************************************************/ /* Definition for Flash drive application call-backs. */ mss_usbd_msc_media_t *g_usbd_msc_media_ops; /* USB current Speed of operation selected by user*/ mss_usb_device_speed_t g_usbd_msc_user_speed; /* Global variables used for multi-transfer OUT transactions */ volatile uint8_t* g_xfr_buf_ptr = 0; volatile uint32_t g_xfr_buf_len = 0u; volatile uint64_t g_xfr_lba_addr = 0u; typedef enum scsi_req_type { SCSI_ZDR, SCSI_IN, SCSI_OUT } scsi_req_type_t; scsi_req_type_t g_req_type = SCSI_ZDR; /* The g_bot_state is used to store the current state of the driver during Bulk-only Transport (BOT) transaction. The drivers response to the host request depends on this state. */ volatile mss_usbd_msc_bot_state_t g_bot_state; /* This variable tracks the current state of the USBD-MSC driver. */ mss_usbd_msc_state_t g_usbd_msc_state = USBD_MSC_NOT_CONFIGURED; /* The g_bot_events is used to know the current event in the BOT transfer */ volatile mss_usbd_msc_bot_events_t g_bottx_events = BOT_EVENT_IDLE; volatile mss_usbd_msc_bot_events_t g_botrx_events = BOT_EVENT_IDLE; mss_usbd_class_cb_t usb_msd_class_cb = {usbd_msc_init_cb, usbd_msc_release_cb, usbd_msc_get_descriptor_cb, usbd_msc_process_request_cb, usbd_msc_tx_complete_cb, usbd_msc_rx_cb, 0, 0 }; uint8_t msc_fs_conf_descr[FULL_CONFIG_DESCR_LENGTH] = { /*----------------------- Configuration Descriptor -----------------------*/ USB_STD_CONFIG_DESCR_LEN, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ FULL_CONFIG_DESCR_LENGTH, /* wTotalLength LSB */ 0x00u, /* wTotalLength MSB */ 0x01u, /* bNumInterfaces */ 0x01u, /* bConfigurationValue */ 0x04u, /* iConfiguration */ 0xC0u, /* bmAttributes */ 0x32u, /* bMaxPower */ /*------------------------- Interface Descriptor -------------------------*/ USB_STD_INTERFACE_DESCR_LEN, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ MSC_CLASS_INTERFACE_NUM, /* bInterfaceNumber */ 0x00u, /* bAlternateSetting */ 0x02u, /* bNumEndpoints */ 0x08u, /* bInterfaceClass */ 0x06u, /* bInterfaceSubClass */ 0x50u, /* bInterfaceProtocol */ 0x05u, /* bInterface */ /*------------------------- IN Endpoint Descriptor --------------------------*/ USB_STD_ENDPOINT_DESCR_LEN, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ (0x80u | MSC_CLASS_BULK_TX_EP), /* bEndpointAddress */ 0x02u, /* bmAttributes */ 0x40u, /* wMaxPacketSize LSB */ //22 0x00u, /* wMaxPacketSize MSB */ //23 0xFFu, /* bInterval */ //ignored by host for Bulk IN EP /*------------------------- OUT Endpoint Descriptor --------------------------*/ USB_STD_ENDPOINT_DESCR_LEN, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ MSC_CLASS_BULK_RX_EP, /* bEndpointAddress */ 0x02u, /* bmAttributes */ 0x40u, /* wMaxPacketSize LSB *///29 0x00u, /* wMaxPacketSize MSB *///30 0xFFu /* bInterval *//*Max NAK rate*/ }; /* Configuration descriptor and sub-ordinate descriptors to enumerate the USB device as Mass Storage class Device by host. */ uint8_t msc_hs_conf_descr[FULL_CONFIG_DESCR_LENGTH] = { /*----------------------- Configuration Descriptor -----------------------*/ USB_STD_CONFIG_DESCR_LEN, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ FULL_CONFIG_DESCR_LENGTH, /* wTotalLength LSB */ 0x00u, /* wTotalLength MSB */ 0x01u, /* bNumInterfaces */ 0x01u, /* bConfigurationValue */ 0x04u, /* iConfiguration */ 0xC0u, /* bmAttributes */ 0x32u, /* bMaxPower */ /*------------------------- Interface Descriptor -------------------------*/ USB_STD_INTERFACE_DESCR_LEN, /* bLength */ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ MSC_CLASS_INTERFACE_NUM, /* bInterfaceNumber */ 0x00u, /* bAlternateSetting */ 0x02u, /* bNumEndpoints */ 0x08u, /* bInterfaceClass */ 0x06u, /* bInterfaceSubClass */ 0x50u, /* bInterfaceProtocol */ 0x05u, /* bInterface */ /*------------------------- IN Endpoint Descriptor --------------------------*/ USB_STD_ENDPOINT_DESCR_LEN, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ (0x80u | MSC_CLASS_BULK_TX_EP), /* bEndpointAddress */ 0x02u, /* bmAttributes */ 0x00u, /* wMaxPacketSize LSB */ //22 0x02u, /* wMaxPacketSize MSB */ //23 0xFFu, /* bInterval *///ignored by host for Bulk IN EP /*------------------------- OUT Endpoint Descriptor --------------------------*/ USB_STD_ENDPOINT_DESCR_LEN, /* bLength */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ MSC_CLASS_BULK_RX_EP, /* bEndpointAddress */ 0x02u, /* bmAttributes */ 0x00u, /* wMaxPacketSize LSB *///29 0x02u, /* wMaxPacketSize MSB *///30 0xFFu /* bInterval */ /*Max NAK rate*/ }; void MSS_USBD_MSC_init ( mss_usbd_msc_media_t* media_ops, mss_usb_device_speed_t speed ) { g_usbd_msc_media_ops = media_ops; g_usbd_msc_user_speed = speed; MSS_USBD_set_class_cb_handler(&usb_msd_class_cb); } mss_usbd_msc_state_t MSS_USBD_MSC_get_state ( void ) { return g_usbd_msc_state; } /***************************************************************************//** returns the configuration descriptor requested by Host. */ static uint8_t* usbd_msc_get_descriptor_cb ( uint8_t recipient, uint8_t type, uint32_t* length, mss_usb_device_speed_t musb_speed ) { uint8_t* conf_desc = 0; uint8_t* os_conf_desc = 0; uint8_t conf_desc_len = 0u; uint8_t os_conf_desc_len = 0u; /*User Selected FS: Operate only in FS User Selected HS: Device connected to 2.0 Host(musb_speed = HS):Operate in HS Device connected to 1.x Host(musb_speed = FS):Operate in FS */ if (MSS_USB_DEVICE_FS == g_usbd_msc_user_speed) { conf_desc = msc_fs_conf_descr; conf_desc[MSCD_CONF_DESCR_DESCTYPE_IDX] = USB_CONFIGURATION_DESCRIPTOR_TYPE; conf_desc_len = sizeof(msc_fs_conf_descr); os_conf_desc = 0u; os_conf_desc_len = 0u; } else if (MSS_USB_DEVICE_HS == g_usbd_msc_user_speed) { if (MSS_USB_DEVICE_HS == musb_speed) { conf_desc = msc_hs_conf_descr; conf_desc[MSCD_CONF_DESCR_DESCTYPE_IDX] = USB_CONFIGURATION_DESCRIPTOR_TYPE; conf_desc_len = sizeof(msc_hs_conf_descr); os_conf_desc = msc_fs_conf_descr; os_conf_desc[MSCD_CONF_DESCR_DESCTYPE_IDX] = USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE; os_conf_desc_len = sizeof(msc_fs_conf_descr); } else if (MSS_USB_DEVICE_FS == musb_speed) { conf_desc = msc_fs_conf_descr; conf_desc[MSCD_CONF_DESCR_DESCTYPE_IDX] = USB_CONFIGURATION_DESCRIPTOR_TYPE; conf_desc_len = sizeof(msc_fs_conf_descr); os_conf_desc = msc_hs_conf_descr; os_conf_desc[MSCD_CONF_DESCR_DESCTYPE_IDX] = USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE; os_conf_desc_len = sizeof(msc_hs_conf_descr); } } else { ASSERT(0); //user must select FS or HS, nothing else. } if (USB_STD_REQ_RECIPIENT_DEVICE == recipient) { if (USB_CONFIGURATION_DESCRIPTOR_TYPE == type) { *length = conf_desc_len; return (conf_desc); } else if (USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE == type) { ASSERT(os_conf_desc != NULL); *length = os_conf_desc_len; return (os_conf_desc); } } else if (USB_STD_REQ_RECIPIENT_ENDPOINT == recipient) /*Need index(EP Num) here*/ { /*Do nothing*/ } else if (USB_STD_REQ_RECIPIENT_INTERFACE == recipient) /*Need index(interface number) here*/ { /*Do nothing*/ } else { /*Do nothing*/ } return USB_FAIL; } /***************************************************************************//** usbd_msc_init_cb() call-back is called by USB Device mode driver on receiving SET_CONFIGURATION command. The MSC class specific configurations are performed by this function. */ static uint8_t usbd_msc_init_cb( uint8_t cfgidx, mss_usb_device_speed_t musb_speed) { uint16_t bulk_rxep_fifo_sz = 0u; uint16_t bulk_rxep_maxpktsz = 0u; uint16_t bulk_txep_fifo_sz = 0u; uint16_t bulk_txep_maxpktsz = 0u; g_bottx_events = BOT_EVENT_IDLE; g_botrx_events = BOT_EVENT_IDLE; g_bot_state = BOT_IDLE; g_current_command_csw.data_residue = 0u; g_current_command_csw.tag = 0u; g_current_command_csw.status = SCSI_COMMAND_FAIL; G_BOT_CBW_INIT(); g_xfr_buf_ptr = 0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; /* User Selected FS: Operate only in FS User Selected HS: Device connected to 2.0 Host(musb_speed = HS):Operate in HS Device connected to 1.x Host(musb_speed = FS):Operate in FS */ /* We calculate the Bulk endpoint sizes and max_pkt_size based on the respective endpoint speed. This is done so that the config descriptor change reflects here and this function need not be updated for that. */ if (MSS_USB_DEVICE_FS == musb_speed) { bulk_txep_fifo_sz = (uint16_t)((msc_fs_conf_descr[23u] << 8u) | (msc_fs_conf_descr[22u])); bulk_txep_maxpktsz = (uint16_t)((msc_fs_conf_descr[23u] << 8u) | (msc_fs_conf_descr[22u])); bulk_rxep_fifo_sz = (uint16_t)((msc_fs_conf_descr[30u] << 8u) | (msc_fs_conf_descr[29u])); bulk_rxep_maxpktsz = (uint16_t)((msc_fs_conf_descr[30u] << 8u) | (msc_fs_conf_descr[29u])); } else if (MSS_USB_DEVICE_HS == musb_speed) { bulk_txep_fifo_sz = (uint16_t)((msc_hs_conf_descr[23u] << 8u) | (msc_hs_conf_descr[22u])); bulk_txep_maxpktsz = (uint16_t)((msc_hs_conf_descr[23u] << 8u) | (msc_hs_conf_descr[22u])); bulk_rxep_fifo_sz = (uint16_t)((msc_hs_conf_descr[30u] << 8u) | (msc_hs_conf_descr[29u])); bulk_rxep_maxpktsz = (uint16_t)((msc_hs_conf_descr[30u] << 8u) | (msc_hs_conf_descr[29u])); } else { ASSERT(0); /*speed value can not be any other than FS or HS*/ } MSS_USBD_rx_ep_configure(MSC_CLASS_BULK_RX_EP, 0x100u, bulk_rxep_fifo_sz, bulk_rxep_maxpktsz, 1u, DMA_DISABLE, MSS_USB_DMA_CHANNEL1, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR); MSS_USBD_rx_ep_read_prepare(MSC_CLASS_BULK_RX_EP, (uint8_t*)&g_bot_cbw, USBD_MSC_BOT_CBW_LENGTH); MSS_USBD_tx_ep_configure(MSC_CLASS_BULK_TX_EP, 0x300u, bulk_txep_fifo_sz, bulk_txep_maxpktsz, 1u, DMA_DISABLE, MSS_USB_DMA_CHANNEL2, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR); g_usbd_msc_state = USBD_MSC_CONFIGURED; if (0 != g_usbd_msc_media_ops->media_init) { g_usbd_msc_media_ops->media_init(0);/*Todo:Remove the lun parameter*/ } return USB_SUCCESS; } /***************************************************************************//** usbd_msc_release_cb() call-back is called by USB Device mode driver on receiving a command to clear the configuration. */ static uint8_t usbd_msc_release_cb(uint8_t cfgidx) { g_usbd_msc_state = USBD_MSC_NOT_CONFIGURED; MSS_USB_CIF_tx_ep_disable_irq(MSC_CLASS_BULK_TX_EP); MSS_USB_CIF_tx_ep_clr_csrreg(MSC_CLASS_BULK_TX_EP); MSS_USB_CIF_dma_clr_ctrlreg(MSS_USB_DMA_CHANNEL2); MSS_USB_CIF_rx_ep_disable_irq(MSC_CLASS_BULK_RX_EP); MSS_USB_CIF_rx_ep_clr_csrreg(MSC_CLASS_BULK_RX_EP); MSS_USB_CIF_dma_clr_ctrlreg(MSS_USB_DMA_CHANNEL1); if (0 != g_usbd_msc_media_ops->media_release) { g_usbd_msc_media_ops->media_release(cfgidx); } return USB_SUCCESS; } /***************************************************************************//** usbd_msc_process_request_cb() call-back function Process the MSC class requests. */ static uint8_t usbd_msc_process_request_cb( mss_usbd_setup_pkt_t* setup_pkt, uint8_t** buf_pp, uint32_t* length) { if ((MSC_CLASS_INTERFACE_NUM == setup_pkt->index) && (0u == setup_pkt->value)) { switch(setup_pkt->request) { case USB_MSC_BOT_REQ_GET_MAX_LUN: /*Return the max LUN index, not the actual number of LUNs*/ ASSERT(g_usbd_msc_media_ops->media_get_max_lun != NULL); if (0 != g_usbd_msc_media_ops->media_get_max_lun) { get_max_lun_response[0] = (g_usbd_msc_media_ops->media_get_max_lun() - 1u); } *length = sizeof(get_max_lun_response); *buf_pp = (uint8_t*)&get_max_lun_response; return USB_SUCCESS; case USB_MSC_BOT_REQ_BMS_RESET: if (0u == setup_pkt->length) { /* LVp:62 - prepare for next CBW. Don't change the stall and Data toggle bit on Bulk EPs. */ g_bottx_events = BOT_EVENT_IDLE; g_botrx_events = BOT_EVENT_IDLE; g_bot_state = BOT_IDLE; g_current_command_csw.data_residue = 0u; g_current_command_csw.tag = 0u; g_current_command_csw.status = SCSI_COMMAND_FAIL; G_BOT_CBW_INIT(); g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; MSS_USBD_rx_ep_read_prepare(MSC_CLASS_BULK_RX_EP, (uint8_t*)&g_bot_cbw, USBD_MSC_BOT_CBW_LENGTH); return USB_SUCCESS; } else { return USB_FAIL; } default: length = 0u; return USB_FAIL; } } else { return USB_FAIL; } } /***************************************************************************//** usbd_msc_tx_complete_cb() call-back function is called by USB Device mode driver on completion of the Current Data Transmissions (IN Transaction) which was previously initiated using MSS_USBD_tx_ep_configure(). */ static uint8_t usbd_msc_tx_complete_cb(mss_usb_ep_num_t num, uint8_t status) { /*Underrun error ignore, it only means we are slow and that is because of the slow serial flash memory*/ if (status & (TX_EP_STALL_ERROR)) { g_bottx_events = BOT_EVENT_TX_ERROR; } else { g_bottx_events = BOT_EVENT_TX; } usbd_msc_bot_fsm(status, 0u); return USB_SUCCESS; } /***************************************************************************//** usbd_msc_rx_cb() call-back function is called by USB Device mode driver on completion of data reception. USB Device mode driver must have been previously prepared for this data reception using MSS_USBD_rx_ep_read_prepare() */ static uint8_t usbd_msc_rx_cb(mss_usb_ep_num_t num, uint8_t status, uint32_t rx_count) { /* 4.3.5.6 xfr length > Allocation length field ==> Terminate with CHECK CONDITION status, sense key = ILLEGAL_REQUEST, additional sense code = INVALID FIELD in CDB when NACA bit = 0 ==> ACA condition is not set = command abort should be done as per sam-5, 5.8.2 */ if (status & (RX_EP_OVER_RUN_ERROR | RX_EP_STALL_ERROR | RX_EP_DATA_ERROR | RX_EP_PID_ERROR | RX_EP_ISO_INCOMP_ERROR)) { g_botrx_events = BOT_EVENT_RX_ERROR; } else { g_botrx_events = BOT_EVENT_RX; } usbd_msc_bot_fsm(status, rx_count); return USB_SUCCESS; } /***************************************************************************//** usbd_msc_bot_fsm() function is the state machine for BOT transfers. */ static void usbd_msc_bot_fsm(uint8_t status, uint32_t rx_count) { uint8_t cb_result = CB_INTERNAL_ERROR; switch (g_bot_state) { case BOT_IDLE: if (BOT_EVENT_RX == g_botrx_events) { if (rx_count != USBD_MSC_BOT_CBW_LENGTH ) { g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); } else { cb_result = usbd_msc_process_cbw(&g_bot_cbw); g_current_command_csw.data_residue = g_bot_cbw.xfr_length; switch(cb_result) { case CB_PASS: g_current_command_csw.status = SCSI_COMMAND_PASS; if (g_req_type == SCSI_OUT) { //CASE:12 (Success) usbd_msc_receive_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } else if (g_req_type == SCSI_IN) { //CASE:6 (Success) usbd_msc_send_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } else if (g_req_type == SCSI_ZDR) { //CASE:1 (Success) usbd_msc_send_csw(); } else { ASSERT(0); /*invalid req_type value*/ } break; case CB_LESSDATA: g_current_command_csw.status = SCSI_COMMAND_LESSDATAPASS; if (SCSI_OUT == g_req_type) { if (g_xfr_buf_len) { //CASE11(lvr:dont stall this) usbd_msc_receive_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } else { //CASE9-This needs to be cross-checked usbd_msc_stallin_sendstatus(); } } else if (SCSI_IN == g_req_type) { if (g_xfr_buf_len) { //CASE5: send a stall and status after dataPhase. usbd_msc_send_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } else { //CASE4 usbd_msc_stallin_sendstatus(); } } else { ASSERT(0);/*invalid req_type value*/ } break; case CB_MOREDATA: if (SCSI_OUT == g_req_type ) { if (g_xfr_buf_len) { //CASE13 g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_stallout_sendstatus(); } else { ASSERT(0); //shouldn't happen } } else if (SCSI_IN == g_req_type) { //CASE7 stall then send status g_current_command_csw.status = SCSI_COMMAND_FAIL; usbd_msc_stallin_sendstatus(); } else { ASSERT(0); } break; case CB_INVALID_CDB_FIELD: /*No data, only stall*/ g_current_command_csw.status = SCSI_COMMAND_FAIL; usbd_msc_stallin_sendstatus(); break; case CB_NOT_SUPPORTED: /*Command Not supported.*/ g_current_command_csw.status = SCSI_COMMAND_FAIL; if (0 == g_bot_cbw.xfr_length) { usbd_msc_stallin_sendstatus(); } else { if (g_bot_cbw.flags & 0x80u) //IN D2H { usbd_msc_stallin_sendstatus(); } else //OUT H2D { usbd_msc_stallout_sendstatus(); usbd_msc_stallin_sendstatus(); } } break; case CB_INTERNAL_ERROR: /*Dont respond till reset recovery*/ g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); break; case CB_LENGTH_MISMATCH: if (SCSI_OUT == g_req_type) { if (0u == g_xfr_buf_len) { g_current_command_csw.status = SCSI_COMMAND_FAIL; usbd_msc_stallout_sendstatus(); } else if (g_xfr_buf_len > g_bot_cbw.xfr_length) { //CASE13 g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_stallout_sendstatus(); } else { //CASE11(lvr:dont stall this) g_current_command_csw.status = SCSI_COMMAND_FAIL; usbd_msc_receive_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } } else if (SCSI_IN == g_req_type) { if (0u == g_xfr_buf_len) { g_current_command_csw.status = SCSI_COMMAND_FAIL; usbd_msc_stallout_sendstatus(); } else if (g_xfr_buf_len > g_bot_cbw.xfr_length) { //CASE7 stall then send status g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_stallin_sendstatus(); } else { g_current_command_csw.status = SCSI_COMMAND_FAIL; usbd_msc_send_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } } else { g_current_command_csw.status = SCSI_COMMAND_FAIL; if (g_bot_cbw.flags & 0x80u) { usbd_msc_stallin_sendstatus(); } else { g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); } } break; case CB_DATA_DIR_MISMATCH: g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_stallin_sendstatus(); break; case CB_INVALID_CBW: /*Don't respond till reset recovery*/ g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); break; default: /*Don't respond till reset recovery*/ g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); //Internal Error break; } } } else { ASSERT(0); } break; case BOT_DATA_TX: if (BOT_EVENT_TX == g_bottx_events) /* Data TX from Device*/ { if (SCSI_COMMAND_LESSDATAPASS == g_current_command_csw.status) { g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; g_current_command_csw.status = SCSI_COMMAND_PASS; usbd_msc_stallin_sendstatus(); } else if (SCSI_COMMAND_PASS == g_current_command_csw.status) { if (g_current_command_csw.data_residue >= g_xfr_buf_len) { g_current_command_csw.data_residue -= g_xfr_buf_len; } else { ASSERT(0);/*corrupt/invalid data_residue value*/ } if (0u == g_current_command_csw.data_residue) { g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; g_current_command_csw.status = SCSI_COMMAND_PASS; usbd_msc_send_csw(); } else { /* Control reaches here because previous App read operation returned less Data than requested by host.Read rest of the data now. */ uint32_t actual_read_len; uint8_t* buf; if (0 != g_usbd_msc_media_ops->media_read) { g_xfr_lba_addr += g_xfr_buf_len; actual_read_len = g_usbd_msc_media_ops->media_read(g_bot_cbw.lun, &buf, g_xfr_lba_addr, g_current_command_csw.data_residue); if (actual_read_len > g_current_command_csw.data_residue) { ASSERT(0);/*App should not read more data than asked for*/ } else { g_xfr_buf_ptr = buf; g_xfr_buf_len = actual_read_len; g_current_command_csw.status = SCSI_COMMAND_PASS; usbd_msc_send_data(buf, g_xfr_buf_len); } } else { g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); //Internal Error } } } else if (SCSI_COMMAND_FAIL == g_current_command_csw.status) { g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; usbd_msc_stallin_sendstatus(); } else { ASSERT(0); //should never come there with Phase Error status } } else if (BOT_EVENT_TX_ERROR == g_bottx_events) { /* Stall Error*/ if (status & TX_EP_STALL_ERROR) { ASSERT(0); //should never get a stall in this state } } else { ASSERT(0);/*corrupt g_bottx_events value*/ } break; case BOT_DATA_RX: if (BOT_EVENT_RX == g_botrx_events) { if (SCSI_COMMAND_LESSDATAPASS == g_current_command_csw.status) { g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; g_current_command_csw.status = SCSI_COMMAND_PASS; usbd_msc_stallin_sendstatus(); } else if (SCSI_COMMAND_PASS == g_current_command_csw.status) { uint8_t result = CB_DATAPHASE_ERROR; if (g_current_command_csw.data_residue >= g_xfr_buf_len) { g_current_command_csw.data_residue -= g_xfr_buf_len; } else { ASSERT(0);/*corrupt/invalid data_residue value*/ } /*Write the received data on flash*/ if (rx_count == g_xfr_buf_len) { result = CB_PASS; } else { result = CB_DATAPHASE_ERROR; } if (0 != g_usbd_msc_media_ops->media_write_ready) { g_usbd_msc_media_ops->media_write_ready(g_bot_cbw.lun, g_xfr_lba_addr, g_xfr_buf_len); result = CB_PASS; } else { result = CB_DATAPHASE_ERROR; } if (CB_PASS == result) { /* data_residue == 0 means we are done with current Data phase of OUT transaction, send the status. */ if (0u == g_current_command_csw.data_residue) { g_xfr_buf_ptr = 0; // Data end. g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; g_current_command_csw.status = SCSI_COMMAND_PASS; usbd_msc_send_csw(); } else { uint32_t app_write_len = 0u; uint8_t* write_buf = (uint8_t*) 0; /* Data phase of current OUT transaction is still in progress. Prepare to write more data on flash */ g_xfr_lba_addr += g_xfr_buf_len; if (0 != g_usbd_msc_media_ops->media_acquire_write_buf) write_buf = g_usbd_msc_media_ops->media_acquire_write_buf(g_bot_cbw.lun, g_xfr_lba_addr, &app_write_len); /* If application buffer is not big enough to handle all requested data from Host,then read amount of data that the application can handle at the moment. */ if (app_write_len < g_current_command_csw.data_residue) { g_xfr_buf_len = app_write_len; } else { g_xfr_buf_len = g_current_command_csw.data_residue; } g_xfr_buf_ptr = write_buf; g_current_command_csw.status = SCSI_COMMAND_PASS; usbd_msc_receive_data((uint8_t *)g_xfr_buf_ptr, g_xfr_buf_len); } } else { g_current_command_csw.status = SCSI_COMMAND_PHASE_ERR; usbd_msc_abort_cbw(0u); //Internal Error } } else if (SCSI_COMMAND_FAIL == g_current_command_csw.status) { g_xfr_buf_ptr = 0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; usbd_msc_send_csw(); } } else if (BOT_EVENT_RX_ERROR == g_botrx_events) { /* Stall Error*/ if (status & 0x02u) { ASSERT(0); //should never get a stall in this state } } else { ASSERT(0); //invalid g_botrx_events } break; case BOT_SEND_STATUS: if (BOT_EVENT_TX == g_bottx_events) { G_BOT_CBW_INIT(); g_current_command_csw.data_residue = 0u; g_current_command_csw.tag = 0u; g_current_command_csw.status = SCSI_COMMAND_FAIL; g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; g_bot_state = BOT_IDLE; /*Prepare to receive next command*/ MSS_USBD_rx_ep_read_prepare(MSC_CLASS_BULK_RX_EP, (uint8_t*)&g_bot_cbw, USBD_MSC_BOT_CBW_LENGTH); } else if (BOT_EVENT_TX_ERROR == g_bottx_events) { /* Stall Error*/ if (status & TX_EP_STALL_ERROR) { if (g_current_command_csw.status == SCSI_COMMAND_LESSDATAPASS) { g_current_command_csw.status = SCSI_COMMAND_PASS; } usbd_msc_send_csw(); } } break; case BOT_ABORTED: { g_bot_state = BOT_ABORTED; usbd_msc_abort_cbw(0u); } break; default: { ASSERT(0); //invalid BOT state } break; } g_bottx_events = BOT_EVENT_IDLE; g_botrx_events = BOT_EVENT_IDLE; } /***************************************************************************//** usbd_msc_process_cbw() function decodes current command sent by host in CBW, and Processes the command. If the command was valid and meaningful, it asks for required information from application and returns the status. If the Command was invalid or is not processed by this driver, it returns the Failure status. */ static uint8_t usbd_msc_process_cbw(mss_usb_msc_cbw_t * cbw) { uint8_t cbw_command = cbw->cmd_block[0]; uint8_t result = CB_PASS; g_current_command_csw.tag = cbw->tag; /* Check for valid cbw 1) CBW received after csw or reset 2) cbw is 32 bytes 3) Signature is correct CBW is meaningful if all reserved bytes are zero Lun value is supported CBWCBLength and cbwcb are valid for the interface subclass. No. Max LUN index provided by App in get_max_lun request. */ if ((cbw->signature != USB_MSC_BOT_CBW_SIGNATURE) || (cbw->lun > get_max_lun_response[0]) || (cbw->cmd_length < 1) || (cbw->cmd_length > 16)) { result = CB_INVALID_CBW; } else { if (g_current_command_csw.data_residue != 0u) { ASSERT(0); } switch(cbw_command) { case USB_MSC_SCSI_INQUIRY: result = usbd_msc_process_inquiry(); break; case USB_MSC_SCSI_READ_CAPACITY_10:/*returns last LBA and block size*/ result = usbd_msc_process_read_capacity_10(); break; case USB_MSC_SCSI_READ_FORMAT_CAPACITIES:/*Returns no. of blocks and block size*/ { uint32_t no_of_blocks = 0u; uint32_t block_size = 0u; uint32_t dev_data_len = 0u; dev_data_len = ((g_bot_cbw.cmd_block[7u] << 8u) | g_bot_cbw.cmd_block[8u]); if (0 != g_usbd_msc_media_ops->media_get_capacity) { g_usbd_msc_media_ops->media_get_capacity(cbw->lun, (uint32_t*)&no_of_blocks, (uint32_t*)&block_size); } format_capacity_list [4u] = (uint8_t)(no_of_blocks >> 24u); format_capacity_list [5u] = (uint8_t)(no_of_blocks >> 16u); format_capacity_list [6u] = (uint8_t)(no_of_blocks >> 8u); format_capacity_list [7u] = (uint8_t)(no_of_blocks); /* format_capacity_list [8] = Descriptor Code*/ format_capacity_list [9u] = (uint8_t)(block_size >> 16u); format_capacity_list [10u] = (uint8_t)(block_size >> 8u); format_capacity_list [11u] = (uint8_t)(block_size); g_req_type = SCSI_IN; g_xfr_buf_ptr = (uint8_t*)format_capacity_list; g_xfr_buf_len = sizeof(format_capacity_list); usbd_msc_prepare_sense_data(cbw->lun, SC_ILLEGAL_REQUEST, ASC_INVALID_CDB); if (g_xfr_buf_len < dev_data_len) { result = CB_LESSDATA; } else if (g_xfr_buf_len > dev_data_len) { result = CB_LESSDATA; } else { result = CB_PASS; } } break; case USB_MSC_SCSI_READ_10: result = usbd_msc_process_read_10(); break; case USB_MSC_SCSI_MODE_SENSE_6: { uint32_t dev_data_len =0; dev_data_len = g_bot_cbw.cmd_block[4u]; g_req_type = SCSI_IN; g_xfr_buf_ptr = mode_sense_response; g_xfr_buf_len = sizeof(mode_sense_response); if (dev_data_len > g_xfr_buf_len) { result = CB_LESSDATA; } else if (dev_data_len < g_xfr_buf_len) { result = CB_MOREDATA; } else { result = CB_PASS; } } break; case USB_MSC_SCSI_REQUEST_SENSE: { uint32_t dev_data_len =0; dev_data_len = g_bot_cbw.cmd_block[4u]; if (g_bot_cbw.cmd_block[1u] & 0x01u)//DESC bit 0 - only fixed format is supported { return (CB_INVALID_CDB_FIELD); } /*SPC-4, table 39*/ g_req_type = SCSI_IN; g_xfr_buf_ptr = (uint8_t*)&g_sense_response; if (0 == dev_data_len) { result = CB_LESSDATA; g_xfr_buf_len = dev_data_len; } else if (dev_data_len > (sizeof(g_sense_response))) { g_xfr_buf_len = dev_data_len; result = CB_MOREDATA; } else { g_xfr_buf_len = dev_data_len; result = CB_PASS; } } break; case USB_MSC_SCSI_WRITE_10: result = usbd_msc_process_write_10(); break; case USB_MSC_SCSI_TEST_UNIT_READY: g_req_type = SCSI_ZDR; g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; /*Fail if DataTransferLength and Allocation length in CBW are mismatched*/ if (0 != g_bot_cbw.xfr_length) { result = CB_LENGTH_MISMATCH; } else { result = CB_PASS; } break; case USB_MSC_SCSI_VERIFY_10: g_req_type = SCSI_ZDR; g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; /*Fail if DataTransferLength and Allocation length in CBW are mismatched*/ if (0 != g_bot_cbw.xfr_length) { result = CB_LENGTH_MISMATCH; } else { result = CB_PASS; } break; default: result = CB_NOT_SUPPORTED; g_req_type = SCSI_IN; g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; usbd_msc_prepare_sense_data(cbw->lun, SC_ILLEGAL_REQUEST, ASC_INVALID_FIELED_IN_COMMAND); break; } } return result; } /***************************************************************************//** usbd_msc_prepare_sense_data() function prepares sense information required by the host in case there was an error in processing CBW. This information is sent as response to REQUEST_SENSE command. */ static void usbd_msc_prepare_sense_data(uint8_t lun, uint8_t skey, uint8_t asc) { g_sense_response.sense_key = skey; g_sense_response.asc = asc; } /***************************************************************************//** usbd_msc_abort_cbw() function aborts the current command CBW.and prepares the driver to receive new CBW from HOST. */ static void usbd_msc_abort_cbw(uint8_t lun) { g_bot_state = BOT_ABORTED; /* Don't respond to anything from host on Bulk IN or OUT Endpoint. Reset Recovery request is mandatory now. */ MSS_USBD_tx_ep_stall(MSC_CLASS_BULK_TX_EP); MSS_USBD_rx_ep_stall(MSC_CLASS_BULK_RX_EP); } /***************************************************************************//** usbd_msc_send_data() function send data to the host (DATA phase of IN transactions) in response to current CBW command. */ static void usbd_msc_send_data(uint8_t* buf, uint32_t len) { /*TODO: check if the length can be accommodated in EP buffer*/ g_bot_state = BOT_DATA_TX; MSS_USBD_tx_ep_write(MSC_CLASS_BULK_TX_EP, buf, len); } static void usbd_msc_stallin_sendstatus(void) { g_bot_state = BOT_SEND_STATUS; MSS_USBD_tx_ep_stall(MSC_CLASS_BULK_TX_EP); } static void usbd_msc_stallout_sendstatus(void) { g_bot_state = BOT_SEND_STATUS; MSS_USBD_rx_ep_stall(MSC_CLASS_BULK_RX_EP); } /***************************************************************************//** usbd_msc_receive_data() function prepares the driver to receive data from USB host (DATA phase of OUT transactions) in response to the current CBW command. */ static void usbd_msc_receive_data(uint8_t* buf, uint32_t len) { g_bot_state = BOT_DATA_RX; MSS_USBD_rx_ep_read_prepare(MSC_CLASS_BULK_RX_EP, (uint8_t *)g_xfr_buf_ptr, len); } /***************************************************************************//** usbd_msc_send_csw() function sends status information to USB host (DATA phase of IN transactions), indicating the Success/Failure status of the current CBW command. */ static void usbd_msc_send_csw(void) { g_bot_state = BOT_SEND_STATUS; MSS_USBD_tx_ep_write(MSC_CLASS_BULK_TX_EP, (uint8_t*)&g_current_command_csw, USBD_MSC_BOT_CSW_LENGTH); } volatile uint64_t capture_dev_data_len = 0u; /***************************************************************************//** usbd_msc_process_read_10() function processes read command and calls application call-back function to read data from media. */ static uint8_t usbd_msc_process_read_10(void) { uint32_t app_read_len = 0u; uint32_t lba = 0u; uint64_t lba_addr = 0u; uint8_t* buf = 0; uint32_t dev_data_len = 0u; uint8_t cb_res = CB_PASS; g_xfr_lba_addr = 0u; g_req_type = SCSI_IN; /*Lba address is in command block byte 2 to 4 with MSB first.*/ lba = (g_bot_cbw.cmd_block[2u] << 24u) | (g_bot_cbw.cmd_block[3u] << 16u) | (g_bot_cbw.cmd_block[4u] << 8u) | g_bot_cbw.cmd_block[5u]; /*Block size was received in USB_MSC_SCSI_READ_CAPACITY_10 command*/ lba_addr = ((uint64_t)lba * lun_capacity[g_bot_cbw.lun].blk_sz_len); /* Number of LBAs to be read is provided in command block byte 7 to 8, calculate the total size to be read */ dev_data_len = ((g_bot_cbw.cmd_block[7u] << 8u) | g_bot_cbw.cmd_block[8u]) * lun_capacity[g_bot_cbw.lun].blk_sz_len; if (lba_addr > capture_dev_data_len) capture_dev_data_len = lba_addr; /*Data Direction must be D2H (IN)*/ if (!(g_bot_cbw.flags & 0x80u)) { g_xfr_buf_len = dev_data_len; cb_res = CB_DATA_DIR_MISMATCH; } /*Fail if DataTransferLength and Allocation length in CBW are mismatched*/ if (dev_data_len != g_bot_cbw.xfr_length) { cb_res = CB_LENGTH_MISMATCH; } if (0 == g_usbd_msc_media_ops->media_read) { cb_res = CB_INTERNAL_ERROR; } if (CB_PASS == cb_res) { if (0 != g_usbd_msc_media_ops->media_read) { app_read_len = g_usbd_msc_media_ops->media_read(g_bot_cbw.lun, &buf, lba_addr, dev_data_len); } if ((uint8_t*)0 == buf) { cb_res = CB_INTERNAL_ERROR; } else { cb_res = CB_PASS; g_xfr_buf_ptr = buf; if (app_read_len < dev_data_len) { g_xfr_buf_len = app_read_len; } else { g_xfr_buf_len = dev_data_len; } /* Store the current LBA address so that it will be used to calculate new LBA address when remaining data is read from flash. */ g_xfr_lba_addr = lba_addr; } } if (CB_PASS != cb_res) { g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; } return (cb_res); } /***************************************************************************//** usbd_msc_process_write_10() function processes Write command and calls application call-back function to acquire a buffer where the data will be receive. */ static uint8_t usbd_msc_process_write_10(void) { uint32_t lba = 0u; uint64_t lba_addr = 0u; uint8_t* write_buf; uint32_t app_write_len = 0u; uint32_t dev_data_len = 0u; uint8_t cb_res = CB_PASS; g_req_type = SCSI_OUT; g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; /*Lba address is in command block byte 2 to 4 with MSB first.*/ lba = (g_bot_cbw.cmd_block[2u] << 24u) | (g_bot_cbw.cmd_block[3u] << 16u) | (g_bot_cbw.cmd_block[4u] << 8u) | g_bot_cbw.cmd_block[5u]; /*Block size was received in USB_MSC_SCSI_READ_CAPACITY_10 command*/ lba_addr = ((uint64_t)lba * lun_capacity[g_bot_cbw.lun].blk_sz_len); /* Number of LBA to be written is provided in command block byte 7 to 8, calculate the total size to be written */ dev_data_len = ((g_bot_cbw.cmd_block[7] << 8u) | g_bot_cbw.cmd_block[8u]) * lun_capacity[g_bot_cbw.lun].blk_sz_len; /*Data Direction must be H2D (OUT)*/ if (g_bot_cbw.flags & 0x80u) { g_xfr_buf_len = dev_data_len; cb_res = CB_DATA_DIR_MISMATCH; } /*Fail if DataTransferLength and Allocation length in CBW are mismatched*/ if (dev_data_len != g_bot_cbw.xfr_length) { cb_res = CB_LENGTH_MISMATCH; } if (0 == g_usbd_msc_media_ops->media_acquire_write_buf) { cb_res = CB_INTERNAL_ERROR; } if (CB_PASS == cb_res) { write_buf = g_usbd_msc_media_ops->media_acquire_write_buf(g_bot_cbw.lun, lba_addr, &app_write_len); if (write_buf == (uint8_t*)0) { cb_res = CB_INTERNAL_ERROR; } else { cb_res = CB_PASS; /* Since App is not capable of handling all data at the moment. Store the current LBA address so that it will be used to calculate new LBA address when remaining data is received. */ g_xfr_lba_addr = lba_addr; g_xfr_buf_ptr = write_buf; /* If application buffer is not big enough to handle all requested data from Host, then read the amount of data that the application can handle at the moment */ if (app_write_len < dev_data_len) { g_xfr_buf_len = app_write_len; } else { g_xfr_buf_len = dev_data_len; } } } if (CB_PASS != cb_res) { g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; g_xfr_lba_addr = 0u; } return (cb_res); } static uint8_t usbd_msc_process_inquiry(void) { uint32_t dev_data_len = 0u; uint8_t* buf = (uint8_t*)0; uint32_t app_data_len; g_req_type = SCSI_IN; g_xfr_buf_ptr = (uint8_t*)0; g_xfr_buf_len = 0u; dev_data_len = ((g_bot_cbw.cmd_block[3u] << 8u) | g_bot_cbw.cmd_block[4u]); /*Data Direction must be D2H (IN)*/ if (!(g_bot_cbw.flags & 0x80u)) { g_xfr_buf_len = dev_data_len; return (CB_DATA_DIR_MISMATCH); } /*Fail if DataTransferLength and Allocation length in CBW are mismatched*/ if (dev_data_len != g_bot_cbw.xfr_length) { return (CB_LENGTH_MISMATCH); } /*If EVPD is zero then Page code must be zero*/ if ((!(g_bot_cbw.cmd_block[1u] & 0x01u)) && (g_bot_cbw.cmd_block[1u])) { return (CB_INVALID_CDB_FIELD); } if (0 == g_usbd_msc_media_ops->media_inquiry) { return (CB_INTERNAL_ERROR); } if (0 != g_usbd_msc_media_ops->media_inquiry) { buf = g_usbd_msc_media_ops->media_inquiry(g_bot_cbw.lun, &app_data_len); } if ((uint8_t*)0 == buf) { return (CB_INTERNAL_ERROR); } else { g_xfr_buf_ptr = buf; if (dev_data_len <= app_data_len) { g_xfr_buf_len = dev_data_len; return (CB_PASS); } else { g_xfr_buf_len = app_data_len; return (CB_LESSDATA); } } } static uint8_t usbd_msc_process_read_capacity_10(void) { uint32_t no_of_blocks = 0u, block_size = 0u; /* Returns last block address and block size Last_blk_lba = no_of_blocks-1 */ g_xfr_buf_ptr = (uint8_t*)NULL; g_xfr_buf_len = 0u; g_req_type = SCSI_IN; /*Data Direction must be D2H (IN)*/ if (!(g_bot_cbw.flags & 0x80u)) { g_xfr_buf_len = 8u; return (CB_DATA_DIR_MISMATCH); } /*PMI bit set to one is not supported*/ if (g_bot_cbw.cmd_block[8u] & 0x01u) { return (CB_INVALID_CDB_FIELD); } if (0 == g_usbd_msc_media_ops->media_get_capacity) { return (CB_INTERNAL_ERROR); } if (0 != g_usbd_msc_media_ops->media_get_capacity) { g_usbd_msc_media_ops->media_get_capacity(g_bot_cbw.lun, (uint32_t*)&no_of_blocks, (uint32_t*)&block_size); } lun_capacity[g_bot_cbw.lun].last_lba_msb = (uint8_t)((no_of_blocks - 1u) >> 24u); lun_capacity[g_bot_cbw.lun].last_lba_2 = (uint8_t)((no_of_blocks - 1u) >> 16u); lun_capacity[g_bot_cbw.lun].last_lba_1 = (uint8_t)((no_of_blocks - 1u) >> 8u); lun_capacity[g_bot_cbw.lun].last_lba_lsb = (uint8_t)((no_of_blocks - 1u)); lun_capacity[g_bot_cbw.lun].blk_sz_len = block_size; lun_capacity[g_bot_cbw.lun].block_size_msb = (uint8_t)(block_size >> 24u); lun_capacity[g_bot_cbw.lun].block_size_2 = (uint8_t)(block_size >> 16u); lun_capacity[g_bot_cbw.lun].block_size_1 = (uint8_t)(block_size >> 8u); lun_capacity[g_bot_cbw.lun].block_size_lsb = (uint8_t)(block_size); g_xfr_buf_ptr = (uint8_t*)&lun_capacity[g_bot_cbw.lun]; g_xfr_buf_len = 8u; return (CB_PASS); } #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device_msd.h000066400000000000000000000430731432224323300301710ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC MSS USB Host logical driver layer Implementation. * * PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBD-MSC class driver. * * USBD-MSC class driver public API. * */ /*=========================================================================*//** @mainpage PolarFire SoC MSS USB driver (USBD-MSC) ============================================================================== Introduction ============================================================================== The Mass Storage Class device driver implements the USB MSC device as specified by the USB-IF. This driver enables easy implementation of mass storage drive functionality on the Smarfusion2 devices. This driver implements the MSC class using Bulk Only transport (BOT). One BULK IN and one BULK OUT endpoints are used to implement BOT. This driver is independent of the storage medium used for storing the data and the number of Logical Units (LUN) it supports. This driver uses the USBD-Class driver template to implement the USB MSC device. This driver passes the USB-IF USB2.0 compliance test for high speed MSC class device. ============================================================================== Theory of Operation ============================================================================== The following steps are involved in the operation of the USBD-MSC driver: - Configuration - Initialization - Enumeration - Class Specific requests - Data transfer -------------------------------- Configuration -------------------------------- To use this driver, the MSS USB driver must first be configured in the USB device mode using the MSS_USB_PERIPHERAL_MODE. No other configuration is necessary. -------------------------------- Initialization -------------------------------- The MSC class driver must be initialized using the MSS_USBD_MSC_init() function. Once initialized, this driver gets configured by the USBD driver during the enumeration process. The Call-back function usbd_msc_init_cb() is implemented by this driver which will be called by the USBD driver when the host configures the this device. The usbd_msc_get_descriptor_cb() function is implemented to provide the class specific descriptor table to the USBD driver. -------------------------------- Class Specific requests -------------------------------- This driver defines descriptor table which contains a configuration descriptor, an interface descriptor, two endpoint descriptors for successful enumeration as a MSC class device. Note: For successful enumeration, the device specific descriptors must also be provided by the application using the MSS_USBD_set_desc_cb_handler() function to the USBD Driver. Since the device descriptor, string descriptors etc. are not class specific, they are not part of the MSC class driver. Class Specific requests The usbd_msc_process_request_cb() call-back function is implemented by this driver which processes the MSC class specific requests. This driver may not have all the information related to the storage medium e.g. storage capacity etc. To process such requests; they are passed on to the application by calling appropriate call-back functions. The application must implement these call-back functions for the driver to successfully respond to the host requests. Refer data structures section for more information. -------------------------------- Data transfer -------------------------------- The MSC class driver performs the data transfers using one BULK IN endpoint and one BULK OUT endpoint. The data transfers follow the BoT protocol. This driver implements the usbd_msc_tx_complete_cb() and the usbd_msc_tx_complete_cb() function to get the information on data transfer events on the USB bus which are called by the USBD Driver. The BoT read/write operations happen on logical units of fixed block sizes. This driver translates these read write operation into memory read/write operation and calls the call-back function where application can perform the memory read/write operations. This method makes the MSC class driver independent of the storage medium being used. The call-back function elements media_acquire_write_buf, media_write_ready and media_read (as part of structure of type mss_usbd_msc_media_t) must be implemented by the application. *//*==========================================================================*/ #ifndef __MSS_USB_DEVICE_MSD_H_ #define __MSS_USB_DEVICE_MSD_H_ #include #include "mss_usb_device.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_DEVICE_ENABLED /******************************************************************************* * User Descriptor lengths */ /* Full configuration descriptor length*/ #define FULL_CONFIG_DESCR_LENGTH (USB_STD_CONFIG_DESCR_LEN + \ USB_STD_INTERFACE_DESCR_LEN + \ USB_STD_ENDPOINT_DESCR_LEN + \ USB_STD_ENDPOINT_DESCR_LEN ) /***************************************************************************//** Exported Types from USBD-MSC class driver */ /***************************************************************************//** mss_usbd_msc_state_t The mss_usbd_msc_state_t provides a type to identify the current state of the MSC class driver. USBD_MSC_NOT_CONFIGURED - The USB MSC class driver is not configured and it cannot perform the data transfers. USBD_MSC_CONFIGURED - The USB MSC class driver is configured by the host and it can perform the data transfers. Note: The application must not access the flash media (on board SPI Flash in this case) while the MSC class driver is in USBD_MSC_CONFIGURED state because the USB host might be performing read/write operation on the flash media. If the application also attempts to access the flash media at the same time, the data might get corrupted and the host will get misleading information from the flash media. */ typedef enum mss_usbd_msc_state { USBD_MSC_NOT_CONFIGURED, USBD_MSC_CONFIGURED, }mss_usbd_msc_state_t; /***************************************************************************//** mss_usbd_msc_media_t The mss_usbd_msc_media_t provides the prototype for all the call-back functions which must be implemented by the user application. The user application must define and initialize a structure of this type and provide the address of that structure as parameter to the MSS_USBD_MSC_init() function. media_init The function pointed by the media_init function pointer will be called to indicate that the MSC driver is configured by the USB host. The application can use this function to prepare itself for data exchange with the host. This driver cannot perform data transfers unless it is configured by the USB host to do so. media_get_capacity The function pointed to by the media_get_capacity function pointer is called to find out the capacity of the LUN on the storage medium. The parameter lun indicates the logical unit on which the current operation is being performed. The application must return address of the last logical block and the size of the logical block in the parameters last_block_lba and block_size respectively. media_is_ready The function pointed by the media_is_ready function pointer is called to find out if the LUN on the media is ready for the data transfers. The parameter lun indicates the logical unit on which the current operation is being performed. media_is_write_protected The function pointed by the media_is_write_protected function pointer is called to find out if the LUN on the media is write-protected, before a write operation can be performed on the LUN. The parameter lun indicates the logical unit on which the current operation is being performed. media_read The function pointed by the media_read function pointer is called when the host wants to read the data from the storage medium. The application must provide a buffer and its length which can be sent to the host. The parameter lun indicates the logical unit on which the current operation is being performed. The blk_addr parameter provides the logical block address and the len parameter provides the number of bytes to be read. The application must provide a buffer in return parameter buf and the length of this buffer must be provided as the return value of this function. media_acquire_write_buffer The function pointed by the msd_media_acquire_write_buffer function pointer is called when the host wants to write data on to the storage medium. The application must provide a buffer where the data sent by the host can be stored. The parameter lun indicates the logical unit on which the current operation is being performed. The blk_addr parameter provides the logical block address where the data is to be written. The application must provide a buffer as a return value of this function and the length of the buffer must be provided in the return parameter length. media_write_ready The function pointed by the media_write_ready function pointer is called when the data to be written is received from the host and is ready to be written on the storage medium. The data is stored in the previously provided write buffer using media_acquire_write_buffer. The parameter lun indicates the logical unit on which the current operation is being performed. The blk_addr parameter provides the logical block address where data is to be written. The parameter length provides the number of bytes to be written. media_get_max_lun The function pointed by the media_get_max_lun function pointer is called to find out the maximum number of logical units supported by the application or the storage medium. media_inquiry The function pointed by the media_inquiry function pointer is called to get the response for the INQUIRY request from the MSC class host. The parameter lun indicates the logical unit on which the current operation is being performed. The application must provide a buffer as a return value of this function and must provide the length of this buffer in the parameter length. media_release The function pointed by the media_inquiry function pointer is called to indicate that the either the MSC class device has been un-configured or is disconnected from the host. The MSC class device is un-configured when it receives SET_CONFIGURATION request from USB host with a cfgidx = 0. This value is passed as a parameter. In case when the disconnect event is detected by the USBD driver a value of cfgidx = 0xFF is passed. The application can use this call-back function and its parameter to take appropriate action as required. */ typedef struct mss_usbd_msc_media { uint8_t (*media_init)(uint8_t lun); uint8_t (*media_get_capacity)(uint8_t lun, uint32_t *last_block_lba, uint32_t *block_size); uint8_t (*media_is_ready)(uint8_t lun); uint8_t (*media_is_write_protected)(uint8_t lun); uint32_t(*media_read)(uint8_t lun, uint8_t **buf, uint64_t blk_addr, uint32_t len); uint8_t*(*media_acquire_write_buf)(uint8_t lun, uint64_t blk_addr, uint32_t *len); uint32_t(*media_write_ready)(uint8_t lun, uint64_t blk_addr, uint32_t len); uint8_t (*media_get_max_lun)(void); uint8_t*(*media_inquiry)(uint8_t lun, uint32_t *len); uint8_t (*media_release)(uint8_t cfgidx); } mss_usbd_msc_media_t; /***************************************************************************//** Types Internal to the USBD-MSC class driver */ typedef enum mss_usbd_msc_bot_events { BOT_EVENT_IDLE, BOT_EVENT_TX, BOT_EVENT_RX, BOT_EVENT_TX_ERROR, BOT_EVENT_RX_ERROR } mss_usbd_msc_bot_events_t; typedef enum mss_usbd_msc_csw_status { SCSI_COMMAND_PASS, SCSI_COMMAND_FAIL, SCSI_COMMAND_PHASE_ERR, SCSI_COMMAND_LESSDATAPASS, } mss_usbd_msc_csw_status_t; typedef enum mss_usbd_msc_bot_state { BOT_IDLE, BOT_DATA_RX, BOT_DATA_TX, BOT_SEND_STATUS, BOT_ABORTED } mss_usbd_msc_bot_state_t; /* Command Block Wrapper (CBW) */ typedef struct mss_usb_msc_cbw { uint32_t signature; uint32_t tag; uint32_t xfr_length; uint8_t flags; uint8_t lun; uint8_t cmd_length; uint8_t cmd_block[16]; } mss_usb_msc_cbw_t; /* Command Status Wrapper (CSW) */ typedef struct mss_usbd_msc_csw { uint32_t signature; uint32_t tag; uint32_t data_residue; mss_usbd_msc_csw_status_t status; } mss_usbd_msc_csw_t; /* SCSI inquiry response */ typedef struct mss_usbd_msc_scsi_inq_resp { uint8_t peripheral; uint8_t removable; uint8_t version; uint8_t resp_data_format; uint8_t additional_length; uint8_t sccstp; uint8_t bqueetc; uint8_t cmd_que; uint8_t vendor_id[8]; uint8_t product_id[16]; uint8_t product_rev[4]; } mss_usbd_msc_scsi_inq_resp_t; typedef struct mss_usbd_msc_scsi_sense_resp { const uint8_t response_code; /*0x70 - spc3-table12*/ const uint8_t obsolete; uint8_t sense_key; /*Table 27 - spc3-4.5.6*/ const uint8_t info[4]; const uint8_t additional_length; const uint8_t command_info[4]; uint8_t asc; /*Table28 - spc3-4.5.6*/ const uint8_t unused[5]; } mss_usbd_msc_scsi_sense_resp_t; typedef struct mss_usbd_msc_lun_capacity { uint8_t last_lba_msb; uint8_t last_lba_2; uint8_t last_lba_1; uint8_t last_lba_lsb; uint8_t block_size_msb; uint8_t block_size_2; uint8_t block_size_1; uint8_t block_size_lsb; uint32_t blk_sz_len; } mss_usbd_msc_lun_capacity_t; /***************************************************************************//** Exported functions from USBD-MSC class driver */ /***************************************************************************//** @brief MSS_USBD_MSC_init() The MSS_USBD_MSC_init() function must be used by the application to initialize the MSC class driver. A pointer to the structure of type mss_usbd_msc_media_t must be passed as a parameter to this function. @param media_ops The media_ops parameter is a pointer to the structure of type mss_usbd_msc_media_t. This is used by the MSC class driver to call the call-back functions implemented by the application. @param speed The speed parameter indicates the USB speed at which this class driver must operate. @return This function does not return a value. Example: @code //Assign call-back function handler structure needed by MSD class driver MSS_USBD_MSC_init(&usb_flash_media, MSS_USB_DEVICE_HS); //Assign call-back function handler structure needed by USB Device Core driver MSS_USBD_set_desc_cb_handler(&flash_drive_descr_cb); //Initialize USB driver HS device mode MSS_USBD_init(MSS_USB_DEVICE_HS); @endcode */ void MSS_USBD_MSC_init ( mss_usbd_msc_media_t* media_ops, mss_usb_device_speed_t speed ); /***************************************************************************//** @brief USBD_get_state() The MSS_USBD_MSC_get_state() function can be used by the application to find out the current state of the MSC class driver. @param media_ops This function does not take a parameter. @return This function returns a value of type mss_usbd_msc_state_t indicating the current state of the MSC class driver. Example: @code uint8_t usb_flash_media_get_capacity ( uint8_t lun, uint32_t *no_of_blocks, uint32_t *block_size ) { if(USBD_MSC_CONFIGURED == MSS_USBD_MSC_get_state()) { *no_of_blocks = lun_data[lun].number_of_blocks; *block_size = lun_data[lun].lba_block_size; return 1; } Else { Return 0; } } @endcode */ mss_usbd_msc_state_t MSS_USBD_MSC_get_state ( void ); #endif //MSS_USB_DEVICE_ENABLED #ifdef __cplusplus } #endif #endif /* __MSS_USB_DEVICE_MSD_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_device_reg_io.h000066400000000000000000000037441432224323300306530ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USBD-CIF * * This file provides interfaces to perform register and register bit level * read / write operations in USB Device mode. * */ #ifndef __MSS_USB_DEVICE_REG_IO_H_ #define __MSS_USB_DEVICE_REG_IO_H_ #ifdef __cplusplus extern "C" { #endif #include "mss_usb_core_regs.h" /******************************************************************************* * Device mode functions */ /******************************************************************************* * POWER register related APIs */ /*lint -e20 -e522 -e10 -e40 -e63 -e35 -e26 -e78*/ static __INLINE uint8_t MSS_USBD_CIF_is_suspend_mode ( void ) { return(((USB->POWER & POWER_REG_SUSPEND_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*To force out of the Suspend while in Device mode.*/ static __INLINE void MSS_USBD_CIF_resume_gen ( void ) { USB->POWER |= POWER_REG_RESUME_SIGNAL_MASK; /*clear after 10ms*/ } /******************************************************************************* * DEVCTL register related APIs */ static __INLINE uint8_t MSS_USB_OTG_is_session_on ( void ) { return (((USB->DEV_CTRL & DEV_CTRL_SESSION_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_OTG_initiate_srp ( void ) { /* TODO:make sure that the device is suspended and is a B-device when this function is called */ USB->DEV_CTRL |= DEV_CTRL_SESSION_MASK; } static __INLINE void MSS_USB_OTG_initiate_hnp ( void ) { /*TODO:make sure that the device is B-device when this function is called*/ USB->DEV_CTRL |= DEV_CTRL_HOST_REQ_MASK; } /*lint -restore */ #ifdef __cplusplus } #endif #endif /* __MSS_USB_DEVICE_REG_IO_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_regs.h000066400000000000000000000007501432224323300270220ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF. * * MSS USB register map * */ #ifndef __MSS_USB_REGS_H_ #define __MSS_USB_REGS_H_ #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif /* __MSS_USB_COMMON_REG_IO_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_std_def.h000066400000000000000000000217161432224323300274770ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS USB Driver Stack * * Standard USB definitions. * */ #ifndef __MSS_USB_STD_DEF_H_ #define __MSS_USB_STD_DEF_H_ #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** Constant values which are internally used by the driver. ============================ */ /* USB request types */ #define USB_STANDARD_REQUEST 0x00u #define USB_CLASS_REQUEST 0x20u #define USB_VENDOR_REQUEST 0x40u /* USB request type masks */ #define USB_STD_REQ_DATA_DIR_MASK 0x80u #define USB_STD_REQ_TYPE_MASK 0x60u #define USB_STD_REQ_RECIPIENT_MASK 0x1Fu #define USB_STD_REQ_DATA_DIR_OUT 0x00u #define USB_STD_REQ_DATA_DIR_IN 0x80u #define USB_STD_REQ_RECIPIENT_DEVICE 0x00u #define USB_STD_REQ_RECIPIENT_INTERFACE 0x01u #define USB_STD_REQ_RECIPIENT_ENDPOINT 0x02u #define USB_STD_REQ_GET_STATUS 0x00u #define USB_STD_REQ_CLEAR_FEATURE 0x01u #define USB_STD_REQ_SET_FEATURE 0x03u #define USB_STD_REQ_SET_ADDRESS 0x05u #define USB_STD_REQ_GET_DESCRIPTOR 0x06u #define USB_STD_REQ_SET_DESCRIPTOR 0x07u #define USB_STD_REQ_GET_CONFIG 0x08u #define USB_STD_REQ_SET_CONFIG 0x09u #define USB_STD_REQ_GET_INTERFACE 0x0Au #define USB_STD_REQ_SET_INTERFACE 0x0Bu #define USB_STD_REQ_SYNCH_FRAME 0x0Cu /* USB Feature selector */ #define USB_STD_FEATURE_REMOTE_WAKEUP 0x0001u #define USB_STD_FEATURE_TEST_MODE 0x0002u #define USB_STD_FEATURE_EP_HALT 0x0000u /* USB Test Mode, Test selectors */ #define USB_TEST_MODE_SELECTOR_TEST_J 0x01u #define USB_TEST_MODE_SELECTOR_TEST_K 0x02u #define USB_TEST_MODE_SELECTOR_TEST_SE0NAK 0x03u #define USB_TEST_MODE_SELECTOR_TEST_PACKET 0x04u #define USB_TEST_MODE_SELECTOR_TEST_FORCE_ENA 0x05u /* Descriptor types */ #define USB_DEVICE_DESCRIPTOR_TYPE 1u #define USB_CONFIGURATION_DESCRIPTOR_TYPE 2u #define USB_STRING_DESCRIPTOR_TYPE 3u #define USB_INTERFACE_DESCRIPTOR_TYPE 4u #define USB_ENDPOINT_DESCRIPTOR_TYPE 5u #define USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE 6u #define USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE 7u #define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 8u #define USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE 11u #define USB_WVALUE_HIBITE_SHIFT 8u #define USB_WINDEX_HIBITE_SHIFT 8u #define USB_EP_DESCR_ATTR_CONTROL 0x00u #define USB_EP_DESCR_ATTR_ISO 0x01u #define USB_EP_DESCR_ATTR_BULK 0x02u #define USB_EP_DESCR_ATTR_INTR 0x03u #define USB_BCD_VERSION_2_0 0x0200u #define USB_BCD_VERSION_2_1 0x0210u #define USB_BCD_VERSION_1_1 0x0110u #define USB_BCD_VERSION_1_0 0x0100u #define USB_DEFAULT_TARGET_ADDR 0u #define USB_SETUP_PKT_LEN 8u #define USB_STD_DEVICE_DESCR_LEN 18u #define USB_STD_CONFIG_DESCR_LEN 9u #define USB_STD_INTERFACE_DESCR_LEN 9u #define USB_STD_ENDPOINT_DESCR_LEN 7u #define USB_STD_IA_DESCR_LEN 8u #define USB_STD_DEV_QUAL_DESCR_LENGTH 10u #define USB_DEVICE_BUS_POWER_MASK 0x40u #define USB_DEVICE_REM_WAKEUP_MASK 0x20u #define USB_MAX_BUS_POWER 250u /*num = mA/2*/ #define USB_CLASS_CODE_MSD 0x08u /* bInterfaceClass */ #define USB_CLASS_MSD_SUBCLASS_SCSI 0x06u /* bInterfaceSubClass */ #define USB_CLAS_MSD_PROTOCOL_BOT 0x50u /* bInterfaceProtocol */ #define USB_DEF_CONFIG_NUM 0u /*-------------------------------------------------------------------------*//** Maximum allowed Packet Sizes for respective transfer types */ #define USB_HS_BULK_MAX_PKT_SIZE 512u #define USB_HS_INTERRUPT_MAX_PKT_SIZE 1024u #define USB_HS_ISO_MAX_PKT_SIZE 1024u #define USB_FS_BULK_MAX_PKT_SIZE 64u #define USB_FS_INTERRUPT_MAX_PKT_SIZE 64u #define USB_FS_ISO_MAX_PKT_SIZE 1023u /*-------------------------------------------------------------------------*//** MSC class related definitions */ /* BoT protocol constants */ #define USBD_MSC_BOT_CSW_LENGTH 13u #define USBD_MSC_BOT_CBW_LENGTH 31u #define USB_MSC_BOT_REQ_GET_MAX_LUN 0xFEu #define USB_MSC_BOT_REQ_BMS_RESET 0xFFu #define USB_MSC_BOT_CBW_SIGNATURE 0x43425355u #define USB_MSC_BOT_CSW_SIGNATURE 0x53425355u /* Supported SCSI commands*/ #define USB_MSC_SCSI_INQUIRY 0x12u #define USB_MSC_SCSI_READ_FORMAT_CAPACITIES 0x23u #define USB_MSC_SCSI_READ_CAPACITY_10 0x25u #define USB_MSC_SCSI_READ_10 0x28u #define USB_MSC_SCSI_REQUEST_SENSE 0x03u #define USB_MSC_SCSI_TEST_UNIT_READY 0x00u #define USB_MSC_SCSI_WRITE_10 0x2Au #define USB_MSC_SCSI_MODE_SENSE_6 0x1Au #define USB_MSC_SCSI_MODE_SELECT_6 0x15u #define USB_MSC_SCSI_PREVENT_ALLW_MDM_RMVL 0x1Eu #define USB_MSC_SCSI_VERIFY_10 0x2Fu #define USB_MSC_SCSI_INVALID_COMMAND_CODE 0xFFu /* Additional sense codes */ #define SC_NO_SENSE 0x00u #define SC_RECOVERED_ERR 0x01u #define SC_NOT_READY 0x02u #define SC_MEDIUM_ERROR 0x03u #define SC_HARDWARE_ERR 0x04u #define SC_ILLEGAL_REQUEST 0x05u #define SC_UNIT_ATTENTION 0x06u #define SC_DATA_PROTECT 0x07u #define SC_BLANK_CHECK 0x08u #define SC_VENDOR_SPECIFIC 0x09u #define SC_COPY_ABORTED 0x0Au #define SC_ABORTED_COMMAND 0x0Bu /*0x0C is obsolete*/ #define SC_VOLUME_OVERFLOW 0x0Du #define SC_MISCOMPARE 0x0Eu /*0x0F is reserved*/ #define ASC_INVALID_CDB 0x20u #define ASC_INVALID_FIELED_IN_COMMAND 0x24u #define ASC_PARAMETER_LIST_LENGTH_ERROR 0x1Au #define ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26u #define ASC_ADDRESS_OUT_OF_RANGE 0x21u #define ASC_MEDIUM_NOT_PRESENT 0x3Au #define ASC_MEDIUM_HAS_CHANGED 0x28u #define ASC_WRITE_PROTECTED 0x27u #define ASC_UNRECOVERED_READ_ERROR 0x11u #define ASC_WRITE_FAULT 0x03u /*-------------------------------------------------------------------------*//** CDC class related definitions */ /* CDC Requests for ACM sub-class */ #define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00u #define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01u #define USB_CDC_SET_COMM_FEATURE 0x02u #define USB_CDC_GET_COMM_FEATURE 0x03u #define USB_CDC_CLEAR_COMM_FEATURE 0x04u #define USB_CDC_SET_LINE_CODING 0x20u #define USB_CDC_GET_LINE_CODING 0x21u #define USB_CDC_SET_CONTROL_LINE_STATE 0x22u #define USB_CDC_SEND_BREAK 0x23u /*-------------------------------------------------------------------------*//** HID class related definitions */ #define USB_HID_DESCR_LENGTH 9u #define USB_HID_DESCRIPTOR_TYPE 0x21u #define USB_REPORT_DESCRIPTOR_TYPE 0x22u #ifdef __cplusplus } #endif #endif /* __MSS_USB_STD_DEF_H_ */ hart-software-services-2022.10/baremetal/drivers/mss/mss_watchdog/000077500000000000000000000000001432224323300251635ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/mss/mss_watchdog/mss_watchdog.c000066400000000000000000000062441432224323300300170ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC (MPFS) Microprocessor SubSystem Watchdog bare metal software * driver implementation. * * */ #include "mss_hal.h" #include "mss_watchdog.h" #ifdef __cplusplus extern "C" { #endif WATCHDOG_TypeDef* wdog_hw_base[10] = {(WATCHDOG_TypeDef*)0x20001000, (WATCHDOG_TypeDef*)0x20101000, (WATCHDOG_TypeDef*)0x20103000, (WATCHDOG_TypeDef*)0x20105000, (WATCHDOG_TypeDef*)0x20107000, (WATCHDOG_TypeDef*)0x28001000, (WATCHDOG_TypeDef*)0x28101000, (WATCHDOG_TypeDef*)0x28103000, (WATCHDOG_TypeDef*)0x28105000, (WATCHDOG_TypeDef*)0x28107000}; /***************************************************************************//** * See mss_watchdog.h for details of how to use this function. */ uint8_t MSS_WD_configure ( mss_watchdog_num_t wd_num, const mss_watchdog_config_t * config ) { uint8_t error = 0u; /* Note that the MSVP register value must always be <= TIMER register value. After any write to register from offset 0x00 to 0x0c the TRIGGER,MSVP and TIME registers are locked. Hence write them in proper sequence. */ if (config->timeout_val <= MSS_WDOG_TRIGGER_MAX) { wdog_hw_base[wd_num]->TRIGGER = config->timeout_val; } else { error = 1u; } if (config->time_val <= MSS_WDOG_TIMER_MAX) { wdog_hw_base[wd_num]->MSVP = config->mvrp_val; } else { error = 1u; } if (config->time_val <= MSS_WDOG_TIMER_MAX) { wdog_hw_base[wd_num]->TIME = config->time_val; } else { error = 1u; } wdog_hw_base[wd_num]->CONTROL = (uint32_t)(config->forbidden_en << MSS_WDOG_ENA_FORBIDDEN); /* Reload watchdog with new load if it is not in forbidden window. */ if (!(MSS_WDOG_FORBIDDEN_MASK & wdog_hw_base[wd_num]->STATUS)) { wdog_hw_base[wd_num]->REFRESH = MSS_WDOG_REFRESH_KEY; } else { error = 1u; } return(error); } /***************************************************************************//** * See mss_watchdog.h for details of how to use this function. */ void MSS_WD_get_config ( mss_watchdog_num_t wd_num, mss_watchdog_config_t* config ) { if((WATCHDOG_TypeDef*)0 != wdog_hw_base[wd_num]) { config->time_val = wdog_hw_base[wd_num]->TIME; config->timeout_val = wdog_hw_base[wd_num]->TRIGGER; config->mvrp_val = wdog_hw_base[wd_num]->MSVP; config->forbidden_en = (uint8_t)((wdog_hw_base[wd_num]->CONTROL & MSS_WDOG_ENA_FORBIDDEN_MASK) >> MSS_WDOG_ENA_FORBIDDEN); } } #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/mss/mss_watchdog/mss_watchdog.h000066400000000000000000000757741432224323300300420ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * PolarFire SoC (MPFS) Microprocessor Subsystem Watchdog bare metal software * driver public API. * * */ /*=========================================================================*//** @mainpage PolarFire SoC MSS Watchdog Bare Metal Driver ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor SubSystem (MSS) includes five instances of watchdog timer hardware blocks used to detect system lockups. This software driver provides a set of functions for controlling the MSS watchdog as part of a bare metal system where no operating system is available. The driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of the driver. The MSS watchdog driver provides support for the following features: - Initialization of the MSS watchdog - Reading the current value and status of the watchdog timer - Refreshing the watchdog timer value - Enabling, disabling and clearing timeout and MVRP interrupts. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all the features of the PolarFire SoC MSS watchdog is covered by this driver. Besides, this driver does not require any other configuration. On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple masters and multiple slaves. Five RISC-V CPUs connect to the Master ports M10 to M14 of the AXI switch. By default, all the APB peripherals are accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB bridges (referred as main APB bus). However, to support logical separation in the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to APB bridges (referred as the AMP APB bus). Application must make sure that the desired MSS Watchdog instance is appropriately configured on one of the APB slaves described above by configuring the PolarFire SoC system registers (SYSREG) as per the application need and that the appropriate data structures are provided to this driver as parameter to the functions provided by this driver. The base address and register addresses are defined in this driver as constants. The interrupt number assignment for the MSS Watchdog peripherals are defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole tool chain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS watchdog driver functions are grouped into the following categories: - Initialization and configuration - Reading the current value and status of the watchdog timer - Refreshing the watchdog timer value - Support for enabling, disabling and clearing time-out and MVRP interrupts. -------------------------------- Initialization and Configuration -------------------------------- The MSS Watchdog driver provides the MSS_WD_configure() function to configure the MSS Watchdog with desired configuration values. It also provides the MSS_WD_get_config() function to read back the current configurations of the MSS Watchdog. You can use this function to retrieve the current configurations and then overwrite them with the application specific values, such as initial watchdog timer value, Maximum Value (up to which) Refresh (is) Permitted, watchdog time-out value, enable/disable forbidden region, enable/disable MVRP interrupt and interrupt type. The occurrence of a time out event before the system reset can be detected using the MSS_WD_timeout_occured() function. This function would typically be used at the start of the application to detect whether the application is starting as a result of a power-on reset or a watchdog reset. The time out event must be cleared through a call to function MSS_WD_clear_timeout_event() in order to allow the detection of subsequent time out events or differentiating between a RISC-V initiated system reset and watchdog reset. -------------------------------------------- Reading the Watchdog Timer Value and Status -------------------------------------------- MSS Watchdog is a down counter. A refresh forbidden window can be created by configuring the watchdog Maximum Value up to which Refresh is Permitted (MVRP). When the current value of the watchdog timer is greater than the MVRP value, refreshing the watchdog is forbidden. Attempting to refresh the watchdog timer in the forbidden window will assert a timeout interrupt. The MSS_WD_forbidden_status() function can be used to know whether the watchdog timer is in forbidden window or has crossed it. By default, the forbidden window is disabled. It can be enabled by providing an appropriate value as parameter to the MSS_WD_configure() function. When the forbidden window is disabled, any attempt to refresh the watchdog timer is ignored and the counter keeps on down counting. The current value of the watchdog timer can be read using the MSS_WD_current_value() function. This function can be called at any time. -------------------------------------------- Refreshing the Watchdog Timer Value -------------------------------------------- The watchdog timer value is refreshed using the MSS_WD_reload() function. The value reloaded into the watchdog timer down-counter is specified at the configuration time with an appropriate value as parameter to the MSS_WD_get_config() function. -------------------------------------------- Interrupt Control -------------------------------------------- The PolarFire SoC MSS Watchdog generates two interrupts, The MVRP interrupt and the timeout interrupt. The MVRP interrupt is generated when the watchdog down-counter crosses the Maximum Value up to which Refresh is Permitted (MVRP). Following functions to control MVRP interrupt: - MSS_WD_enable_mvrp_irq - MSS_WD_disable_mvrp_irq - MSS_WD_clear_mvrp_irq The timeout interrupt is generated when the watchdog down-counter crosses the watchdog timeout value. The timeout value is a non-zero value and it can be set to a maximum of MSS_WDOG_TRIGGER_MAX. The non-maskable interrupt is generated when the watchdog crosses this timeout value, the down counter keeps on down counting and a reset signal is generated when reaches zero. Following functions to control timeout interrupt: - MSS_WD_enable_timeout_irq - MSS_WD_disable_timeout_irq - MSS_WD_clear_timeout_irq *//*=========================================================================*/ #ifndef MSS_WATCHDOG_H_ #define MSS_WATCHDOG_H_ #ifdef __cplusplus extern "C" { #endif #include /* The following constants can be used to configure the MSS Watchdog where a zero or non-zero value such as enable or disable is to be provided as input parameter as shown below: wd0lo_config.forbidden_en = MSS_WDOG_DISABLE; MSS_WD_configure(MSS_WDOG0_LO, &wd0lo_config); */ #define MSS_WDOG_ENABLE 1u #define MSS_WDOG_DISABLE 0u /***************************************************************************//** The mss_watchdog_num_t is the Watchdog module number enumeration. The MSS_WDOG0_LO to MSS_WDOG4_LO Correspond to the Watchdog module number 0 to 4 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI Correspond to the Watchdog module number 0 to 4 when the appear on the AXI switch Slave 6. */ typedef enum mss_watchdog_num{ MSS_WDOG0_LO = 0, MSS_WDOG1_LO = 1, MSS_WDOG2_LO = 2, MSS_WDOG3_LO = 3, MSS_WDOG4_LO = 4, MSS_WDOG0_HI = 5, MSS_WDOG1_HI = 6, MSS_WDOG2_HI = 7, MSS_WDOG3_HI = 8, MSS_WDOG4_HI = 9, } mss_watchdog_num_t; /***************************************************************************//** The mss_watchdog_config_t type for the watchdog Configuration structure. This type is used as a parameter for the MSS_WD_configure() and the MSS_WD_get_config() functions. Following are the values as part of this structure | Parameter | Description | |------------------|-----------------------------------------------------------| | time_val | The value from which the watchdog timer counts down | | mvrp_val | The Watchdog MVRP value | | timeout_val | The watchdog timeout value | | forbidden_en | Enable/disable the forbidden window | | | When set, if a refresh occurs in the forbidden window, | | | the watchdog timeout interrupt will be generated. | Time calculation example: time_val = 0xFFFFF0u mvrp_val = 0x989680u timeout_val = 0x3e8u A presaclar = 256 is used on the MSS AHB/APB clock. Considering AHB/APB clock = 25Mhz The MVRP interrupt will happen after (0xFFFFF0 - 0x989680) * ( 1/25MHz/256) mvrp interrupt will happen after 69 sec. after system reset (0xFFFFF0 - 0x3e8) * ( 1/25MHz/256) timeout interrupt will happen after 171 sec. after system reset */ typedef struct mss_watchdog_config{ uint32_t time_val; uint32_t mvrp_val; uint32_t timeout_val; uint8_t forbidden_en; uint8_t intr_type; } mss_watchdog_config_t; /***************************************************************************//** Internal constants and types *******************************************************************************/ #define MSS_WDOG_INTEN_MVRP 0u #define MSS_WDOG_INTEN_TRIG 1u #define MSS_WDOG_INTEN_SLEEP 2u #define MSS_WDOG_ACTIVE_SLEEP 3u #define MSS_WDOG_ENA_FORBIDDEN 4u #define MSS_WDOG_INTEN_MVRP_MASK ( 1u << MSS_WDOG_INTEN_MVRP) #define MSS_WDOG_INTEN_TRIG_MASK ( 1u << MSS_WDOG_INTEN_TRIG) #define MSS_WDOG_INTEN_SLEEP_MASK ( 1u << MSS_WDOG_INTEN_SLEEP) #define MSS_WDOG_ACTIVE_SLEEP_MASK ( 1u << MSS_WDOG_ACTIVE_SLEEP) #define MSS_WDOG_ENA_FORBIDDEN_MASK ( 1u << MSS_WDOG_ENA_FORBIDDEN) #define MSS_WDOG_MVRP_TRIPPED 0u #define MSS_WDOG_WDOG_TRIPPED 1u #define MSS_WDOG_FORBIDDEN 2u #define MSS_WDOG_TRIGGERED 3u #define MSS_WDOG_LOCKED 4u #define MSS_WDOG_DEVRST 5u #define MSS_WDOG_MVRP_TRIPPED_MASK ( 1u << MSS_WDOG_MVRP_TRIPPED) #define MSS_WDOG_WDOG_TRIPPED_MASK ( 1u << MSS_WDOG_WDOG_TRIPPED) #define MSS_WDOG_FORBIDDEN_MASK ( 1u << MSS_WDOG_FORBIDDEN) #define MSS_WDOG_TRIGGERED_MASK ( 1u << MSS_WDOG_TRIGGERED) #define MSS_WDOG_LOCKED_MASK ( 1u << MSS_WDOG_LOCKED) #define MSS_WDOG_DEVRST_MASK ( 1u << MSS_WDOG_DEVRST) #define MSS_WDOG_TRIGGER_MAX 4095u #define MSS_WDOG_TIMER_MAX 16777200u /*0xFFFFFFu*/ /* The WATCHDOG_TypeDef is the hardware register structure for the PolarFire SoC MSS Watchdog. */ typedef struct { volatile uint32_t REFRESH; volatile uint32_t CONTROL; volatile uint32_t STATUS; volatile uint32_t TIME; volatile uint32_t MSVP; volatile uint32_t TRIGGER; volatile uint32_t FORCE; } WATCHDOG_TypeDef; extern WATCHDOG_TypeDef* wdog_hw_base[10]; /***************************************************************************//** The MSS_WDOG_REFRESH_KEY macro holds the magic value which will cause a reload of the watchdog's down counter when written to the watchdog's WDOGREFRESH register. */ #define MSS_WDOG_REFRESH_KEY (uint32_t)0xDEADC0DEU /***************************************************************************//** The MSS_WDOG_FORCE_RESET_KEY macro holds the magic value which will force a reset if the Watchdog is already timed out (gone past the timeout value). Writing Any other value or writing TRIGGER register at other times will trigger the watchdog NMI sequence (i.e Raise the timeout interrupt). */ #define MSS_WDOG_FORCE_RESET_KEY (uint32_t)0xDEADU /***************************************************************************//** The MSS_WD_get_config() function returns the current configurations of the PolarFire SoC MSS Watchdog. The MSS Watchdog is pre-initialized by the flash bits at the design time. When used for the first time before calling the MSS_WD_configure() function, this function will return the default configurations as configured at the design time. You can reconfigure the MSS Watchdog using MSS_WD_configure() function. A call to MSS_WD_get_config() function will then return the current configuration values set by a previous call to MSS_WD_configure() function. You may not need to use this function if you do not want to know what the current configurations are. In that case, you can directly use the MSS_WD_configure() function to configure the MSS Watchdog to the values of your choice. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI Correspond to the Watchdog module number 0 to 5 when they appear on the AXI switch Slave 6. @param config The config parameter is the return parameter in which the current configurations of the watchdog module will be stored. Please see the description of mss_watchdog_config_t for details. @return This function does not return any value. Example: @code #include "mss_watchdog.h" mss_watchdog_config_t wd0lo_config; void e51( void ) { MSS_WD_get_config(MSS_WDOG0_LO, &wd0lo_config); wd0lo_config.forbidden_en = WDOG_ENABLE; wd0lo_config.mvrp_val = 0xFFFF000u; MSS_WD_configure(MSS_WDOG0_LO, &wd0lo_config); for(;;) { main_task(); } } */ void MSS_WD_get_config ( mss_watchdog_num_t wd_num, mss_watchdog_config_t* config ); /***************************************************************************//** The MSS_WD_configure() function configures the desired watchdog module. The Watchdog module is pre-initialized by the flash bits at the design time to the default values. You can reconfigure the Watchdog module using MSS_WD_configure() function. Note that the MSS_WD_configure() function can be used only once, as it writes into the TIME register. After a write into the TIME register, the TIME, TRIGGER and MSVP register values are frozen and can't be altered again unless a system reset happens. Note also that the MSS Watchdog is not enabled at reset, calling this function will start the watchdog, it cannot then be disabled and must be refreshed periodically. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @param config The config parameter is the input parameter in which the configurations to be applied to the watchdog module are provided by the application. Please see the description of mss_watchdog_config_t for details. @return This function returns a zero value when executed successfully. A non-zero value is returned when the configuration values are out of bound. Example: @code #include "mss_watchdog.h" mss_watchdog_config_t wd0lo_config; void e51( void ) { MSS_WD_get_config(MSS_WDOG0_LO, &wd0lo_config); wd0lo_config.forbidden_en = WDOG_ENABLE; wd0lo_config.mvrp_val = 0xFFFF000u; MSS_WD_configure(MSS_WDOG0_LO, &wd0lo_config); for(;;) { main_task(); } } */ uint8_t MSS_WD_configure ( mss_watchdog_num_t wd_num, const mss_watchdog_config_t * config ); /***************************************************************************//** The MSS_WD_reload() function causes the watchdog to reload its down-counter timer with the load value configured through the MSS configurator in the hardware flow. This function must be called regularly to avoid a system reset or a watchdog interrupt. Note that the MSS Watchdog is not enabled at reset, calling this function will start the watchdog, it cannot then be disabled and must be refreshed periodically. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when they appear on the AXI switch Slave 6. @return This function does not return a value. */ static inline void MSS_WD_reload(mss_watchdog_num_t wd_num) { if ((WATCHDOG_TypeDef*)0 != wdog_hw_base[wd_num]) { wdog_hw_base[wd_num]->REFRESH = MSS_WDOG_REFRESH_KEY; } } /***************************************************************************//** The MSS_WD_current_value() function returns the current value of the watchdog's down-counter. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return This function returns the current value of the watchdog's down-counter as a 32-bit unsigned integer. */ static inline uint32_t MSS_WD_current_value(mss_watchdog_num_t wd_num) { return wdog_hw_base[wd_num]->REFRESH; } /***************************************************************************//** The MSS_WD_forbidden_status() function returns the refresh status of the MSS Watchdog. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return This function returns the refresh status of the watchdog. A value of 1 indicates that watchdog's down-counter is within the forbidden window and that a reload should not be done. A value of 0 indicates that the watchdog's down counter is within the permitted window and that a reload is allowed. */ static inline uint32_t MSS_WD_forbidden_status(mss_watchdog_num_t wd_num) { return ((wdog_hw_base[wd_num]->STATUS & MSS_WDOG_FORBIDDEN_MASK) >> MSS_WDOG_FORBIDDEN); } /***************************************************************************//** The MSS_WD_enable_mvrp_irq() function enables the MVRP interrupt. The MSS Watchdog 0 to 4 generate a local MVRP interrupt to HART0 to 4 respectively. At the same time these interrupts are also available over the PLIC. This function allows you to choose which interrupt type should be enabled for each interrupt. The corresponding interrupt handler gets called when the interrupt asserts. Note: The Watchdog MVRP interrupt handler default implementations are weakly defined in the PolarFire SoC HAL. You must provide your own implementation of these functions, which will override the default implementation, to suit your application. Please refer mss_ints.h in the MPFS HAL for the actual names and the prototypes of these functions. Note: This function must be called from appropriate HART context. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @param intr_type The intr_type parameter indicates the type of interrupt that must be enabled. The MVRP interrupt for each hart can either be local interrupt to that hart or it can be accessed as a PLIC interrupt. @return This function does not return a value. Example: @code #include "mss_watchdog.h" void e51( void ) { MSS_WD_enable_mvrp_irq(wd_num); for (;;) { main_task(); cortex_sleep(); } } void wdog0_mvrp_E51_local_IRQHandler_10(void) { process_timeout(); MSS_WD_clear_mvrp_irq(); } @endcode */ static inline void MSS_WD_enable_mvrp_irq ( mss_watchdog_num_t wd_num ) { if ((WATCHDOG_TypeDef*)0 != wdog_hw_base[wd_num]) { wdog_hw_base[wd_num]->CONTROL |= MSS_WDOG_INTEN_MVRP_MASK; } } /***************************************************************************//** The MSS_WD_disable_mvrp_irq() function disables the generation of the MVRP interrupt. Note: This function must be called from appropriate HART context. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return This function does not return a value. */ static __inline void MSS_WD_disable_mvrp_irq ( mss_watchdog_num_t wd_num ) { if ((WATCHDOG_TypeDef*)0 != wdog_hw_base[wd_num]) { wdog_hw_base[wd_num]->CONTROL &= ~(MSS_WDOG_INTEN_MVRP_MASK); } } /***************************************************************************//** The MSS_WD_clear_timeout_irq() function clears the watchdog's timeout interrupt which is connected to the RISC-V NMI interrupt. Calling MSS_WD_clear_timeout_irq() results in clearing the RISC-V NMI interrupt. Note: You must call the MSS_WD_clear_timeout_irq() function as part of your implementation of the wdog0_tout_u51_local_IRQHandler_9() timeout interrupt service routine (ISR) in order to prevent the same interrupt event re-triggering a call to the timeout ISR. Note: This function must be called from appropriate HART context. Note: The MSS_WD_enable_timeout_irq() and MSS_WD_disable_timeout_irq() are removed as in the PolarFire SoC MSS Watchdog the timeout interrupt is permanently enabled by default and it can not be disabled. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return This function does not return any value. */ static inline void MSS_WD_clear_timeout_irq(mss_watchdog_num_t wd_num) { if ((WATCHDOG_TypeDef*)0 != wdog_hw_base[wd_num]) { wdog_hw_base[wd_num]->STATUS |= MSS_WDOG_WDOG_TRIPPED_MASK; /* * Perform a second write to ensure that the first write completed before * returning from this function. This is to account for posted writes across * the AHB matrix. The second write ensures that the first write has * completed and that the interrupt line has been de-asserted by the time * the function returns. Omitting the second write may result in a delay * in the de-assertion of the interrupt line going to the RISC-V and a * retriggering of the interrupt. */ wdog_hw_base[wd_num]->STATUS |= MSS_WDOG_WDOG_TRIPPED_MASK; } } /***************************************************************************//** The MSS_WD_clear_mvrp_irq() function clears the mvrp interrupt. This function also clears the interrupt in the RISC-V interrupt controller through a call to NVIC_ClearPendingIRQ(). Note: You must call the MSS_WD_clear_mvrp_irq() function as part of your implementation of the wdog0_msvp_u51_local_IRQHandler_10() mvrp interrupt service routine (ISR) in order to prevent the same interrupt event re-triggering a call to the mvrp ISR. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return This function does not return a value. */ static inline void MSS_WD_clear_mvrp_irq(mss_watchdog_num_t wd_num) { if ((WATCHDOG_TypeDef*)0 != wdog_hw_base[wd_num]) { wdog_hw_base[wd_num]->STATUS |= MSS_WDOG_MVRP_TRIPPED_MASK; /* * Perform a second write to ensure that the first write completed before * returning from this function. This is to account for posted writes across * the AHB matrix. The second write ensures that the first write has * completed and that the interrupt line has been de-asserted by the time * the function returns. Omitting the second write may result in a delay * in the de-assertion of the interrupt line going to the RISC-V and a * re-triggering of the interrupt. */ wdog_hw_base[wd_num]->STATUS |= MSS_WDOG_MVRP_TRIPPED_MASK; } } /***************************************************************************//** The MSS_WD_timeout_occured() function reports the occurrence of a timeout event. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return A zero value indicates no watchdog timeout event occurred. A value of 1 indicates that a timeout event occurred. Example: @code #include "mss_watchdog.h" void e51( void ) { uint32_t wdg_reset; wdg_reset = MSS_WD_timeout_occured(); if (wdg_reset) { log_watchdog_event(); MSS_WD_clear_timeout_event(); } for(;;) { main_task(); } } */ static inline uint32_t MSS_WD_timeout_occured(mss_watchdog_num_t wd_num) { return((wdog_hw_base[wd_num]->STATUS & MSS_WDOG_TRIGGERED_MASK) >> MSS_WDOG_TRIGGERED); } /***************************************************************************//** The MSS_WD_force_reset() function is used to force an immediate reset if the watchdog has already triggered. Writing any value in this condition will cause an NMI sequence. Moreover any attempt to force reset when the watchdog is not in triggered condition will also cause an NMI sequence. @param wd_num The wd_num parameter is the Watchdog module number in the PolarFire SoC MSS on which the operation needs to be performed. The Watchdog module number can be chosen using mss_watchdog_num_t. The MSS_WDOG0_LO to MSS_WDOG4_LO correspond to the Watchdog module number 0 to 5 when the appear on the AXI switch Slave 5. The MSS_WDOG0_HI to MSS_WDOG4_HI correspond to the watchdog module number 0 to 5 when the appear on the AXI switch Slave 6. @return This function does not return a value. */ static inline void MSS_WD_force_reset(mss_watchdog_num_t wd_num) { if (MSS_WDOG_TRIGGERED_MASK == (uint32_t)(wdog_hw_base[wd_num]->STATUS | MSS_WDOG_TRIGGERED_MASK)) { wdog_hw_base[wd_num]->FORCE = 0xDEADu; } else { wdog_hw_base[wd_num]->FORCE = 0x0u; } } #ifdef __cplusplus } #endif #endif /* MSS_WATCHDOG_H_ */ hart-software-services-2022.10/baremetal/drivers/winbond_w25n01gv/000077500000000000000000000000001432224323300247105ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.c000066400000000000000000000477441432224323300301050ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2019-2022 Microchip Corporation. * * SPDX-License-Identifier: MIT * * Bare metal driver for the Winbond w25n01gv NAND flash memory. * This driver uses the MPFS MSS QSPI driver interface. */ #include "mpfs_hal/mss_hal.h" #include "drivers/winbond_w25n01gv/winbond_w25n01gv.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include //assert #include //memcpy /* The following constant must be defined if you want to use the interrupt mode * transfers provided by the MSS QSPI driver. Comment this out to use the * polling mode transfers. */ /* #define USE_QSPI_INTERRUPT 1u */ #ifdef __cplusplus extern "C" { #endif #define NUM_PAGES_PER_BLOCK 64u #define NUM_BLOCKS_PER_DIE 1024u #define PAGE_LENGTH 2048u #define BLOCK_LENGTH (PAGE_LENGTH * NUM_PAGES_PER_BLOCK) #define DIE_SIZE (BLOCK_LENGTH * NUM_BLOCKS_PER_DIE) #define NUM_LUTS 20u #define STATUS_REG_1 0xA0u #define STATUS_REG_2 0xB0u #define STATUS_REG_3 0xC0u #define STATUS_REG_2_OTP_L (1u << 7) #define STATUS_REG_2_OTP_E (1u << 6) #define STATUS_REG_2_SR1_L (1u << 5) #define STATUS_REG_2_ECC_E (1u << 4) #define STATUS_REG_2_BUF (1u << 3) #define STATUS_REG_3_LUTF (1u << 6) #define STATUS_REG_3_ECC1 (1u << 5) #define STATUS_REG_3_ECC0 (1u << 4) #define STATUS_REG_3_PFAIL (1u << 3) #define STATUS_REG_3_EFAIL (1u << 2) #define STATUS_REG_3_WEL (1u << 1) #define STATUS_REG_3_BUSY (1u << 0) #define DEVICE_RESET_OPCODE 0xFFu #define READ_ID_OPCODE 0x9Fu #define READ_STATUS_REG_OPCODE 0x05u #define WRITE_STATUS_REG_OPCODE 0x01u #define WRITE_ENABLE_OPCODE 0x06u #define PAGE_DATA_READ_OPCODE 0x13u #define READ_DATA_OPCODE 0x03u #define FAST_READ_OPCODE 0x0Bu #define BLOCK_ERASE_OPCODE 0xD8u #define LOAD_PROGRAM_DATA_OPCODE 0x02u #define RANDOM_LOAD_PROGRAM_DATA_OPCODE 0x84u #define PROGRAM_EXECUTE_OPCODE 0x10u #define READ_BBM_LUT_OPCODE 0xA5u #define BAD_BLOCK_MANAGEMENT_OPCODE 0xA1u #define FAST_READ_DUAL_OUTPUT_OPCODE 0x3Bu #define FAST_READ_DUAL_OUTPUT_ADDR4_OPCODE 0x3Cu #define FAST_READ_DUAL_IO_OPCODE 0xBBu #define FAST_READ_DUAL_IO_ADDR4_OPCODE 0xBCu #define FAST_READ_QUAD_O_OPCODE 0x6Bu #define FAST_READ_QUAD_O_ADDR4_OPCODE 0x6Cu #define FAST_READ_QUAD_IO_OPCODE 0xEBu #define FAST_READ_QUAD_IO_ADDR4_OPCODE 0xECu // The MSS QSPI peripheral has a CMDBYTES field that is limited to // 511 bytes. // // We currently use it to transmit the command phase plus the TX // phase of a TX transaction... So our payload is limited to // 511 - 1 byte opcode - 2 byte address // // See the CoreQSPI Handbook for details // #define MSS_QSPI_CMDBYTES_LIMIT (511 - 3) static mss_qspi_config_t g_qspi_config= { 0 }; #ifdef USE_QSPI_INTERRUPT static volatile uint8_t g_rx_complete = 0u; static volatile uint8_t g_tx_complete = 0u; #endif #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /******************************************************************************* * Local functions */ static uint8_t read_page(uint8_t* p_rx_buf, uint32_t page, uint16_t column, uint32_t read_len); static void send_write_enable_command(void); static void disable_write_protect(void); static bool is_bad_block(uint16_t block_index); static uint8_t erase_block(uint16_t addr); static uint8_t program_page(uint8_t const * const p_tx_buf, uint32_t page, const uint32_t wr_len); static uint8_t mark_block_as_bad(uint32_t block_index); static void read_statusreg(uint8_t status_reg_address, uint8_t* rd_buf); static void write_statusreg(uint8_t address, uint8_t value); static void wait_if_busy(void); static void wait_for_wel(void); static uint32_t wait_if_busy_or_wel(void); #ifdef USE_QSPI_INTERRUPT void transfer_status_handler(uint32_t status) { if (STTS_RDONE_MASK == (STTS_RDONE_MASK & status)) { g_rx_complete = 1; } else if (STTS_TDONE_MASK == (STTS_TDONE_MASK & status)) { g_tx_complete = 1; } } static void wait_for_tx_complete(void) { while (0u == g_tx_complete) { ; } g_tx_complete = 0u; } static void wait_for_rx_complete(void) { while (0u == g_rx_complete) { ; } g_rx_complete = 0u; } #endif void Flash_init(mss_qspi_io_format io_format) { volatile uint8_t transmit_buffer[2]; volatile uint8_t receive_buffer[3]; uint8_t status_reg2_value; MSS_QSPI_init(); g_qspi_config.clk_div = MSS_QSPI_CLK_DIV_8; g_qspi_config.sample = MSS_QSPI_SAMPLE_POSAGE_SPICLK; g_qspi_config.spi_mode = MSS_QSPI_MODE3; g_qspi_config.xip = MSS_QSPI_DISABLE; g_qspi_config.io_format = MSS_QSPI_NORMAL; MSS_QSPI_configure(&g_qspi_config); /* store the format for later use in READ and Write APIs */ switch (io_format) { case MSS_QSPI_QUAD_FULL: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_QUAD_EX_RO: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_QUAD_EX_RW: g_qspi_config.io_format = MSS_QSPI_QUAD_EX_RW; break; case MSS_QSPI_DUAL_FULL: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_DUAL_EX_RO: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_DUAL_EX_RW: g_qspi_config.io_format = MSS_QSPI_DUAL_EX_RO; break; default: g_qspi_config.io_format = MSS_QSPI_NORMAL; break; } /* Reset Flash memory */ transmit_buffer[0] = DEVICE_RESET_OPCODE; MSS_QSPI_polled_transfer_block(0u, (const void * const)transmit_buffer, 0u, (const void * const)receive_buffer, 0u, 0u); // Ensure BUF=1 and ECC-E=1 for page-based ECC read_statusreg(STATUS_REG_2, (uint8_t *)&status_reg2_value); status_reg2_value |= (STATUS_REG_2_ECC_E | STATUS_REG_2_BUF); write_statusreg(STATUS_REG_2, status_reg2_value); } void Flash_readid(uint8_t* buf) { const uint8_t command_buf[1] __attribute__ ((aligned (4))) = {READ_ID_OPCODE}; #ifdef USE_QSPI_INTERRUPT MSS_QSPI_irq_transfer_block(0u, (const void * const)command_buf, 0u, (const void *const)buf, 3u, 8u); wait_for_rx_complete(); #else MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 0u, (const void * const)buf, 3u, 8u); #endif } uint8_t Flash_read(uint8_t* pDst, uint32_t srcAddr, uint32_t len) { /* We only deal with reads from page boundaries for now */ assert((srcAddr % PAGE_LENGTH) == 0); uint8_t result = 0u; uint32_t page_index; uint8_t * target_buf = pDst; int32_t remaining_length = (int32_t)len; page_index = srcAddr / PAGE_LENGTH; while (remaining_length > 0) { uint32_t length; if (remaining_length > PAGE_LENGTH) { length = PAGE_LENGTH; } else { length = remaining_length; } result = read_page(target_buf, page_index, 0u, length); if (result) { break; } remaining_length = remaining_length - length; page_index++; target_buf = target_buf + length; } return result; } uint8_t Flash_erase(void) { uint16_t block_index; uint8_t status = 0xFFu; disable_write_protect(); for (block_index = 0u; block_index < NUM_BLOCKS_PER_DIE; block_index++) { status = erase_block(block_index); } return(status); } uint8_t Flash_erase_block(uint16_t block_index) { uint8_t status = 0xFFu; disable_write_protect(); status = erase_block(block_index); //if (status & STATUS_REG_3_EFAIL) { // mark_block_as_bad(block_index); //} return(status); } uint8_t Flash_program(uint8_t* buf, uint32_t addr, uint32_t len) { int32_t remaining_length = (int32_t)len; uint32_t target_page_offset = addr / PAGE_LENGTH; uint8_t status = 0xFFu; disable_write_protect(); while (remaining_length > 0u) { uint32_t length; if (remaining_length >= PAGE_LENGTH) { length = PAGE_LENGTH; } else { length = remaining_length; } status = program_page(buf, target_page_offset, length); //if (status & STATUS_REG_3_PFAIL) { // mark_block_as_bad(target_page_offset / NUM_PAGES_PER_BLOCK); //} (void)mark_block_as_bad; remaining_length -= length; target_page_offset += 1u; buf += length; } return status; } uint8_t Flash_add_entry_to_bb_lut(uint16_t lba, uint16_t pba) { uint8_t result = 0u; uint8_t status; read_statusreg(STATUS_REG_3, (uint8_t *)&status); if ((status & STATUS_REG_3_LUTF) == 0) { uint8_t command_buf[5] __attribute__ ((aligned (4))) = { BAD_BLOCK_MANAGEMENT_OPCODE, (lba >> 8) & 0xFF, lba & 0xFF, (pba >> 8) & 0xFF, lba & 0xFF }; send_write_enable_command(); MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 4u, (const void * const)0, 0u, 0u); status = wait_if_busy_or_wel(); (void)status; result = 1u; } return result; } void Flash_read_status_regs(uint8_t * buf) { read_statusreg(STATUS_REG_1, buf); read_statusreg(STATUS_REG_2, buf + 1); read_statusreg(STATUS_REG_3, buf + 2); } uint8_t Flash_read_bb_lut(w25_bb_lut_entry_t* lut_ptr) { uint8_t num_bb = 0u; uint8_t buf[4 * NUM_LUTS] = { 0u }; uint8_t command_buf[2] __attribute__ ((aligned (2))) = { READ_BBM_LUT_OPCODE, 0u }; /* * Read Bad block LUT * 8 dummy cycles * 20 LUT entries of 4 bytes each */ MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 0u, (const void * const)buf, 80u, 8u); for (int lut_idx = 0u; lut_idx < NUM_LUTS; lut_idx++) { const int buf_idx = lut_idx * 4u; lut_ptr[lut_idx].enable = ((buf[buf_idx] & 0x80u)? 1u : 0u); lut_ptr[lut_idx].invalid = ((buf[buf_idx] & 0x40u)? 1u : 0u); lut_ptr[lut_idx].lba = (((uint16_t)(buf[buf_idx] & 0x3u) << 8u) | buf[buf_idx+1]); lut_ptr[lut_idx].pba = (((uint16_t)buf[buf_idx+2] << 8u) | buf[buf_idx+3]); if ((1u == lut_ptr[lut_idx].enable) && (0u == lut_ptr[lut_idx].invalid)) { num_bb++; } } return num_bb; } uint32_t Flash_scan_for_bad_blocks(uint16_t* buf) { uint32_t bad_count; bad_count = 0u; for (uint16_t block_num = 0u; block_num < NUM_BLOCKS_PER_DIE; block_num++) { if (is_bad_block(block_num)) { buf[bad_count++] = block_num; } } return(bad_count); } /******************************************************************************* * Local functions */ static void send_write_enable_command(void) { uint8_t command_buf[1] __attribute__ ((aligned (4))) = { WRITE_ENABLE_OPCODE }; MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 0u, (const void * const)0, 0u, 0u); wait_for_wel(); } static void disable_write_protect(void) { write_statusreg(STATUS_REG_1, 0x0u); } static bool is_bad_block(uint16_t block_index) { bool result = false; uint8_t receive_buf[2]; // read the OOB read_page(receive_buf, block_index * NUM_PAGES_PER_BLOCK, PAGE_LENGTH, ARRAY_SIZE(receive_buf)); if ((receive_buf[0] != 0xFFu) || (receive_buf[1] != 0xFFu)) { result = true; } return result; } static uint8_t erase_block(uint16_t block_index) { uint8_t status; if (is_bad_block(block_index)) { // never erase bad blocks, as we'll lose bad block marker information... status = STATUS_REG_3_EFAIL; } else { // // weirdly, the W25N01GV block erase (D8h) actually uses a PAGE ADDRESS // and not a block address // uint8_t command_buf[4] __attribute__ ((aligned (4))) = { BLOCK_ERASE_OPCODE, 0u, // dummy for 8 clocks ((block_index * NUM_PAGES_PER_BLOCK) >> 8u) & 0xFF, (block_index * NUM_PAGES_PER_BLOCK) & 0xFF }; read_statusreg(STATUS_REG_1, &status); assert(0 == status); // protection must be disabled! wait_if_busy(); send_write_enable_command(); MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 3u, (const void * const)0, 0u, 0u); status = wait_if_busy_or_wel(); status = (STATUS_REG_3_EFAIL & status); } return status; } static uint8_t program_page(uint8_t const * const p_tx_buf, uint32_t page, const uint32_t wr_len) { uint8_t command_buf[PAGE_LENGTH + 3] __attribute__ ((aligned (4))) = { 0u }; uint16_t column = 0u; uint8_t status = 0xFFu; ASSERT(wr_len <= PAGE_LENGTH); int32_t remaining_length = (int32_t)wr_len; while (remaining_length > 0u) { uint32_t subpage_length; if (remaining_length > MSS_QSPI_CMDBYTES_LIMIT) { subpage_length = MSS_QSPI_CMDBYTES_LIMIT; } else { subpage_length = remaining_length; } if (remaining_length == wr_len) { // first time around, reset unused data bytes in data buffer to FFh command_buf[0] = LOAD_PROGRAM_DATA_OPCODE; } else { command_buf[0] = RANDOM_LOAD_PROGRAM_DATA_OPCODE; } command_buf[1] = (column >> 8) & 0xFF; command_buf[2] = column & 0xFF; for (uint16_t idx = 0u; idx < subpage_length; idx++) { command_buf[3 + idx] = p_tx_buf[column + idx]; } send_write_enable_command(); MSS_QSPI_polled_transfer_block(2u, (const void * const)command_buf, subpage_length, (const void * const)0, 0u, 0u); assert(remaining_length >= subpage_length); remaining_length -= subpage_length; column += subpage_length; } command_buf[0] = PROGRAM_EXECUTE_OPCODE; command_buf[1] = 0u; command_buf[2] = (page >> 8) & 0xFF; command_buf[3] = page & 0xFF; send_write_enable_command(); MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 3u, (const void * const)0, 0u, 0u); status = wait_if_busy_or_wel(); // ECC-1 indicates 2-bit error that cannot be corrected... return ((STATUS_REG_3_ECC1 | STATUS_REG_3_PFAIL) & status); } static uint8_t mark_block_as_bad(uint32_t block_index) { uint8_t command_buf[PAGE_LENGTH + 3] __attribute__ ((aligned (4))) = { 0u }; const uint16_t column = PAGE_LENGTH; uint8_t status = 0xFFu; const uint32_t page = block_index * NUM_PAGES_PER_BLOCK; // A "Bad Block Marker" is a non-FFh data byte stored at Byte 0 of Page 0 // for each bad block. An additional marker is also stored in the first two // bytes of the 64-Byte spare area. // // We'll mark the block as bad by writing to the first two bytes of the // spare area... // opcode command_buf[0] = RANDOM_LOAD_PROGRAM_DATA_OPCODE; // 2-bytes address command_buf[1] = (column >> 8) & 0xFF; command_buf[2] = column & 0xFF; // 2-bytes data command_buf[3] = 0x00u; command_buf[4] = 0x00u; send_write_enable_command(); MSS_QSPI_polled_transfer_block(2u, (const void * const)command_buf, 2u, (const void * const)0, 0u, 0u); // opcode command_buf[0] = PROGRAM_EXECUTE_OPCODE; // 0-bytes address // 3-bytes data command_buf[1] = 0u; command_buf[2] = (page >> 8) & 0xFF; command_buf[3] = page & 0xFF; send_write_enable_command(); MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 3u, (const void * const)0, 0u, 0u); status = wait_if_busy_or_wel(); return (STATUS_REG_3_PFAIL & status); } /* * Make sure that the program/erase operation is complete. i.e. wait for * busy bit to go 0. */ // this define is to prevent the code getting stuck forever spinning on a bit // it is arbitrarily large, but big enough that it won't cause timeouts in // normal operation #define MAX_SPIN_COUNT 0x01000000 static void wait_if_busy(void) { uint32_t status_reg = 0u; uint32_t max_count = MAX_SPIN_COUNT; do { read_statusreg(STATUS_REG_3, (uint8_t*)&status_reg); max_count--; } while (max_count && (STATUS_REG_3_BUSY & status_reg)); } static void wait_for_wel(void) { uint32_t status_reg = 0u; uint32_t max_count = MAX_SPIN_COUNT; do { read_statusreg(STATUS_REG_3, (uint8_t*)&status_reg); max_count--; } while (max_count && !(STATUS_REG_3_WEL & status_reg)); } static uint32_t wait_if_busy_or_wel(void) { uint32_t status_reg = 0u; uint32_t max_count = MAX_SPIN_COUNT; do { read_statusreg(STATUS_REG_3, (uint8_t*)&status_reg); max_count--; } while (max_count && ((STATUS_REG_3_BUSY & status_reg) || (STATUS_REG_3_WEL & status_reg))); return status_reg; } static void write_statusreg(uint8_t address, uint8_t value) { const uint8_t command_buf[3] __attribute__ ((aligned (4))) = { WRITE_STATUS_REG_OPCODE, address, value }; MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 2u, (const void * const)0, 0u, 0u); } static void read_statusreg(uint8_t status_reg_address, uint8_t* pRd_buf) { const uint8_t command_buf[2] __attribute__ ((aligned (4))) = { READ_STATUS_REG_OPCODE, status_reg_address }; MSS_QSPI_polled_transfer_block(1u, (const void * const)command_buf, 0u, (const void * const)pRd_buf, 1u, 0u); } static uint8_t read_page(uint8_t* p_rx_buf, uint32_t page, uint16_t column, uint32_t read_len) { uint8_t result = 0u; uint32_t length = read_len; uint8_t num_tx_bytes = 0u; uint8_t num_addr_bytes = 0u; uint8_t command_buf[4] __attribute__ ((aligned (4))) = { 0u }; uint8_t num_dummy_cycles = 0u; wait_if_busy(); command_buf[0] = PAGE_DATA_READ_OPCODE; command_buf[1] = 0u; command_buf[2] = (page >> 8u) & 0xFF; command_buf[3] = page & 0xFF; MSS_QSPI_polled_transfer_block(0u, (const void * const)command_buf, 3u, (const void * const)0, 0u, 0u); wait_if_busy(); command_buf[1] = (column >> 8u) & 0xFF; command_buf[2] = column & 0xFF; num_addr_bytes = 2u; num_tx_bytes = 0u; switch (g_qspi_config.io_format) { case MSS_QSPI_QUAD_FULL: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_QUAD_EX_RO: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_QUAD_EX_RW: command_buf[0] = FAST_READ_QUAD_IO_OPCODE; num_dummy_cycles = 4u; break; case MSS_QSPI_DUAL_FULL: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_DUAL_EX_RO: __attribute__((fallthrough)); // deliberate fallthrough case MSS_QSPI_DUAL_EX_RW: command_buf[0] = FAST_READ_DUAL_OUTPUT_OPCODE; num_dummy_cycles = 8u; break; default: command_buf[0] = FAST_READ_OPCODE; //READ_DATA_OPCODE; num_dummy_cycles = 8u; break; } if (read_len > PAGE_LENGTH) { length = PAGE_LENGTH; } mss_qspi_io_format temp = g_qspi_config.io_format; MSS_QSPI_configure(&g_qspi_config); MSS_QSPI_polled_transfer_block(num_addr_bytes, (const void * const)command_buf, num_tx_bytes, (const void * const)p_rx_buf, length, num_dummy_cycles); g_qspi_config.io_format = MSS_QSPI_NORMAL; MSS_QSPI_configure(&g_qspi_config); g_qspi_config.io_format = temp; read_statusreg(STATUS_REG_3, (uint8_t *)&result); result &= (STATUS_REG_3_ECC1 & STATUS_REG_3_ECC0); return result; } #ifdef __cplusplus } #endif hart-software-services-2022.10/baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.h000066400000000000000000000233531432224323300301000ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2022 Microchip Corporation. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * APIs for the Winbond w25n01gv flash driver. * This driver uses the MPFS MSS QSPI driver interface. *=========================================================================*/ #ifndef MSS_WINBOND_MT25Q_H_ #define MSS_WINBOND_MT25Q_H_ #include #include "drivers/mss/mss_qspi/mss_qspi.h" #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** * The w25_bb_lut_entry_t defines the lookup table intry in the Winbond NAD * flash memory device. */ typedef struct w25_bb_lut_entry { uint8_t enable; uint8_t invalid; uint16_t lba; uint16_t pba; } w25_bb_lut_entry_t; /*-------------------------------------------------------------------------*//** The Flash_init() function initializes the MSS QSPI and the flash memory to normal SPI operations. The g_qspi_config.io_format is used for the read/write operations to choose the Flash memory commands accordingly. This function must be called before calling any other function provided by this driver. The Winbondw25n01gv device expects the command-address bytes on DQ0 always. Hence the only MSS QSPI IO formats that can be used are MSS_QSPI_NORMAL, MSS_QSPI_DUAL_EX_RO, MSS_QSPI_QUAD_EX_RO. Furthermore, the DUAL operations are not supported by the flash program commands (Flash read supports dual and quad IOs). When dual operations are selected the programming operations will fall-back to normal mode. Reads will happen on quad IO. It is recommended that QUAD mode is selected for faster operations. @param io_format The io_format parameter provides the SPI IO format that needs to be used for read/write operations. @return This function does not returns any value @example ##### Example1 Example @code @endcode */ void Flash_init(mss_qspi_io_format io_format); /*-------------------------------------------------------------------------*//** The Flash_readid() function returns first 3 bytes of data of the device JEDEC ID. @param buf The rd_buf parameter provides a pointer to the buffer in which the driver will copy the JEDEC ID data. The buffer must be at least 3 bytes long. @return This function does not returns any value @example ##### Example1 Example @code @endcode */ void Flash_readid(uint8_t* buf); /*-------------------------------------------------------------------------*//** The Flash_read() function reads data from the flash memory. @param buf The buf parameter is a pointer to the buffer in which the driver will copy the data read from the flash memory. @param addr The addr parameter is the address in the flash memory from which the driver will read the data. @param len The len parameter is the number of 8-bit bytes that will be read from the flash memory starting with the address indicated by the addr parameter. @return This function returns a non-zero value if there was an error during the read operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_read(uint8_t* buf, uint32_t addr, uint32_t len); /*-------------------------------------------------------------------------*//** The Flash_erase() function erases the complete device. @return This function returns a non-zero value if there was an error during the erase operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_erase(void); /*-------------------------------------------------------------------------*//** The Flash_erase_block() function erases the complete device. @return This function returns a non-zero value if there was an error during the erase operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_erase_block(uint16_t block_nb); /*-------------------------------------------------------------------------*//** The Flash_program() function writes data into the flash memory. @param buf The rd_buf parameter provides a pointer to the buffer from which the data needs to be written into the flash memory. @param addr The addr parameter is an address in the flash memory to which the data will be written to. @param len The len parameter indicates the number of 8-bit bytes that will be written to the flash memory starting from the address indicated by the addr parameter. @return This function returns a non-zero value if there was an error during program operation. A zero return value indicates success. @example ##### Example1 Example @code @endcode */ uint8_t Flash_program(uint8_t* buf, uint32_t addr, uint32_t len); /*-------------------------------------------------------------------------*//** The Flash_scan_for_bad_blocks() function scans for bad blocks within the flash memory. The NAND flash devices are allowed to be shipped with certain number of bad blocks. In such cases, the flash device is shipped with bad blocks markers written into the respective bad blocks. The markers will be permanently lost if the block is written or erased. This function can be called on a unused device to know the factory marked bad blocks before erasing or writing on those block. The bad blocks can then be re-mapped to good blocks by adding a bad block (lba) to good block (pba) mapping in the lookup table (LUT) within the flash memory using the Flash_add_entry_to_bb_lut() function. Maximum 20 entries are allowed in the lookup table in the W25N01 devices. Only the first block of the shipped device is guaranteed to be a good block. Bad blocks can also be developed during the regular usage of the flash memory device. These should be handled as and when errors happen during program/erase operations and the LUT should be updated accordingly. @param buf The buf parameter is a pointer to the buffer in which the driver will write the block numbers of the blocks containing the bad-block marker. The buffer must be larg enough to contain 20 block numbers. @return This function returns the total number of bad blocks found during the scan. @example ##### Example1 Example @code @endcode */ uint32_t Flash_scan_for_bad_blocks(uint16_t* buf); /*-------------------------------------------------------------------------*//** The Flash_read_status_regs() function reads all three status registers @param buf The buf parameter is a pointer to the buffer in which the driver will copy the status register values. The buffer should be large enough to store 3 8-bit bytes. @return This function does not return any value. @example ##### Example1 Example @code @endcode */ void Flash_read_status_regs(uint8_t * buf); /*-------------------------------------------------------------------------*//** The Flash_read_bb_lut() function reads the look up table (LUT) in the flash memory that contains the bad block (lba) to good block (pba) mapping. @param lut_ptr The lut_ptr parameter is a pointer to the buffer in which the driver will copy the LUT data read from the flash memory. The buffer must be large enough to hold 20 LUT entries of type w25_bb_lut_entry_t. @return This function returns the number of valid bad block mappings in the LUT. @example ##### Example1 Example @code @endcode */ uint8_t Flash_read_bb_lut(w25_bb_lut_entry_t* lut_ptr); /*-------------------------------------------------------------------------*//** The Flash_add_entry_to_bb_lut() function adds an entry to the look up table (LUT) in the flash memory that contains the bad block (lba) to good block (pba) mapping. When the bad blocks are found during the initial bad block scan ( using Flash_scan_for_bad_blocks() function) or when a bad block is found during regular operation (indicated by errors during programming or erase operation), this function can be used to map these bad block to a good block where no errors are seen so far. After the LUT entry is added, any access to the bad block will be directed to the mapped good block. The bad block will not be accessed. @param lba The lba parameter is the block number of the bad block. @param pba The pba parameter is the block number of a good block. @return This function returns 1 if successful, or 0 otherwise @example ##### Example1 Example @code @endcode */ uint8_t Flash_add_entry_to_bb_lut(uint16_t lba, uint16_t pba); /* */ void Flash_flush(void); #ifdef __cplusplus } #endif #endif /* MSS_WINBOND_MT25Q_H_*/ hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/000077500000000000000000000000001432224323300264375ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/readme.md000066400000000000000000000065611432224323300302260ustar00rootroot00000000000000# PolarFire SoC Bare Metal Library This folder contains the PolarFire SoC Bare Metal Library. The PolarFire SoC Bare Metal Library includes: - Source code for start-up code and Hardware Abstraction Layer (HAL) for the PolarFire SoC RISC-V processor complex - Source code for the PolarFire SoC Microprocessor Subsystem (MSS) peripehral drivers - Documentation for the HAL and peripheral drivers - SoftConsole example projects demonstrating the use of the various PolarFire SoC peripherals ## Source Source code is found under the "src" folder. polarfire-soc-bare-metal-library | |--- docs |--- examples |--- src |--- platform |--- config | |--- hardware | |--- linker | |--- software | |--- drivers |--- hal |--- mpfs_hal ### src/platform The src/platform folder contains the entire source code specific to PolarFire SoC. This entire folder is intended to be copied into a bare metal software project. #### src/platform/config The src/platform/config folder contains configuration files applying to the hardware design, software configuration and linker scripts. - src/platform/config/hardware folder contains files describing the configuration of the PolarFire SoC specific to a Libero design/board. - src/platform/config/linker contains linker scripts - src/platform/config/software contains configuration parameters relevant to the Hardware Abstraction Layer (HAL) and drivers. ##### src/platform/config/hardware The content of this folder is expected to be generated from a Libero design. The content of this folder is not intended to be manually modified but instead should be regenerated from a Libero design meta-data description whenever required. The content of this folder may need to be updated when reprogramming PolarFire SoC hardware with a new design. If you need to modify a parameter coming from the Libero flow please follow the method described in any of the header files contained in #### src/platform/drivers The src/platform/drivers folder contains the source code for the MSS peripherals and DirectCore soft IP. The content of this folder is not intended to be modified. #### src/platform/hal The src/platform/hal folder contains the Hardware Abstraction Layer (HAL). This part of the HAL is intended to be generic across all SoC-FPGA devices. It is mainly used by DirectCore FPGA IP cores' drivers. The content of this folder is not intended to be modified. #### src/platform/mpfs_hal The src/platform/mpfs_hal folder contains the part of the HAL specific to PolarFire SoC. It contains start-up code and MSS peripheral register descriptions. The content of this folder is not intended to be modified. ## Documentation Documentation for the HAL and MSS peripheral drivers can be found in the "docs" folder. ## Examples The "examples" folder contains SoftConsole example projects demonstrating the use of the HAL and MSS peripheral drivers. Some of these examples include Renode development virtual platform debug configurations providing an execution platform for these examples in the absence of hardware. Please refer to the [Readme.md](examples/Readme.md) file in the "examples" folder for details on how to use these examples. hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/000077500000000000000000000000001432224323300272265ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/000077500000000000000000000000001432224323300310525ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/000077500000000000000000000000001432224323300325305ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/000077500000000000000000000000001432224323300333325ustar00rootroot00000000000000mss_can/000077500000000000000000000000001432224323300346765ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_can.c000066400000000000000000000675741432224323300365100ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_can/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC (MPFS) microprocessor subsystem CAN bare metal software driver * implementation. * * SVN $Revision$ * SVN $Date$ */ /******************************************************************************* * include files */ #include #include #include "mss_can.h" #include "mss_sysreg.h" #include "mss_plic.h" #include "mss_util.h" #ifdef __cplusplus extern "C" { #endif /******************************************************************************* * Macros */ #define CAN_ID_SHIFT 18u #define CAN_ERROR_STATUS_SHIFT 16u #define CAN_ERROR_STATUS_MASK 0x03u #define CAN_RX_GTE96_SHIFT 19u #define CAN_FLAG_MASK 0x01u #define CAN_ERROR_COUNT_SHIFT 8u #define CAN_ERROR_COUNT_MASK 0xFFu #define CAN_TXGTE96_SHIFT 18u #define CAN_INT_MASK 0xFFFFFFFCu #define ENABLE 1u #define DISABLE 0u #define SYSREG_CAN_SOFTRESET_MASK (uint32_t)(3 << 14u) /******************************************************************************* * Instance definition */ mss_can_instance_t g_mss_can_0_lo; mss_can_instance_t g_mss_can_1_lo; mss_can_instance_t g_mss_can_0_hi; mss_can_instance_t g_mss_can_1_hi; static void global_init ( mss_can_instance_t* this_wd ); /***************************************************************************//** * MSS_CAN_init() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_init ( mss_can_instance_t* this_can, uint32_t bitrate, pmss_can_config_reg pcan_config, uint8_t basic_can_rx_mb, uint8_t basic_can_tx_mb ) { uint32_t temp; uint8_t mailbox_number; uint8_t ret_value; mss_can_rxmsgobject canrxobj; global_init(this_can); /* Initialize the device structure */ this_can->basic_can_rx_mb = basic_can_rx_mb; this_can->basic_can_tx_mb = basic_can_tx_mb; /* Initialize the rx mailbox */ canrxobj.ID = 0u; canrxobj.DATAHIGH = 0u; canrxobj.DATALOW = 0u; canrxobj.AMR.L = 0u; canrxobj.ACR.L = 0u; canrxobj.AMR_D = 0u; canrxobj.ACR_D = 0u; canrxobj.RXB.L = (0u | CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL); for (mailbox_number = 0u; mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { ret_value = MSS_CAN_config_buffer_n(this_can, mailbox_number, &canrxobj); } /* Configure CAN controller */ if (CAN_SPEED_MANUAL == bitrate) { /* * If user wants to specify registers directly Check if parameters * meet minimums. */ if (pcan_config->CFG_TSEG1 < 2u) { return (CAN_TSEG1_TOO_SMALL ); } if ((pcan_config->CFG_TSEG2 == 0u) || ((pcan_config->SAMPLING_MODE == 1u) && (pcan_config->CFG_TSEG2 == 1u))) { return (CAN_TSEG2_TOO_SMALL); } temp = pcan_config->CFG_SJW; if ((temp > pcan_config->CFG_TSEG1) || (temp > pcan_config->CFG_TSEG2)) { return (CAN_SJW_TOO_BIG); } this_can->hw_reg->Config.L = pcan_config->L; } else { /* User has chosen a default setting. */ this_can->hw_reg->Config.L = bitrate; } /* Disable Interrupts */ this_can->hw_reg->IntEbl.L = DISABLE; return (CAN_OK); } /***************************************************************************//** * MSS_CAN_set_config_reg() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_set_config_reg ( mss_can_instance_t* this_can, uint32_t cfg ) { /* Clear all pending interrupts */ this_can->hw_reg->IntStatus.L = DISABLE; /* Disable CAN Device */ this_can->hw_reg->Command.RUN_STOP = DISABLE; /* Disable receive interrupts. */ this_can->hw_reg->IntEbl.RX_MSG = DISABLE; /* Disable interrupts from CAN device. */ this_can->hw_reg->IntEbl.INT_EBL = DISABLE; /* Sets configuration bits */ this_can->hw_reg->Config.L = cfg; MSS_CAN_start(this_can); } /***************************************************************************//** * MSS_CAN_set_mode() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_set_mode ( mss_can_instance_t* this_can, mss_can_mode_t mode ) { this_can->hw_reg->Command.RUN_STOP = DISABLE; if (CANOP_SW_RESET == mode) { SYSREG->SOFT_RESET_CR |= SYSREG_CAN_SOFTRESET_MASK; SYSREG->SOFT_RESET_CR &= ~SYSREG_CAN_SOFTRESET_MASK; } else { this_can->hw_reg->Command.L = (uint32_t)mode; } } /***************************************************************************//** * MSS_CAN_start() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_start ( mss_can_instance_t* this_can ) { /* Clear all pending interrupts*/ this_can->hw_reg->IntStatus.L = DISABLE; /* Enable CAN Device*/ this_can->hw_reg->Command.RUN_STOP = ENABLE; /* Enable CAN Interrupt at NVIC level- if supported */ #ifdef MSS_CAN_ENABLE_INTERRUPTS if (if (&g_mss_can_0_lo == this_can) || (&g_mss_can_0_hi == this_can)) { PLIC_DisableIRQ(CAN0_PLIC); } else { PLIC_DisableIRQ(CAN1_PLIC); } #endif /* Enable receive interrupts. */ this_can->hw_reg->IntEbl.RX_MSG = ENABLE; /* Enable interrupts from CAN device.*/ this_can->hw_reg->IntEbl.INT_EBL = ENABLE; } /***************************************************************************//** * MSS_CAN_stop() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_stop ( mss_can_instance_t* this_can ) { this_can->hw_reg->Command.RUN_STOP = DISABLE; } /***************************************************************************//** * MSS_CAN_get_id() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_id ( pmss_can_msgobject pmsg ) { if (pmsg->IDE) { return (pmsg->ID); } else { return (pmsg->ID >> CAN_ID_SHIFT); } } /***************************************************************************//** * MSS_CAN_set_id() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_set_id ( pmss_can_msgobject pmsg ) { if (pmsg->IDE) { return (pmsg->ID); } else { return (pmsg->ID << CAN_ID_SHIFT); } } /***************************************************************************//** * MSS_CAN_get_msg_filter_mask() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_msg_filter_mask ( uint32_t id, uint8_t ide, uint8_t rtr ) { if (ide) { id <<= 3u; } else { id <<= 21; /* Set unused ID bits to 1! */ id |= (0x3FFFF << 3u); } id |= ((uint32_t)(ide << 2u) | (uint32_t)(rtr << 1u)); return (id); } /***************************************************************************//** * MSS_CAN_set_int_ebl() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_set_int_ebl ( mss_can_instance_t* this_can, uint32_t irq_flag ) { this_can->hw_reg->IntEbl.L |= irq_flag; } /***************************************************************************//** * MSS_CAN_clear_int_ebl() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_clear_int_ebl ( mss_can_instance_t* this_can, uint32_t irq_flag ) { this_can->hw_reg->IntEbl.L &= ~irq_flag; } /***************************************************************************//** * MSS_CAN_get_global_int_ebl() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_global_int_ebl ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->IntEbl.INT_EBL); } /***************************************************************************//** * MSS_CAN_get_int_ebl() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_int_ebl ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->IntEbl.L & CAN_INT_MASK); } /***************************************************************************//** * MSS_CAN_clear_int_status() * See "mss_can.h" for details of how to use this function. */ void MSS_CAN_clear_int_status ( mss_can_instance_t* this_can, uint32_t irq_flag ) { this_can->hw_reg->IntStatus.L = irq_flag; } /***************************************************************************//** * MSS_CAN_get_int_status() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_int_status ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->IntStatus.L); } /***************************************************************************//** * MSS_CAN_set_rtr_message_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_set_rtr_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { return (CAN_BASIC_CAN_MAILBOX); } /* Is buffer configured for RTR auto-replay? */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLY == 0u) { return (CAN_NO_RTR_MAILBOX); } else { /* Transfer the ID. */ this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; return (CAN_OK); } } /***************************************************************************//** * MSS_CAN_get_rtr_message_abort_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_rtr_message_abort_n ( mss_can_instance_t* this_can, uint8_t mailbox_number ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { /* Mailbox is configured for basic CAN */ return (CAN_BASIC_CAN_MAILBOX); } /* Set abort request */ this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRABORT = 1u; /* Check the abort is granted */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.RTRREPLYPEND == 0u) { /* If the RX buffer isn't busy. Abort was successful */ return (CAN_OK); } else { /* Message not aborted.*/ return (CAN_ERR); } } /***************************************************************************//** * MSS_CAN_config_buffer() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_config_buffer ( mss_can_instance_t* this_can, pmss_can_filterobject pfilter ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_rx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that has a message available */ for (mailbox_number = CAN_RX_MAILBOX - this_can->basic_can_rx_mb; \ mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { /* Set filters */ this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pfilter->ACR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pfilter->AMR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pfilter->AMCR_D.MASK; this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pfilter->AMCR_D.CODE; /* Configure mailbox */ if (mailbox_number < (CAN_RX_MAILBOX - 1)) { /* set link flag, if not last buffer */ this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \ CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL | \ CAN_RX_LINK_EBL); } else { this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \ CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL); } success = CAN_OK; } return (success); } /***************************************************************************//** * MSS_CAN_config_buffer_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_config_buffer_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_rxmsgobject pmsg ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { return (CAN_BASIC_CAN_MAILBOX); } /* Configure mailbox */ this_can->hw_reg->RxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->RxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; this_can->hw_reg->RxMsg[mailbox_number].ACR.L = pmsg->ACR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR.L = pmsg->AMR.L; this_can->hw_reg->RxMsg[mailbox_number].AMR_D = pmsg->AMR_D; this_can->hw_reg->RxMsg[mailbox_number].ACR_D = pmsg->ACR_D; this_can->hw_reg->RxMsg[mailbox_number].RXB.L = (pmsg->RXB.L | \ CAN_RX_WPNH_EBL | CAN_RX_WPNL_EBL | \ CAN_RX_BUFFER_EBL | CAN_RX_INT_EBL); return (CAN_OK); } /***************************************************************************//** * MSS_CAN_get_message_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_RX_MAILBOX - this_can->basic_can_rx_mb)) { return (CAN_BASIC_CAN_MAILBOX); } /* Check that a new message is available and get it */ if ((ENABLE == this_can->hw_reg->Command.RUN_STOP) && (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV)) { /* Copy ID */ pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID; /* Copy 4 of the data bytes */ pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW; /* Copy the other 4 data bytes. */ pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH; /* Get DLC, IDE and RTR and time stamp. */ pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L; /* Ack that it's been removed from the FIFO */ this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE; /* And let app know there is a message. */ return (CAN_VALID_MSG); } else { return (CAN_NO_MSG); } } /******************************************************************************* * MSS_CAN_get_message() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_message ( mss_can_instance_t* this_can, pmss_can_msgobject pmsg ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_rx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that has a message available */ for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb; \ mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { /* Check that if there is a valid message */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV) { /* Copy ID */ pmsg->ID = this_can->hw_reg->RxMsg[mailbox_number].ID; /* Copy 4 of the data bytes */ pmsg->DATALOW = this_can->hw_reg->RxMsg[mailbox_number].DATALOW; /* Copy the other 4 data bytes.*/ pmsg->DATAHIGH = this_can->hw_reg->RxMsg[mailbox_number].DATAHIGH; /* Get DLC, IDE and RTR and time stamp.*/ pmsg->L = this_can->hw_reg->RxMsg[mailbox_number].RXB.L; /* Ack that it's been removed from the FIFO */ this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV = ENABLE; success = CAN_VALID_MSG; break; } } return (success); } /***************************************************************************//** * MSS_CAN_get_message_av() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_message_av ( mss_can_instance_t* this_can ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_rx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that has a message available */ for (mailbox_number = CAN_RX_MAILBOX-this_can->basic_can_rx_mb; \ mailbox_number < CAN_RX_MAILBOX; mailbox_number++) { /* Check that buffer is enabled and contains a message */ if (this_can->hw_reg->RxMsg[mailbox_number].RXB.MSGAV) { success = CAN_VALID_MSG; break; } } return (success); } /***************************************************************************//** * MSS_CAN_send_message_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ) { /* Can't send if device is disabled */ if (DISABLE == this_can->hw_reg->Command.RUN_STOP) { /* Message not sent. */ return (CAN_NO_MSG); } /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb)) { /* mailbox is configured for basic CAN */ return (CAN_BASIC_CAN_MAILBOX); } if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u) { /* If the Tx buffer isn't busy.... */ this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \ CAN_TX_WPNH_EBL | \ CAN_TX_REQ); return (CAN_VALID_MSG); } else { /* Message not sent. */ return (CAN_NO_MSG); } } /***************************************************************************//** * MSS_CAN_send_message_abort_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message_abort_n ( mss_can_instance_t* this_can, uint8_t mailbox_number ) { /* Is buffer configured for Full CAN? */ if (mailbox_number >= (CAN_TX_MAILBOX - this_can->basic_can_tx_mb)) { /* mailbox is configured for basic CAN */ return (CAN_BASIC_CAN_MAILBOX); } /* Set abort request */ this_can->hw_reg->TxMsg[mailbox_number].TXB.L = ((this_can->hw_reg->TxMsg[mailbox_number].TXB.L & ~CAN_TX_REQ) | \ CAN_TX_ABORT); /* Check the abort is granted */ if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXABORT == 0u) { /* If the Tx buffer isn't busy, Abort was successful */ return (CAN_OK); } else { /* Message not aborted. */ return (CAN_ERR); } } /***************************************************************************//** * MSS_CAN_send_message_ready() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message_ready ( mss_can_instance_t* this_can ) { uint8_t success = CAN_ERR; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_tx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that is available */ for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \ mailbox_number < CAN_TX_MAILBOX; mailbox_number++) { if (this_can->hw_reg->TxMsg[mailbox_number].TXB.TXREQ == 0u) { /* Tx buffer isn't busy */ success = CAN_OK; break; } } return (success); } /***************************************************************************//** * MSS_CAN_send_message() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_send_message ( mss_can_instance_t* this_can, pmss_can_msgobject pmsg ) { uint8_t success = CAN_NO_MSG; uint8_t mailbox_number; /* Is a buffer configured for Basic CAN? */ if (this_can->basic_can_tx_mb == 0u) { return (CAN_INVALID_MAILBOX); } /* Find next BASIC CAN buffer that is available */ for (mailbox_number = CAN_TX_MAILBOX-this_can->basic_can_tx_mb; \ mailbox_number < CAN_TX_MAILBOX; mailbox_number++) { /* Check which transmit mailbox is not busy and use it. */ if ((MSS_CAN_get_tx_buffer_status(this_can) & (1u << mailbox_number)) == 0) { /* If the Tx buffer isn't busy.... */ this_can->hw_reg->TxMsg[mailbox_number].ID = pmsg->ID; this_can->hw_reg->TxMsg[mailbox_number].DATALOW = pmsg->DATALOW; this_can->hw_reg->TxMsg[mailbox_number].DATAHIGH = pmsg->DATAHIGH; this_can->hw_reg->TxMsg[mailbox_number].TXB.L = (pmsg->L | \ CAN_TX_WPNH_EBL | \ CAN_TX_REQ); success = CAN_VALID_MSG; break; } } return (success); } /***************************************************************************//** * MSS_CAN_get_mask_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_mask_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, uint32_t *pamr, uint32_t *pacr, uint16_t *pdta_amr, uint16_t *pdta_acr ) { if (mailbox_number >= CAN_RX_MAILBOX) { return (CAN_BASIC_CAN_MAILBOX); } *pamr = this_can->hw_reg->RxMsg[mailbox_number].AMR.L; *pacr = this_can->hw_reg->RxMsg[mailbox_number].ACR.L; *pdta_acr = this_can->hw_reg->RxMsg[mailbox_number].ACR_D; *pdta_amr = this_can->hw_reg->RxMsg[mailbox_number].AMR_D; return (CAN_OK); } /***************************************************************************//** * MSS_CAN_set_mask_n() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_set_mask_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, uint32_t amr, uint32_t acr, uint16_t dta_amr, uint16_t dta_acr ) { if (mailbox_number >= CAN_RX_MAILBOX) { return (CAN_BASIC_CAN_MAILBOX); } this_can->hw_reg->RxMsg[mailbox_number].AMR.L = amr; this_can->hw_reg->RxMsg[mailbox_number].ACR.L = acr; this_can->hw_reg->RxMsg[mailbox_number].AMR_D = (uint32_t)dta_amr; this_can->hw_reg->RxMsg[mailbox_number].ACR_D = (uint32_t)dta_acr; return (CAN_OK); } /***************************************************************************//** * MSS_CAN_get_rx_buffer_status() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_rx_buffer_status ( mss_can_instance_t* this_can ) { #ifdef CANMOD3 return (this_can->hw_reg->BufferStatus.L & 0x0000FFFF); #else return (this_can->hw_reg->BufferStatus.RXMSGAV); #endif } /***************************************************************************//** * MSS_CAN_get_tx_buffer_status() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_tx_buffer_status ( mss_can_instance_t* this_can ) { #ifdef CANMOD3 return ((this_can->hw_reg->BufferStatus.L >> 16u) & 0x00FF); #else return (this_can->hw_reg->BufferStatus.TXREQ); #endif } /***************************************************************************//** * MSS_CAN_get_error_status() * See "mss_can.h" for details of how to use this function. */ uint8_t MSS_CAN_get_error_status ( mss_can_instance_t* this_can, uint32_t *status ) { /* Supply error register info if user wants. */ *status = this_can->hw_reg->ErrorStatus.L; /* 00 Error Active, 01 Error Passive, 1x Bus Off */ return ((uint8_t)(((*status) >> CAN_ERROR_STATUS_SHIFT) & CAN_ERROR_STATUS_MASK)); } /***************************************************************************//** * MSS_CAN_get_rx_error_count() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_rx_error_count ( mss_can_instance_t* this_can ) { return ((this_can->hw_reg->ErrorStatus.L >> CAN_ERROR_COUNT_SHIFT) & \ CAN_ERROR_COUNT_MASK); } /***************************************************************************//** * MSS_CAN_get_rx_gte96() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_rx_gte96 ( mss_can_instance_t* this_can ) { return ((this_can->hw_reg->ErrorStatus.L >> CAN_RX_GTE96_SHIFT) & \ CAN_FLAG_MASK); } /***************************************************************************//** * MSS_CAN_get_tx_error_count() * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_tx_error_count ( mss_can_instance_t* this_can ) { return (this_can->hw_reg->ErrorStatus.L & CAN_ERROR_COUNT_MASK); } /***************************************************************************//** * MSS_CAN_get_tx_gte96 () * See "mss_can.h" for details of how to use this function. */ uint32_t MSS_CAN_get_tx_gte96 ( mss_can_instance_t* this_can ) { return ((this_can->hw_reg->ErrorStatus.L >> CAN_TXGTE96_SHIFT) & \ CAN_FLAG_MASK); } /******************************************************************************* * Global initialization for all modes */ static void global_init ( mss_can_instance_t* this_wd ) { if (&g_mss_can_0_lo == this_wd) { this_wd->hw_reg = MSS_CAN_0_LO_BASE; this_wd->irqn = CAN0_PLIC; this_wd->int_type = 0; } else if (&g_mss_can_1_lo == this_wd) { this_wd->hw_reg = MSS_CAN_1_LO_BASE; this_wd->irqn = CAN1_PLIC; this_wd->int_type = 0; } else if (&g_mss_can_0_hi == this_wd) { this_wd->hw_reg = MSS_CAN_0_HI_BASE; this_wd->irqn = CAN0_PLIC; this_wd->int_type = 0; } else if (&g_mss_can_1_hi == this_wd) { this_wd->hw_reg = MSS_CAN_1_HI_BASE; this_wd->irqn = CAN1_PLIC; this_wd->int_type = 0; } else { ;/* LDRA Warning */ } } #ifndef MSS_CAN_USER_ISR /***************************************************************************//** * CAN interrupt service routine. * CAN_IRQHandler is included within the RISC-V vector table as part of the * MPFS HAL. */ uint8_t External_can0_plic_IRQHandler(void) { #ifdef MSS_CAN_ENABLE_INTERRUPTS /* User provided code is required here to handle interrupts from the MSS CAN * peripheral. Remove the assert once this is in place.*/ ASSERT(!"An ISR is required here if interrupts are enabled"); #else ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \ disabled"); #endif return 0; } uint8_t can1_IRQHandler(void) { #ifdef MSS_CAN_ENABLE_INTERRUPTS /* User provided code is required here to handle interrupts from the MSS CAN * peripheral. Remove the assert once this is in place.*/ ASSERT(!"An ISR is required here if interrupts are enabled"); #else ASSERT(!"Unexpected MSS CAN interrupt - MSS CAN NVIC Interrupts should be \ disabled"); #endif return 0; } #endif #ifdef __cplusplus } #endif mss_can.h000066400000000000000000002510771432224323300365060ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_can/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC microprocessor subsystem CAN bare metal software driver public * API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire MSS CAN Bare Metal Driver. ============================================================================== Introduction ============================================================================== The PolarFire SoC microprocessor subsystem (MSS) includes two CAN controller. The CAN controller is configurable to provide support for up to 32 transmit and 32 receive mailboxes. This PolarFire SoC MSS CAN driver provides a set of functions for accessing and controlling the MSS CAN as part of a bare metal system where no operating system is available. The driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of the driver. -------------------------------- Features -------------------------------- The MSS CAN driver provides support for the following features: - Basic CAN APIs if application needs support for Basic CAN operation. (Configure as FIFO by linking several mailboxes together, one message filter for entire FIFO) - Full CAN APIs (each mail box has its own message filter) - Support for 11 bit and 29 bit message identifiers - Support for Data frame and Remote frames - Error detection mechanism ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all features of the PolarFire MSS CAN is covered by this driver, with the exception of the PolarFire SoC IOMUX configuration. The PolarFire SoC allows multiple non-concurrent uses of few external pins through IOMUX configuration. This feature allows optimization of external pin usage by assigning external pins for use by either the microprocessor subsystem or the FPGA fabric. The MSS CAN serial signals are routed through IOMUXs to the PolarFire SoC device external pins. The MSS CAN serial signals can also be routed through IOMUXs to the PolarFire SoC FPGA fabric. For more information on IOMUX, see the IOMUX section of the PolarFire SoC Microprocessor Subsystem (MSS) User's Guide. The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You must ensure that the MSS CAN peripherals are enabled and configured in the PolarFire SoC MSS configurator if you wish to use them. For more information on IOMUXs, refer to the IOMUX section of the PolarFire SoC microprocessor Subsystem (MSS) User's Guide. On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple masters and multiple slaves. Five RISC-V CPUs connect to the Master ports M10 to M14 of the AXI switch. By default, all the APB peripherals are accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB bridges (referred as main APB bus). However, to support logical separation in the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to APB bridges (referred as the AMP APB bus). Application must make sure that the desired CAN instance is appropriately configured on one of the APB bus described above by configuring the PolarFire SoC system registers (SYSREG) as per the application need and that the appropriate data structures are provided to this driver as parameter to the functions provided by this driver. The base address and the register addresses are defined in this driver as constants. The interrupt number assignment for the MSS CAN peripherals is defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole toolchain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS CAN driver uses one instance of the mss_can_instance_t structure per port. This instance is used to identify the target port and a pointer to this instance is passed as the first argument to all CAN driver functions. The PolarFire SoC MSS CAN driver operations can be divided in following sub-sections: - CAN Controller Configuration - Operation Status - Interrupt Support - Helper Functions - Basic CAN Message Handling - Full CAN Message Handling -------------------------------- Configuration -------------------------------- The MSS CAN driver must first be initialized and the mode of operation must be selected before performing data transfers on CAN Bus. The MSS_CAN_init() function is used to initialize the CAN controller and driver. Set CAN controller operation mode as normal operation using MSS_CAN_set_mode() function. The operating mode of operation is selected using MSS_CAN_set_mode() function. The actual data transfer can be started using start the CAN controller by using MSS_CAN_start() function, with this actual data transmission or reception shall start. MSS_CAN_stop() function is used to stops the CAN controller. Once initialized, during normal mode of operation, the MSS CAN driver configuration can be changed using MSS_CAN_set_config_reg() function is used to change the CAN controllers configuration during normal operation. -------------------------------- Operation Status -------------------------------- MSS_CAN_get_error_status() function returns the current CAN error state (error active, error passive, and bus off). The MSS_CAN_get_rx_error_count() and MSS_CAN_get_tx_error_count() functions return the actual receive and transmit error counter values while MSS_CAN_get_rx_gte96() function and MSS_CAN_get_tx_gte96() function show if the error counters are greater or equal to 96, which indicates a heavily disturbed bus. -------------------------------- Interrupt Support -------------------------------- The interrupt service routines are not part of the CAN driver. But access functions for the interrupt registers are provided. The individual interrupt enable bits can be set using MSS_CAN_set_int_ebl() function and individual interrupt enable bits can be cleared using MSS_CAN_clear_int_ebl while MSS_CAN_get_int_ebl() function returns their actual state. MSS_CAN_get_global_int_ebl() function indicates if interrupt generation is enabled at all. MSS_CAN_get_int_status() function shows the current state of the different interrupt status bits. Each interrupt status bit can be individually cleared using MSS_CAN_clear_int_status() function. The interrupt service routines are not part of the MSS CAN driver and the driver ships with the MSS_CAN_ENABLE_INTERRUPTS macro disabled which stops the MSS CAN interrupt being enabled at the PLIC, however a stub ISR is present in the mss_can.c file to show the format of the function and catch any unexpected interrupts to aid in debugging. -------------------------------- Helper Functions -------------------------------- The MSS CAN peripheral expects all ID bits to be left aligned. This makes setting the ID cumbersome. Using MSS_CAN_set_id(), a given right-aligned ID field is modified according to the ID size which is indicated by the IDE bit. MSS_CAN_get_id() provides the reverse operation: It returns the ID right aligned. MSS_CAN_get_msg_filter_mask() packs the ID, IDE, and RTR bits together as they are used in the mask registers. MSS_CAN_get_mask_n() returns the message filter settings of the selected receive mailbox. MSS_CAN_set_mask_n() configures the message filter settings for the selected receive mailbox. -------------------------------- Basic CAN Message Handling -------------------------------- A Basic CAN type controller contains one or more message filter and one common message buffer or FIFO. The CAN driver contains some functions to emulate Basic CAN operation by linking several buffers together to form a buffer array that shares one message filter. Since this buffer array is not a real FIFO, message inversion might happen (eg, a newer message might be pulled from the receive buffer prior to an older message). Before using the Basic CAN API, the CAN controller has to be configured first with a MSS_CAN_config_buffer() function call. This sets up the message array and configures the message filter. MSS_CAN_send_message() function and MSS_CAN_get_message() function are used to send and receive a message from transmit or receive buffers. MSS_CAN_send_message_ready() function indicates if a new message can be sent. MSS_CAN_get_message_av() function shows if a new message is available. -------------------------------- Full CAN Message Handling -------------------------------- In Full CAN operation, each message mailbox has its own message filter. This reduces the number of receive interrupts as the host CPU only gets an interrupt when a message of interest has arrived. Further, software based message filtering overhead is reduced and there is less message to be checked. Before a buffer can be used for Full CAN operation, it needs to be configured using MSS_CAN_config_buffer_n() function. An error is generated if this buffer is already reserved for Basic CAN operation. The MSS_CAN_get_rx_buffer_status() and MSS_CAN_get_tx_buffer_status() functions indicate the current state of the receive and transmit buffers respectively. With MSS_CAN_send_message_n() function a message can be sent using buffer. A pending message transfer can be aborted with MSS_CAN_send_message_abort_n() function and a message can be read with MSS_CAN_get_message_n() function. If a buffer is set for automatic RTR reply, MSS_CAN_set_rtr_message_n() function sets the CAN message that is returned upon reception of the RTR message. MSS_CAN_get_rtr_message_abort_n() function aborts a RTR message transmit request. NOTE: 1. User has to set the RTR message filter to match with MSS_CAN_rtr_message_abort_n() function a pending RTR auto-reply can be aborted. 2. An error is generated if buffer is already reserved for Basic CAN operation and is trying to use the same buffer for Full CAN functionality. 3. Special case of Full CAN where several mailboxes are linked together to create FIFOs that share an identical message filter configuration, can be built upon the available Full CAN functions. *//*=========================================================================*/ #ifndef MSS_CAN_H_ #define MSS_CAN_H_ #ifdef __cplusplus extern "C" { #endif #define __I const volatile #define __IO volatile #define __O volatile /* The following macro MSS_CAN_ENABLE_INTERRUPTS must be defined to allow the * enabling of the MSS CAN peripheral interrupts at the PLIC level. * This version of the MSS CAN driver does not provide any support for MSS CAN * interrupts and so this MACRO should be disabled unless there is a user * supplied ISR. */ #if 0 #define MSS_CAN_ENABLE_INTERRUPTS #endif /** * Define CAN target device * * CANMOD3: Device with 16 Rx and 8 Tx mailboxes * CANMOD3X: Device with 32 Rx and 32 Tx mailboxes */ #define CANMOD3X #ifdef CANMOD3 #define CAN_RX_MAILBOX 16u #define CAN_TX_MAILBOX 8u #else #define CAN_RX_MAILBOX 32u #define CAN_TX_MAILBOX 32u #endif /* Configuration and Speed definitions */ #define CAN_PRESET (mss_can_config_reg.L)0 #define CAN_SAMPLE_BOTH_EDGES 0x00000001u #define CAN_THREE_SAMPLES 0x00000002u #define CAN_SET_SJW(_sjw) (_sjw<<2u) #define CAN_AUTO_RESTART 0x00000010u #define CAN_SET_TSEG2(_tseg2) (_tseg2<<5u) #define CAN_SET_TSEG1(_tseg1) (_tseg1<<8u) #define CAN_SET_BITRATE(_bitrate) (_bitrate<<16u) #define CAN_ARB_ROUNDROBIN 0x00000000u #define CAN_ARB_FIXED_PRIO 0x00001000u #define CAN_BIG_ENDIAN 0x00000000u #define CAN_LITTLE_ENDIAN 0x00002000u /* Manual setting with specified fields */ #define CAN_SPEED_MANUAL 0u /*-------------------------------------------------------------------------*//** The following constants are used in the PolarFire SoC MSS CAN driver for bitrate definitions: | Constants | Description | |--------------------|-----------------------------------------------------| | CAN_SPEED_8M_5K | Indicates CAN controller shall be configured with | | | 5Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_5K | Indicates CAN controller shall be configured with | | | 5Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_5K | Indicates CAN controller shall be configured with | | | 5Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_10K | Indicates CAN controller shall be configured with | | | 10Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_10K | Indicates CAN controller shall be configured with | | | 10Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_10K | Indicates CAN controller shall be configured with | | | 10Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_20K | Indicates CAN controller shall be configured with | | | 20Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_20K | Indicates CAN controller shall be configured with | | | 20Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_20K | Indicates CAN controller shall be configured with | | | 20Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_50K | Indicates CAN controller shall be configured with | | | 50Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_50K | Indicates CAN controller shall be configured with | | | 50Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_50K | Indicates CAN controller shall be configured with | | | 50Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_100K | Indicates CAN controller shall be configured with | | | 100Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_100K | Indicates CAN controller shall be configured with | | | 100Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_100K | Indicates CAN controller shall be configured with | | | 100Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_125K | Indicates CAN controller shall be configured with | | | 125Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_125K | Indicates CAN controller shall be configured with | | | 125Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_125K | Indicates CAN controller shall be configured with | | | 125Kbps baud rate if the input clock is 32MHz. | | AN_SPEED_8M_250K | Indicates CAN controller shall be configured with | | | 250Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_250K | Indicates CAN controller shall be configured with | | | 250Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_250K | Indicates CAN controller shall be configured with | | | 250Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_500K | Indicates CAN controller shall be configured with | | | 500Kbps baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_500K | Indicates CAN controller shall be configured with | | | 500Kbps baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_500K | Indicates CAN controller shall be configured with | | | 500Kbps baud rate if the input clock is 32MHz. | | CAN_SPEED_8M_1M | Indicates CAN controller shall be configured with | | | 1MBPS baud rate if the input clock is 8MHz. | | CAN_SPEED_16M_1M | Indicates CAN controller shall be configured with | | | 1MBPS baud rate if the input clock is 16MHz. | | CAN_SPEED_32M_1M | Indicates CAN controller shall be configured with | | | 1MBPS baud rate if the input clock is 32MHz. | */ /* 5000m 81% Sample bit three times */ #define CAN_SPEED_8M_5K CAN_SET_BITRATE(99)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES #define CAN_SPEED_16M_5K CAN_SET_BITRATE(199)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES #define CAN_SPEED_32M_5K CAN_SET_BITRATE(399)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES /* 5000m 81% Sample bit three times */ #define CAN_SPEED_8M_10K CAN_SET_BITRATE(49)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES #define CAN_SPEED_16M_10K CAN_SET_BITRATE(99)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES #define CAN_SPEED_32M_10K CAN_SET_BITRATE(199)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES /* 2500m 81% Sample bit three times */ #define CAN_SPEED_8M_20K CAN_SET_BITRATE(24)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES #define CAN_SPEED_16M_20K CAN_SET_BITRATE(49)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES #define CAN_SPEED_32M_20K CAN_SET_BITRATE(99)|CAN_SET_TSEG1(11)|CAN_SET_TSEG2(2)|CAN_THREE_SAMPLES /* 1000m 87% */ #define CAN_SPEED_8M_50K CAN_SET_BITRATE(9)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_16M_50K CAN_SET_BITRATE(19)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_32M_50K CAN_SET_BITRATE(39)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) /* 600m 87% */ #define CAN_SPEED_8M_100K CAN_SET_BITRATE(4)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_16M_100K CAN_SET_BITRATE(9)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_32M_100K CAN_SET_BITRATE(19)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) /* 500m 87% */ #define CAN_SPEED_8M_125K CAN_SET_BITRATE(3)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_16M_125K CAN_SET_BITRATE(7)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_32M_125K CAN_SET_BITRATE(15)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) /* 250m 87% */ #define CAN_SPEED_8M_250K CAN_SET_BITRATE(1)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_16M_250K CAN_SET_BITRATE(3)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_32M_250K CAN_SET_BITRATE(7)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) /* 100m 75% @ 8M, 87% @ 16M */ #define CAN_SPEED_8M_500K CAN_SET_BITRATE(1)|CAN_SET_TSEG1(4)|CAN_SET_TSEG2(1) #define CAN_SPEED_16M_500K CAN_SET_BITRATE(1)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) #define CAN_SPEED_32M_500K CAN_SET_BITRATE(3)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) /* 25m 75% */ #define CAN_SPEED_8M_1M CAN_SET_BITRATE(0)|CAN_SET_TSEG1(4)|CAN_SET_TSEG2(1) #define CAN_SPEED_16M_1M CAN_SET_BITRATE(1)|CAN_SET_TSEG1(4)|CAN_SET_TSEG2(1) #define CAN_SPEED_32M_1M CAN_SET_BITRATE(1)|CAN_SET_TSEG1(12)|CAN_SET_TSEG2(1) /*-------------------------------------------------------------------------*//** The following constants are used for error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_OK | Indicates there is no error | | CAN_ERR | Indicates error condition | | CAN_TSEG1_TOO_SMALL | Value provided to configure TSEG1 is too | | | small | | CAN_TSEG2_TOO_SMALL | Value provided to configure TSEG2 is too | | | small | | CAN_SJW_TOO_BIG | Value provided to configure synchronous jump| | | width (SJW) is too big. | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | | CAN_NO_RTR_MAILBOX | Indicates that there is no mailbox for | | | remote transmit request (RTR) frame | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | */ #define CAN_OK 0u #define CAN_ERR 1u #define CAN_TSEG1_TOO_SMALL 2u #define CAN_TSEG2_TOO_SMALL 3u #define CAN_SJW_TOO_BIG 4u #define CAN_BASIC_CAN_MAILBOX 5u #define CAN_NO_RTR_MAILBOX 6u #define CAN_INVALID_MAILBOX 7u /* Flag bits */ #define CAN_NO_MSG 0x00u #define CAN_VALID_MSG 0x01u /* * A couple of definitions just to make the code more readable so we know * what a 1 and 0 mean. #define CAN_RTR 1<<21 #define CAN_EXT_IDE 1<<20 /*-------------------------------------------------------------------------*//** The following constants are used in the MSS CAN driver for Interrupt Bit Definitions | Constants | Description | |--------------------------|------------------------------------------------| | CAN_INT_GLOBAL | Indicates to enable global interrupts | | CAN_INT_ARB_LOSS | Indicates arbitration loss interrupt | | CAN_INT_OVR_LOAD | Indicates overload message detected interrupt | | CAN_INT_BIT_ERR | Indicates bit error interrupt | | CAN_INT_STUFF_ERR | Indicates bit stuffing error interrupt | | CAN_INT_ACK_ERR | Indicates acknowledge error interrupt | | CAN_INT_FORM_ERR | Indicates format error interrupt | | CAN_INT_CRC_ERR | Indicates CRC error interrupt | | CAN_INT_BUS_OFF | Indicates bus off interrupt | | CAN_INT_RX_MSG_LOST | Indicates received message lost interrupt | | CAN_INT_TX_MSG | Indicates message transmit interrupt | | CAN_INT_RX_MSG | Indicates receive message available interrupt | | CAN_INT_RTR_MSG | Indicates RTR auto-reply message sent interrupt| | CAN_INT_STUCK_AT_0 | Indicates stuck at dominant error interrupt | | CAN_INT_SST_FAILURE | Indicates single shot transmission failure | | | interrupt | */ #define CAN_INT_GLOBAL 1<<0 /* Global interrupt */ #define CAN_INT_ARB_LOSS 1<<2 /* Arbitration loss interrupt */ #define CAN_INT_OVR_LOAD 1<<3 /*Overload interrupt */ #define CAN_INT_BIT_ERR 1<<4 /* Bit error interrupt */ #define CAN_INT_STUFF_ERR 1<<5 /* Bit stuffing error interrupt */ #define CAN_INT_ACK_ERR 1<<6 /* Acknowledgement error interrupt */ #define CAN_INT_FORM_ERR 1<<7 /* Format error interrupt */ #define CAN_INT_CRC_ERR 1<<8 /* CRC error interrupt */ #define CAN_INT_BUS_OFF 1<<9 /* Bus-off interrupt */ #define CAN_INT_RX_MSG_LOST 1<<10 /* Rx message lost interrupt */ #define CAN_INT_TX_MSG 1<<11 /* Tx message interupt */ #define CAN_INT_RX_MSG 1<<12 /* Rx message interrupt */ #define CAN_INT_RTR_MSG 1<<13 /* RTR message interrupt */ #define CAN_INT_STUCK_AT_0 1<<14 /* Stuck-at-0 error interrupt */ #define CAN_INT_SST_FAILURE 1<<15 /* Single-shot transmission error interrupt*/ /*-------------------------------------------------------------------------*//** The following constants are used for transmit message buffer control bit definitions: | Constants | Description | |--------------------------|------------------------------------------------| | CAN_TX_WPNH_EBL | Indicates "WPNH" bit mask | | CAN_TX_WPNL_EBL | Indicates WPNL bit mask | | CAN_TX_REQ | Indicates transmit request flag bit position | | CAN_TX_INT_EBL | Indicates transmit Interrupt enable bit mask | | CAN_TX_ABORT | Indicates Transmit abort mask | */ #define CAN_TX_WPNH_EBL 1<<23 #define CAN_TX_WPNL_EBL 1<<3 #define CAN_TX_INT_EBL 1<<2 #define CAN_TX_ABORT 1<<1 #define CAN_TX_REQ 0x01u /*-------------------------------------------------------------------------*//** The following constants are used for receive message buffer control bit definitions: | Constants | Description | |--------------------------|------------------------------------------------| | CAN_RX_WPNH_EBL | Indicates WPNH bit mask. | | CAN_RX_WPNL_EBL | Indicates WPNL bit mask | | CAN_RX_LINK_EBL | Indicates link flag bit mask | | CAN_RX_INT_EBL | Indicates receive interrupt enable bit mask | | CAN_RX_RTR_REPLY_EBL | Indicates RTR reply bit mask | | CAN_RX_BUFFER_EBL | Indicates Transaction buffer enable bit mask | | CAN_RX_RTR_ABORT | Indicates RTR abort request mask | | CAN_RX_RTRP | Indicates RTReply pending status mask | | CAN_RX_MSGAV | Indicates receive message available status mask| */ #define CAN_RX_WPNH_EBL 1<<23 #define CAN_RX_WPNL_EBL 1<<7 #define CAN_RX_LINK_EBL 1<<6 #define CAN_RX_INT_EBL 1<<5 #define CAN_RX_RTR_REPLY_EBL 1<<4 #define CAN_RX_BUFFER_EBL 1<<3 #define CAN_RX_RTR_ABORT 1<<2 #define CAN_RX_RTRP 1<<1 #define CAN_RX_MSGAV 0x01 /*-------------------------------------------------------------------------*//** The mss_can_mode_t enumeration specifies the possible operating modes of CAN controller. The meaning of the constants is as described below | Modes | Description | |----------------------------|------------------------------------------| | CANOP_MODE_NORMAL | Indicates CAN controller is in normal | | | operational mode. | | CANOP_MODE_LISTEN_ONLY | Indicates CAN controller is in listen | | | only mode. | | CANOP_MODE_EXT_LOOPBACK | Indicates CAN controller is in external | | | loop back mode. | | CANOP_MODE_INT_LOOPBACK | Indicates CAN controller is in internal | | | loop back mode. | | CANOP_SRAM_TEST_MODE | Indicates CAN controller is in test mode.| | CANOP_SW_RESET | Indicates CAN controller is in stop mode.| */ typedef enum mss_can_mode { CANOP_MODE_NORMAL = 0x01u, CANOP_MODE_LISTEN_ONLY = 0x03u, CANOP_MODE_EXT_LOOPBACK = 0x05u, CANOP_MODE_INT_LOOPBACK = 0x07u, CANOP_SRAM_TEST_MODE = 0x08u, CANOP_SW_RESET = 0x10u } mss_can_mode_t; typedef struct _mss_can_msgobject { /* CAN Message ID. */ struct { __IO uint32_t N_ID:3; __IO uint32_t ID:29; }; /* CAN Message Data organized as two 32 bit words or 8 data bytes */ union { struct { __IO uint32_t DATAHIGH; __IO uint32_t DATALOW; }; __IO int8_t DATA[8]; }; /* CAN Message flags and smaller values organized as one single 32 bit word or a number of bit fields. */ union { __IO uint32_t L; /* 32 bit flag */ struct { /* Flags structure. */ __IO uint32_t NA0:16; __IO uint32_t DLC:4; __IO uint32_t IDE:1; __IO uint32_t RTR:1; __IO uint32_t NA1:10; }; }; } mss_can_msgobject; typedef mss_can_msgobject * pmss_can_msgobject; /* _CAN_filterobject */ typedef struct _CAN_filterobject { /* Acceptance mask settings */ union { __IO uint32_t L; struct { __IO uint32_t N_A:1; __IO uint32_t RTR:1; __IO uint32_t IDE:1; __IO uint32_t ID:29; }; } AMR; /* Acceptance code settings */ union { __IO uint32_t L; struct { __IO uint32_t N_A:1; __IO uint32_t RTR:1; __IO uint32_t IDE:1; __IO uint32_t ID:29; }; } ACR; /* Acceptance mask and code settings for first two data bytes */ union { __IO uint32_t L; struct { __IO uint32_t MASK:16; __IO uint32_t CODE:16; }; } AMCR_D; } mss_can_filterobject; typedef mss_can_filterobject * pmss_can_filterobject; /*_CAN_txmsgobject */ typedef struct _CAN_txmsgobject { /* CAN Message flags and smaller values organized as one single 32 bit word or a number of bit fields.*/ union { __IO uint32_t L; /* Tx Flags structure. */ struct { __IO uint32_t TXREQ:1; __IO uint32_t TXABORT:1; __IO uint32_t TXINTEBL:1; __IO uint32_t WPNL:1; __IO uint32_t NA0:12; __IO uint32_t DLC:4; __IO uint32_t IDE:1; __IO uint32_t RTR:1; __IO uint32_t NA1:1; __IO uint32_t WPNH:1; __IO uint32_t NA2:8; }; } TXB; /* CAN Message ID. */ struct { __IO uint32_t N_ID:3; __IO uint32_t ID:29; }; /* CAN Message Data organized as two 32 bit words or 8 data bytes */ union { struct { __IO uint32_t DATAHIGH; __IO uint32_t DATALOW; }; __IO int8_t DATA[8]; }; } mss_can_txmsgobject; /* _mss_can_rxmsgobject */ typedef struct _mss_can_rxmsgobject { /* CAN Message flags and smaller values organized as one single 32 bit word or a number of bit fields. */ union { __IO uint32_t L; /* 32 bit flag */ /* Tx Flags structure. */ struct { __IO uint32_t MSGAV:1; __IO uint32_t RTRREPLYPEND:1; __IO uint32_t RTRABORT:1; __IO uint32_t BUFFEREBL:1; __IO uint32_t RTRREPLY:1; __IO uint32_t RXINTEBL:1; __IO uint32_t LINKFLAG:1; __IO uint32_t WPNL:1; __IO uint32_t NA0:8; __IO uint32_t DLC:4; __IO uint32_t IDE:1; __IO uint32_t RTR:1; __IO uint32_t NA1:1; __IO uint32_t WPNH:1; __IO uint32_t NA2:8; }; } RXB; /* CAN Message ID. */ struct { __IO uint32_t N_ID:3; __IO uint32_t ID:29; }; /* CAN Message Data organized as two 32 bit words or 8 data bytes */ union { struct { __IO uint32_t DATAHIGH; __IO uint32_t DATALOW; }; __IO int8_t DATA[8]; }; /* CAN Message Filter: Acceptance mask register */ union { __IO uint32_t L; struct { __IO uint32_t N_A:1; __IO uint32_t RTR:1; __IO uint32_t IDE:1; __IO uint32_t ID:29; }; } AMR; /* CAN Message Filter: Acceptance code register */ union { __IO uint32_t L; struct { __IO uint32_t N_A:1; __IO uint32_t RTR:1; __IO uint32_t IDE:1; __IO uint32_t ID:29; }; } ACR; __IO uint32_t AMR_D; __IO uint32_t ACR_D; } mss_can_rxmsgobject; typedef mss_can_rxmsgobject * pmss_can_rxmsgobject; /* Error status register */ typedef union error_status { __IO uint32_t L; struct { __IO uint32_t TX_ERR_CNT:8; __IO uint32_t RX_ERR_CNT:8; __IO uint32_t ERROR_STAT:2; __IO uint32_t TXGTE96:1; __IO uint32_t RXGTE96:1; __IO uint32_t N_A:12; }; } mss_can_error_status; /* * Buffer status register For CANMOD3X, * this are two 32-bit registers, for can, it is only one 32-bit register. */ #ifdef CANMOD3 typedef union buffer_status { __I uint32_t L; struct { __I uint32_t RXMSGAV:16; __I uint32_t TXREQ:8; __I uint32_t N_A:8; }; #else typedef struct buffer_status { __I uint32_t RXMSGAV; __I uint32_t TXREQ; #endif } mss_can_buffer_status; /* Interrupt enable register */ typedef union int_enable { __IO uint32_t L; struct { __IO uint32_t INT_EBL:1; __IO uint32_t N_A0:1; __IO uint32_t ARB_LOSS:1; __IO uint32_t OVR_LOAD:1; __IO uint32_t BIT_ERR:1; __IO uint32_t STUFF_ERR:1; __IO uint32_t ACK_ERR:1; __IO uint32_t FORM_ERR:1; __IO uint32_t CRC_ERR:1; __IO uint32_t BUS_OFF:1; __IO uint32_t RX_MSG_LOSS:1; __IO uint32_t TX_MSG:1; __IO uint32_t RX_MSG:1; __IO uint32_t RTR_MSG:1; __IO uint32_t STUCK_AT_0:1; __IO uint32_t SST_FAILURE:1; __IO uint32_t N_A1:16; }; } mss_can_int_enable; typedef mss_can_int_enable * pmss_can_int_enable; /* Interrupt status register */ typedef union int_status { __IO uint32_t L; struct { __IO uint32_t N_A0:2; __IO uint32_t ARB_LOSS:1; __IO uint32_t OVR_LOAD:1; __IO uint32_t BIT_ERR:1; __IO uint32_t STUFF_ERR:1; __IO uint32_t ACK_ERR:1; __IO uint32_t FORM_ERR:1; __IO uint32_t CRC_ERR:1; __IO uint32_t BUS_OFF:1; __IO uint32_t RX_MSG_LOSS:1; __IO uint32_t TX_MSG:1; __IO uint32_t RX_MSG:1; __IO uint32_t RTR_MSG:1; __IO uint32_t STUCK_AT_0:1; __IO uint32_t SST_FAILURE:1; __IO uint32_t N_A1:16; }; } mss_can_int_status; typedef mss_can_int_status * pmss_can_int_status; /* Command register */ typedef union command_reg { __IO uint32_t L; struct { __IO uint32_t RUN_STOP:1; __IO uint32_t LISTEN_ONLY:1; __IO uint32_t LOOP_BACK:1; __IO uint32_t SRAM_TEST:1; __IO uint32_t SW_RESET:1; __IO uint32_t N_A:27; }; } mss_can_command_reg; /* Configuration register */ typedef union can_config_reg { __IO uint32_t L; struct { __IO uint32_t EDGE_MODE:1; __IO uint32_t SAMPLING_MODE:1; __IO uint32_t CFG_SJW:2; __IO uint32_t AUTO_RESTART:1; __IO uint32_t CFG_TSEG2:3; __IO uint32_t CFG_TSEG1:4; __IO uint32_t CFG_ARBITER:1; __IO uint32_t ENDIAN:1; __IO uint32_t ECR_MODE:1; __IO uint32_t N_A0:1; __IO uint32_t CFG_BITRATE:15; __IO uint32_t N_A1:1; }; } mss_can_config_reg; typedef mss_can_config_reg * pmss_can_config_reg ; /* Register mapping of CAN controller */ typedef struct CAN_device { mss_can_int_status IntStatus; /* Interrupt status register */ mss_can_int_enable IntEbl; /* Interrupt enable register */ mss_can_buffer_status BufferStatus; /* Buffer status indicators */ mss_can_error_status ErrorStatus; /* Error status */ mss_can_command_reg Command; /* CAN operating mode */ mss_can_config_reg Config; /* Configuration register */ #ifdef CANMOD3 uint32_t NA[2]; #else uint32_t NA; #endif mss_can_txmsgobject TxMsg[CAN_TX_MAILBOX]; /* Tx message buffers */ mss_can_rxmsgobject RxMsg[CAN_RX_MAILBOX]; /* Rx message buffers */ } CAN_DEVICE; typedef CAN_DEVICE * PCAN_DEVICE; #define MSS_CAN_0_LO_BASE (CAN_DEVICE*)0x2010C000 #define MSS_CAN_1_LO_BASE (CAN_DEVICE*)0x2010D000 #define MSS_CAN_0_HI_BASE (CAN_DEVICE*)0x2810C000 #define MSS_CAN_1_HI_BASE (CAN_DEVICE*)0x2810D000 #define SYSREG_CAN_A_SOFTRESET_MASK ( (uint32_t)0x01u << 14u ) #define SYSREG_CAN_B_SOFTRESET_MASK ( (uint32_t)0x01u << 15u ) /*-------------------------------------------------------------------------*//** The structure mss_can_instance_t is used by the driver to manage the configuration and operation of each MSS CAN peripheral. The instance content should only be accessed by using the respective API functions. Each API function has a pointer to this instance as first argument. */ typedef struct can_instance { /* Hardware related entries (pointer to device, interrupt number etc) */ CAN_DEVICE * hw_reg; /* Pointer to CAN registers. */ uint8_t irqn; /* refer to local or PLIC */ uint8_t int_type; /*!< 0 => local, 1 => PLIC */ /* Local data (eg pointer to local FIFO, irq number etc) */ uint8_t basic_can_rx_mb; /* number of rx mailboxes */ uint8_t basic_can_tx_mb; /* number of tx mailboxes */ } mss_can_instance_t; /*------------------------------------------------------------------------*//** This instances of mss_can_instance_t holds all data related to the operations performed by CAN. A pointer to instance is passed as the first parameter to CAN driver functions to indicate that which CAN instance should perform the requested operation. */ extern mss_can_instance_t g_mss_can_0_lo; extern mss_can_instance_t g_mss_can_1_lo; extern mss_can_instance_t g_mss_can_0_hi; extern mss_can_instance_t g_mss_can_1_hi; /*----------------------------------------------------------------------------*/ /*-----------------------MSS CAN Public APIs ---------------------------------*/ /*----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_CAN_init() function initializes the CAN driver as well as the CAN controller. The basic_can_rx_mb and basic_can_tx_mb are used to configure the number of receive and transmit mailboxes in basic CAN operation. This function configures the CAN channel speed as per the "bitrate" parameter. It initializes all receive mailboxes and make it ready for configuration. This is the first function to be called before using any other function. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param bitrate The bitRate parameter is used to configure CAN speed. The following standard preset definitions are provided for systems with a PCLK1 of 8MHz, 16MHz or 32MHz: +-------------------+--------------------+--------------------+ | 8MHz PCLK1 | 16MHz PCLK1 | 32MHz PCLK1 | +-------------------+--------------------+--------------------+ | CAN_SPEED_8M_5K | CAN_SPEED_16M_5K | CAN_SPEED_32M_5K | | CAN_SPEED_8M_10K | CAN_SPEED_16M_10K | CAN_SPEED_32M_10K | | CAN_SPEED_8M_20K | CAN_SPEED_16M_20K | CAN_SPEED_32M_20K | | CAN_SPEED_8M_50K | CAN_SPEED_16M_50K | CAN_SPEED_32M_50K | | CAN_SPEED_8M_100K | CAN_SPEED_16M_100K | CAN_SPEED_32M_100K | | CAN_SPEED_8M_125K | CAN_SPEED_16M_125K | CAN_SPEED_32M_125K | | CAN_SPEED_8M_250K | CAN_SPEED_16M_250K | CAN_SPEED_32M_250K | | CAN_SPEED_8M_500K | CAN_SPEED_16M_500K | CAN_SPEED_32M_500K | | CAN_SPEED_8M_1M | CAN_SPEED_16M_1M | CAN_SPEED_32M_1M | +-------------------+--------------------+--------------------+ For custom settings, use CAN_SPEED_MANUAL and configure the settings via pcan_config. The default configurations can be altered by the addition of 0 or more of the following: - CAN_AUTO_RESTART - CAN_ARB_FIXED_PRIO - CAN_LITTLE_ENDIAN @param pcan_config The pcan_config parameter is a pointer to a mss_can_config_reg structure. This structure is only used when bitrate is configured as CAN_SPEED_MANUAL. When populating the mss_can_config_reg structure, the following should be noted: 1. CFG_BITRATE defines the length of a CAN time quantum in terms of PCLK1 with 0 = 1 PCLK1, 1 = 2 PCLK1s and so on. 2. A CAN bit time is made up of between 8 and 25 time quanta and the bit rate is PCLK1 / ((CFG_BITRATE + 1) * number of time quanta per bit). 3. There is a fixed overhead of 1 time quantum for synchronization at the start of every CAN bit and the remaining time quanta in the bit are allocated with CFG_TSEG1 and CFG_TSEG2. 4. CFG_TSEG1 can have a value between 2 and 15 which represents between 3 and 16 time quanta. 5. If SAMPLING_MODE is 0, CFG_TSEG2 can have a value between 1 and 7 which represents between 2 and 8 time quanta and if SAMPLING_MODE is 1, CFG_TSEG2 can have a value between 2 and 7 which represents between 3 and 8 time quanta. 6. Receive sampling takes place at the end of the segment defined by CFG_TSEG1. For example, if CFG_TSEG1 = 3 and CFG_TSEG2 = 2 we get: |<------------ 1 CAN bit time (8 time quanta)------------>| /------+------+------+------+------+------+------+------\ -+ Synch | CFG_TSEG1 + 1 | CFG_TSEG2 + 1 +- \------+------+------+------+------+------+------+------/ | Receiver samples date here -->| @param basic_can_rx_mb The basic_can_rx_mb parameter is the number of receive mailboxes used in basic CAN mode. @param basic_can_tx_mb The basic_can_tx_mb parameter is the number of transmit mailboxes used in basic CAN mode. @return This function returns CAN_OK on successful execution, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_ERR | Indicates error condition | | CAN_TSEG1_TOO_SMALL | Value provided to configure TSEG1 is too | | | small | | CAN_TSEG2_TOO_SMALL | Value provided to configure TSEG2 is too | | | small | | CAN_SJW_TOO_BIG | Value provided to configure synchronous jump| | | width (SJW) is too big. | Example 1: Using a default set for bitrate, tseg1, tseg2, and sjw and additional configuration parameters. @code mss_can_instance_t g_mss_can_0_lo; int e51(void) { MSS_CAN_init(&g_mss_can_0_lo, (CAN_SPEED_16M_500K | CAN_AUTO_RESTART | \ CAN_LITTLE_ENDIAN),(pmss_can_config_reg)0,16u,7u); return(0); } @endcode Example 2: Using custom settings for bitrate, tseg1, tseg2, and sjw. @code mss_can_instance_t g_mss_can_0_lo; #define SYSTEM_CLOCK 8000000 #define BITS_PER_SECOND 10000 int e51(void) { mss_can_config_reg canreg; canreg.CFG_BITRATE = (SYSTEM_CLOCK / (BITS_PER_SECOND * 8) - 1; canreg.CFG_TSEG1 = 4; canreg.CFG_TSEG2 = 1; canreg.AUTO_RESTART = 0; canreg.CFG_SJW = 0; canreg.SAMPLING_MODE = 0; canreg.EDGE_MODE = 0; canreg.ENDIAN = 1; MSS_CAN_init(&g_mss_can_0_lo,CAN_SPEED_MANUAL,&canreg,8,4); return(0); } @endcode */ uint8_t MSS_CAN_init ( mss_can_instance_t* this_can, uint32_t bitrate, pmss_can_config_reg pcan_config, uint8_t basic_can_rx_mb, uint8_t basic_can_tx_mb ); /*------------------------------------------------------------------------*//** The MSS_CAN_set_config_reg() function sets the configuration register and starts the CAN controller for normal mode operation. This function is used when one needs to change the configuration settings while the CAN controller was already initialized using MSS_CAN_init() function and is running. MSS_CAN_set_config_reg() function should not be used when the CAN controller wasn't initialized yet. It performs following tasks: - Clears all pending interrupts - Stops CAN controller - Disable interrupts - Sets new configuration - Starts CAN controller @param this_can The this_can parameter is a pointer to the MSS_CAN_instance_t structure. @param cfg The cfg parameter is a 4 bytes variable used to set the configuration settings. @return This function does not return a value. Example: @code mss_can_instance_t g_mss_can_0_lo; int e51(void) { Return_status = MSS_CAN_init(&g_mss_can_0_lo,(CAN_SPEED_16M_500K | \ CAN_AUTO_RESTART | CAN_LITTLE_ENDIAN), (pmss_can_config_reg)0,16,7); .... MSS_CAN_set_config_reg(&g_mss_can_0_lo, (CAN_SPEED_16M_500K | \ CAN_AUTO_RESTART | CAN_LITTLE_ENDIAN)); .... return(0); } @endcode */ void MSS_CAN_set_config_reg ( mss_can_instance_t* this_can, uint32_t cfg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_set_mode() function sets the CAN controller operating mode based on the mode parameter. After this operation CAN controller is not in operational, to do that invoke MSS_CAN_start() function. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mode The mode parameter tells about desired operating mode of CAN controller. Possible operating modes are as mentioned below: | Mode | Description | |--------------------------|-----------------------------------------| | CANOP_MODE_INT_LOOPBACK | Sets normal operating mode | | CANOP_MODE_LISTEN_ONLY | In listen-only mode, the CAN controller | | | does not send any messages. Normally | | | used for automatic bitrate detection | | CANOP_MODE_INT_LOOPBACK | Selects internal loopback mode. This is | | | used for self-test | | CANOP_MODE_EXT_LOOPBACK | Selects external loopback. The CAN | | | controller will receive a copy of each | | | message sent. | | CANOP_SRAM_TEST_MODE | Sets SRAM test mode | | CANOP_SW_RESET | Issues a software reset | @return This function does not return a value. Example: @code int e51(void) { MSS_CAN_init(&g_mss_can_0_lo,(CAN_SPEED_16M_500K | CAN_AUTO_RESTART | \ CAN_LITTLE_ENDIAN),(pmss_can_config_reg)0,16,7); MSS_CAN_set_mode(&g_mss_can_0_lo,CANOP_MODE_INT_LOOPBACK); .... return(0); } @endcode */ void MSS_CAN_set_mode ( mss_can_instance_t* this_can, mss_can_mode_t mode ); /*-------------------------------------------------------------------------*//** The MSS_CAN_start() function clears all pending interrupts and enable CAN controller to perform normal operation. It enables receive interrupts also. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function does not return a value. Example: @code int e51(void) { MSS_CAN_init(&g_mss_can_0_lo,(CAN_SPEED_16M_500K | CAN_AUTO_RESTART | \ CAN_LITTLE_ENDIAN),(pmss_can_config_reg)0,16,7); MSS_CAN_set_mode(&g_mss_can_0_lo,CANOP_MODE_INT_LOOPBACK); MSS_CAN_start(&g_mss_can_0_lo); .... return(0); } @endcode */ void MSS_CAN_start ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_stop() function is used to disable the CAN controller. NOTE: Interrupt flags status remain unaffected. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function does not return a value. Example: @code int e51(void) { MSS_CAN_init(&g_mss_can_0_lo,(CAN_SPEED_16M_500K | CAN_AUTO_RESTART | \ CAN_LITTLE_ENDIAN),(pmss_can_config_reg)0,16,7); MSS_CAN_set_mode(&g_mss_can_0_lo,CANOP_MODE_INT_LOOPBACK); MSS_CAN_start(&g_mss_can_0_lo); .... .... MSS_CAN_stop(&g_mss_can_0_lo); return(0); } @endcode */ void MSS_CAN_stop ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_id() function returns the message identifier. Bits right justified based on message identifier (Extended identifier) type. @param pmsg The pmsg parameter is a pointer to the message object. @return This function returns message identifier. Example: @code int e51(void) { ... return_id = MSS_CAN_get_id(&pmsg); return(0); } @endcode */ uint32_t MSS_CAN_get_id ( pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_set_id() function returns ID bits left justified based on IDE type. IDE type might be either standard or extended. @param pmsg The pmsg parameter is a pointer to the message object. @return This function returns message identifier. Example: @code int e51(void) { .... pmsg->ID = 0x120; MSS_CAN_set_id(&pmsg); .... return(0); } @endcode */ uint32_t MSS_CAN_set_id ( pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_msg_filter_mask() function packs the ID, IDE, and RTR bits together as they are used in the message filter mask and returns packed identifier. @param id The id parameter is a 4 byte variable to hold message identifier. @param ide The ide parameter is a 1 byte variable to indicate IDE type. Acceptable values are as mentioned below: | Value | Description | |------------|-------------------------------| | 0 | Standard format | | 1 | Extended format | @param rtr The rtr parameter is a 1 byte variable to indicate message type. Acceptable values are as mentioned below: | Value | Description | |------------|-------------------------------| | 0 | Regular message (data frame) | | 1 | RTR message (remote frame) | @return This function returns packed id. Example: @code int e51(void) { .... MSS_CAN_get_msg_filter_mask( 0x120, 1, 0); .... return(0); } @endcode */ uint32_t MSS_CAN_get_msg_filter_mask ( uint32_t id, uint8_t ide, uint8_t rtr ); /*-------------------------------------------------------------------------*//** The MSS_CAN_set_int_ebl() function enable specific interrupt based on irq_flag parameter. @param this_can This is a pointer to an mss_can_instance_t structure. @param irq_flag The irq_flag parameter is a 4 byte variable indicates Interrupt type. Possible values are: | Constants | Description | |------------------------|------------------------------------------------| | CAN_INT_GLOBAL | Indicates to enable global interrupts | | CAN_INT_ARB_LOSS | Indicates arbitration loss interrupt | | CAN_INT_OVR_LOAD | Indicates overload message detected interrupt | | CAN_INT_BIT_ERR | Indicates bit error interrupt | | CAN_INT_STUFF_ERR | Indicates bit stuffing error interrupt | | CAN_INT_ACK_ERR | Indicates acknowledge error interrupt | | CAN_INT_FORM_ERR | Indicates format error interrupt | | CAN_INT_CRC_ERR | Indicates CRC error interrupt | | CAN_INT_BUS_OFF | Indicates bus off interrupt | | CAN_INT_RX_MSG_LOST | Indicates received message lost interrupt | | CAN_INT_TX_MSG | Indicates message transmit interrupt | | CAN_INT_RX_MSG | Indicates receive message available interrupt | | CAN_INT_RTR_MSG | Indicates RTR auto-reply message sent interrupt| | CAN_INT_STUCK_AT_0 | Indicates stuck at dominant error interrupt | | CAN_INT_SST_FAILURE | Indicates single shot transmission failure | | | interrupt | @return This function does not return a value. Example: @code int e51(void) { .... MSS_CAN_set_int_ebl(&g_mss_can_0_lo,CAN_INT_TX_MSG); .... return(0); } @endcode */ void MSS_CAN_set_int_ebl ( mss_can_instance_t* this_can, uint32_t irq_flag ); /*-------------------------------------------------------------------------*//** The MSS_CAN_clear_int_ebl() function disable specific interrupt based on irq_flag parameter. @param this_can This is a pointer to an mss_can_instance_t structure. @param irq_flag The irq_flag parameter is a 4 byte variable indicates Interrupt type. Possible values are: | Constant | Description | |------------------------|------------------------------------------------| | CAN_INT_GLOBAL | Indicates to enable global interrupts | | CAN_INT_ARB_LOSS | Indicates arbitration loss interrupt | | CAN_INT_OVR_LOAD | Indicates overload message detected interrupt | | CAN_INT_BIT_ERR | Indicates bit error interrupt | | CAN_INT_STUFF_ERR | Indicates bit stuffing error interrupt | | CAN_INT_ACK_ERR | Indicates acknowledge error interrupt | | CAN_INT_FORM_ERR | Indicates format error interrupt | | CAN_INT_CRC_ERR | Indicates CRC error interrupt | | CAN_INT_BUS_OFF | Indicates bus off interrupt | | CAN_INT_RX_MSG_LOST | Indicates received message lost interrupt | | CAN_INT_TX_MSG | Indicates message transmit interrupt | | CAN_INT_RX_MSG | Indicates receive message available interrupt | | CAN_INT_RTR_MSG | Indicates RTR auto-reply message sent interrupt| | CAN_INT_STUCK_AT_0 | Indicates stuck at dominant error interrupt | | CAN_INT_SST_FAILURE | Indicates single shot transmission failure | | | interrupt | @return This function does not return a value. Example: @code int e51(void) { .... MSS_CAN_clear_int_ebl(&g_mss_can_0_lo,CAN_INT_TX_MSG); .... return(0); } @endcode */ void MSS_CAN_clear_int_ebl ( mss_can_instance_t* this_can, uint32_t irq_flag ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_global_int_ebl() function returns the status of global interrupt enable flag. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns global interrupt enable flag status. Example: @code int e51(void) { .... MSS_CAN_get_global_int_ebl(&g_mss_can_0_lo); .... return(0); } @endcode */ uint32_t MSS_CAN_get_global_int_ebl ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_int_ebl() function returns the status of interrupt enable flags. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns interrupt enable flag status. Example: @code int e51(void) { .... MSS_CAN_get_int_ebl(&g_mss_can_0_lo); .... return(0); } @endcode */ uint32_t MSS_CAN_get_int_ebl ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_clear_int_status() function clears the selected interrupt flags. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param irq_flag The irq_flag parameter is a 4 byte variable indicates Interrupt type. Possible values are: | Constants | Description | |------------------------|------------------------------------------------| | CAN_INT_GLOBAL | Indicates to enable global interrupts | | CAN_INT_ARB_LOSS | Indicates arbitration loss interrupt | | CAN_INT_OVR_LOAD | Indicates overload message detected interrupt | | CAN_INT_BIT_ERR | Indicates bit error interrupt | | CAN_INT_STUFF_ERR | Indicates bit stuffing error interrupt | | CAN_INT_ACK_ERR | Indicates acknowledge error interrupt | | CAN_INT_FORM_ERR | Indicates format error interrupt | | CAN_INT_CRC_ERR | Indicates CRC error interrupt | | CAN_INT_BUS_OFF | Indicates bus off interrupt | | CAN_INT_RX_MSG_LOST | Indicates received message lost interrupt | | CAN_INT_TX_MSG | Indicates message transmit interrupt | | CAN_INT_RX_MSG | Indicates receive message available interrupt | | CAN_INT_RTR_MSG | Indicates RTR auto-reply message sent interrupt| | CAN_INT_STUCK_AT_0 | Indicates stuck at dominant error interrupt | | CAN_INT_SST_FAILURE | Indicates single shot transmission failure | | | interrupt | @return This function does not return a value. Example: @code int e51(void) { .... MSS_CAN_clear_int_status(&g_mss_can_0_lo,CAN_INT_RX_MSG); .... return(0); } @endcode */ void MSS_CAN_clear_int_status ( mss_can_instance_t* this_can, uint32_t irq_flag ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_int_status() function returns the status of interrupts. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns status of existed interrupts. Example: @code int e51(void) { .... MSS_CAN_get_int_status(&g_mss_can_0_lo); .... return(0); } @endcode */ uint32_t MSS_CAN_get_int_status ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_set_rtr_message_n () function loads mailbox with the given CAN message. This message will be sent out after receipt of a RTR message request. It verifies that whether the given mailbox is configured for Full CAN or not and also checks for RTR auto-reply is enabled or not. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @param pmsg The pmsg parameter is a pointer to the message object. @return This function returns CAN_OK on successful execution, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | | CAN_NO_RTR_MAILBOX | Indicates that there is no mailbox for | | | remote transmit request (RTR) frame | Example: @code e51() { ... pmsg->ID = 0x120; pmsg->DATALOW = 0xAA5555AA; pmsg->DATAHIGH = 0xAA5555AA; MSS_CAN_set_rtr_message_n(&g_mss_can_0_lo, 5, &pmsg); ... } @endcode */ uint8_t MSS_CAN_set_rtr_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_rtr_message_abort_n() function aborts a RTR message transmit request on mailbox mailbox_number and checks that message abort was successful. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @return This function returns CAN_OK on successful execution, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_ERR | Indicates error condition | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | Example: @code e51() { ... ret_status = MSS_CAN_get_rtr_message_abort_n((&g_mss_can_0_lo, 6); ... } @endcode */ uint8_t MSS_CAN_get_rtr_message_abort_n ( mss_can_instance_t* this_can, uint8_t mailbox_number ); /*-------------------------------------------------------------------------*//** The MSS_CAN_config_buffer() function configures receive mailboxes initialized for Basic CAN operation. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param pfilter The pfilter parameter is a pointer to the CAN message filter structure. @return This function returns CAN_OK on successful execution, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_NO_MSG | Indicates that there is no message received | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | Example: @code e51() { ... pfilter.ACR.L=0x00000000; pfilter.AMR.L= 0xFFFFFFFF; pfilter.AMCR_D.MASK= 0xFFFF; pfilter.AMCR_D.CODE= 0x00; ret_status = MSS_CAN_config_buffer(&g_mss_can_0_lo, &pfilter); ... } @endcode */ uint8_t MSS_CAN_config_buffer ( mss_can_instance_t* this_can, pmss_can_filterobject pfilter ); /*-------------------------------------------------------------------------*//** The MSS_CAN_config_buffer_n() function configures the receive mailbox specified in mailbox_number. The function checks that the mailbox is set for Full CAN operation, if not it return with error code. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @param pmsg The pmsg parameter is a pointer to the message object. @return This function returns CAN_OK on successful execution, otherwise it will returns following error codes - CAN_BASIC_CAN_MAILBOX | Constants | Description | |-----------------------|---------------------------------------------| | CAN_NO_MSG | Indicates that there is no message received | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | Example: @code e51() { ... rx_msg.ID = 0x200; rx_msg.DATAHIGH = 0u; rx_msg.DATALOW = 0u; rx_msg.AMR.L = 0xFFFFFFFF; rx_msg.ACR.L = 0x00000000; rx_msg.AMR_D = 0x0000FFFF; rx_msg.ACR_D = 0x00000000; rx_msg.RXB.DLC = 8u; rx_msg.RXB.IDE = 0; ret_status = MSS_CAN_config_buffer_n(&g_mss_can_0_lo, 3, &rx_msg); ... } @endcode */ uint8_t MSS_CAN_config_buffer_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_rxmsgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_message_n() function read message from the receive mailbox specified in "mailbox_number" parameter and returns status of operation. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @param pmsg The pmsg parameter is a pointer to the message object that will hold the received message. @return This function returns CAN_VALID_MSG on successful execution, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_NO_MSG | Indicates that there is no message received | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | Example: @code e51() { pmss_can_msgobject msg; ... ret_status = MSS_CAN_get_message_n(&g_mss_can_0_lo, 3, &msg); ... } @endcode */ uint8_t MSS_CAN_get_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_message() function read message from the first mailbox set for Basic CAN operation that contains a message. Once the message has been read from the mailbox, the message receipt is acknowledged. Note: Since neither a hardware nor a software FIFO exists, message inversion might happen (example, a newer message might be read from the receive buffer prior to an older message). @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param pmsg The pmsg parameter is a pointer to the message object, that will hold the received message. @return This function returns CAN_VALID_MSG on successful execution, otherwise it will returns following error codes | Constants | Description | |-----------------------|---------------------------------------------| | CAN_NO_MSG | Indicates that there is no message received | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | Example: @code e51() { pmss_can_msgobject rx_buf; ... if(CAN_VALID_MSG == MSS_CAN_get_message_av(&g_mss_can_0_lo)) { if(CAN_VALID_MSG != MSS_CAN_get_message(&g_mss_can_0_lo, &rx_buf)) { .... } } ... } @endcode */ uint8_t MSS_CAN_get_message ( mss_can_instance_t* this_can, pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_message_av() function indicates if receive buffer contains a new message in Basic CAN operation. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns CAN_VALID_MSG on successful execution, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_NO_MSG | Indicates that there is no message received | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | Example: @code e51() { pmss_can_msgobject rx_buf; ... if(CAN_VALID_MSG == MSS_CAN_get_message_av(&g_mss_can_0_lo)) { MSS_CAN_get_message(&g_mss_can_0_lo, &rx_buf); } ... } @endcode */ uint8_t MSS_CAN_get_message_av ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_send_message_n() function sends a message using mailbox "mailbox_number". The function verifies that this mailbox is configured for Full CAN operation and is empty. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @param pmsg The pmsg parameter is a pointer to the message object that holds the CAN message to transmit. @return This function returns CAN_VALID_MSG on successful execution, otherwise it will return the following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_NO_MSG | Indicates that there is no message received | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | Example: @code e51() { pmss_can_msgobject pmsg; ... pmsg.ID=0x120; pmsg.DATALOW = 0x55555555; pmsg.DATAHIGH = 0x55555555; pmsg.L = ((0<<20)| 0x00080000); if (CAN_OK != MSS_CAN_send_message_n(&g_mss_can_0_lo, 0, &pmsg)) { ... } ... } @endcode */ uint8_t MSS_CAN_send_message_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_send_message_abort_n() function aborts a message transmit request for the specified mailbox number in mailbox_number and checks that message abort status. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @return This function returns CAN_OK on successful execution, otherwise it will return the following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_ERR | Indicates error condition | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | Example: @code e51() { ... if (CAN_OK != MSS_CAN_send_message_abort_n(&g_mss_can_0_lo, 0)) { ... } ... } @endcode */ uint8_t MSS_CAN_send_message_abort_n ( mss_can_instance_t* this_can, uint8_t mailbox_number ); /*-------------------------------------------------------------------------*//** The MSS_CAN_send_message_ready() function will identify the availability of mailbox to fill with new message in basic CAN operation. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns CAN_OK on successful identification of free mailbox, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_ERR | Indicates error condition | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | Example: @code e51() { pmss_can_msgobject pmsg; ... pmsg.ID = 0x120; pmsg.DATALOW = 0x55555555; pmsg.DATAHIGH = 0x55555555; pmsg.L = ((0 << 20)| 0x00080000); if(CAN_OK == MSS_CAN_send_message_ready(&g_mss_can_0_lo)) { MSS_CAN_send_message(&g_mss_can_0_lo, &pmsg); } ... } @endcode */ uint8_t MSS_CAN_send_message_ready ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_send_message() function will copy the data to the first available mailbox set for Basic CAN operation and send data on to the bus. Note: Since neither a hardware nor a software FIFO exists, message inversion might happen (example, a newer message might be send from the transmit buffer prior to an older message). @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param pmsg The pmsg parameter is a pointer to the message object that holds the CAN message to transmit. @return This function returns CAN_OK on successful identification of free mailbox, otherwise it will returns following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_ERR | Indicates error condition | | CAN_INVALID_MAILBOX | Indicates invalid mailbox number | Example: @code e51() { pmss_can_msgobject pmsg; ... pmsg.ID = 0x120; pmsg.DATALOW = 0x55555555; pmsg.DATAHIGH = 0x55555555; pmsg.L = ((0 << 20)| 0x00080000); if (CAN_OK == MSS_CAN_send_message_ready(&g_mss_can_0_lo)) { if (CAN_OK != MSS_CAN_send_message(&g_mss_can_0_lo, &pmsg)) { ... } } ... } @endcode */ uint8_t MSS_CAN_send_message ( mss_can_instance_t* this_can, pmss_can_msgobject pmsg ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_mask_n() function returns the message filter settings of the selected receive mailbox. The function is valid for Full CAN operation only. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @param pamr The pamr parameter is a pointer to the acceptance mask. @param pacr The pacr parameter is a pointer to the acceptance code. @param pdta_amr The pdta_amr parameter is a pointer to the acceptance mask of first two data bytes. @param pdta_acr The pdta_acr parameter is a pointer to the acceptance code of first two data bytes. @return This function will returns the following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_OK | Indicates there is no error | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | Example: @code e51() { ... if (CAN_OK != MSS_CAN_get_mask_n(&g_mss_can_0_lo,mailbox_number,&pamr,&pacr, &pdamr, &pdacr)) { ... } ... } @endcode */ uint8_t MSS_CAN_get_mask_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, uint32_t *pamr, uint32_t *pacr, uint16_t *pdta_amr, uint16_t *pdta_acr ); /*-------------------------------------------------------------------------*//** The MSS_CAN_set_mask_n() function configures the message filter settings for the selected receive mailbox. The function is valid for Full CAN operation only. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param mailbox_number The mailbox_number parameter is a variable to hold the mailbox number to be used for message transfer. @param amr The amr parameter is a variable to hold the acceptance mask. @param acr The acr parameter is a variable to hold the acceptance code. @param dta_amr The dta_amr parameter is a variable to hold the acceptance mask of first two data bytes. @param dta_acr The dta_acr parameter is a variable to hold the acceptance code of first two data bytes. @return This function returns the following error codes: | Constants | Description | |-----------------------|---------------------------------------------| | CAN_OK | Indicates there is no error | | CAN_BASIC_CAN_MAILBOX | Indicates that mailbox is configured for | | | Basic CAN operation | Example: @code e51() { ... if (CAN_OK != MSS_CAN_set_mask_n(&g_mss_can_0_lo,mailbox_number,&pamr,&pacr, &pdamr, &pdacr)) { ... } ... } @endcode */ uint8_t MSS_CAN_set_mask_n ( mss_can_instance_t* this_can, uint8_t mailbox_number, uint32_t amr, uint32_t acr, uint16_t dta_amr, uint16_t dta_acr ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_rx_buffer_status() function returns the buffer status of all receive (32) mailboxes. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns status of receive buffers (32 buffers). Example: @code e51() { uint32_t return_status=0; ... return_status = MSS_CAN_get_rx_buffer_status(&g_mss_can_0_lo); ... } @endcode */ uint32_t MSS_CAN_get_rx_buffer_status ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_tx_buffer_status() function returns the buffer status of all transmit(32) mailboxes. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns status of transmit buffers (32 buffers). Example: @code e51() { uint32_t return_status = 0; ... return_status = MSS_CAN_get_tx_buffer_status(&g_mss_can_0_lo); ... } @endcode */ uint32_t MSS_CAN_get_tx_buffer_status ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_error_status() function returns the present error state of the CAN controller. Error state might be error active or error passive or bus-off. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @param status The status parameter is a pointer to hold the content of error status register. @return The function shall return the following codes: | Codes | Descriptions | |--------|-------------------------------| | 0 | error active | | 1 | error passive | | 2 | bus-off | Example: @code e51() { uint8_t return_status = 0; ... return_status = MSS_CAN_get_error_status(&g_mss_can_0_lo); ... } @endcode */ uint8_t MSS_CAN_get_error_status ( mss_can_instance_t* this_can, uint32_t* status ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_rx_error_count() function returns the current receive error counter value. Counter value ranges from 0x00 - 0xFF. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns the receive error counter value. Example: @code e51() { uint32_t return_status = 0; ... return_status = MSS_CAN_get_rx_error_count(&g_mss_can_0_lo); ... } @endcode */ uint32_t MSS_CAN_get_rx_error_count ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_rx_gte96() function provides information about receive error count. It identifies that receive error count is greater than or equal to 96, and reports 1 if count exceeds 96. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns following values: | Value | Description | |-------|------------------------------------------------------| | 0 | if receive error count less than 96. | | 1 | if receive error count greater than or equals to 96. | Example: @code e51() { uint32_t return_status = 0; ... return_status = MSS_CAN_get_rx_gte96(&g_mss_can_0_lo); ... } @endcode */ uint32_t MSS_CAN_get_rx_gte96 ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_tx_error_count() function returns the current transmit error counter value. Counter value ranges from 0x00 - 0xFF. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns the transmit error counter value. Example: @code e51() { uint32_t return_status = 0; ... return_status = MSS_CAN_get_tx_error_count(&g_mss_can_0_lo); ... } @endcode */ uint32_t MSS_CAN_get_tx_error_count ( mss_can_instance_t* this_can ); /*-------------------------------------------------------------------------*//** The MSS_CAN_get_tx_gte96() function provides information about transmit error count. It identifies that transmit error count is greater than or equals to 96, and reports 1 if count exceeds 96. @param this_can The this_can parameter is a pointer to the mss_can_instance_t structure. @return This function returns following values: | Value | Description | |-------|-------------------------------------------------------| | 0 | if transmit error count less than 96. | | 1 | if transmit error count greater than or equals to 96. | Example: @code e51() { uint32_t return_status = 0; ... return_status = MSS_CAN_get_tx_gte96(&g_mss_can_0_lo); ... } @endcode */ uint32_t MSS_CAN_get_tx_gte96 ( mss_can_instance_t* this_can ); #ifdef __cplusplus } #endif #endif /* MSS_CAN_H_ */ mss_ethernet_mac/000077500000000000000000000000001432224323300365735ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_ethernet_mac.c000066400000000000000000004612141432224323300422670ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC 10/100/1000 Mbps Ethernet MAC bare metal software driver implementation. * */ #include #include #include #include #include "mss_plic.h" #include "mss_util.h" #include "mss_ints.h" #include "fpga_design_config/fpga_design_config.h" #include "drivers/mss/mss_mac/mss_ethernet_registers.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_regs.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_user_config.h" #if defined(USING_FREERTOS) #include "FreeRTOS.h" #endif #include "drivers/mss/mss_mac/mss_ethernet_mac.h" #include "drivers/mss/mss_mac/phy.h" #include "hal/hal.h" #include "mss_assert.h" #include "mss_sysreg.h" #if defined (TI_PHY) #include "mss_gpio.h" #endif #ifdef __cplusplus extern "C" { #endif /**************************************************************************/ /* Preprocessor Macros */ /**************************************************************************/ #define NULL_POINTER (void *)0U #if !defined(NDEBUG) #define IS_STATE(x) ( ((x) == MSS_MAC_ENABLE) || ((x) == MSS_MAC_DISABLE) ) #endif /* NDEBUG */ #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) #define IS_WORD_ALIGNED(x) ((uint64_t)0U == ((uint64_t)(x) & (uint64_t)3U)) #else #define IS_WORD_ALIGNED(x) ((uint32_t)0U == ((uint32_t)(x) & (uint32_t)3U)) #endif #define BMSR_AUTO_NEGOTIATION_COMPLETE (0x0020U) #define INVALID_INDEX (0xFFFFFFFFU) #define PHY_ADDRESS_MIN (0U) #define PHY_ADDRESS_MAX (31U) /* * Defines for determining DMA descriptor sizes */ #if 0 #if !defined(MSS_MAC_TIME_STAMPED_MODE) #define MSS_MAC_TIME_STAMPED_MODE 0 /* Default to non time stamped descriptors */ #endif #endif #if defined(TARGET_ALOE) #define MSS_MAC0_BASE (0x10090000U); #elif defined(TARGET_G5_SOC) #define MSS_MAC0_BASE (0x20110000U) #define MSS_EMAC0_BASE (0x20111000U) #define MSS_MAC1_BASE (0x20112000U) #define MSS_EMAC1_BASE (0x20113000U) #define MSS_MAC0_BASE_HI (0x28110000U) #define MSS_EMAC0_BASE_HI (0x28111000U) #define MSS_MAC1_BASE_HI (0x28112000U) #define MSS_EMAC1_BASE_HI (0x28113000U) #define MSS_MAC_GEM0_ABP_BIT (0x00010000U) #define MSS_MAC_GEM1_ABP_BIT (0x00020000U) #else #warning "No target platform defined for MSS Ethernet MAC" #endif /**************************************************************************/ /* Private variables */ /**************************************************************************/ #if defined(TARGET_ALOE) static volatile uint32_t *GEMGXL_tx_clk_sel = (volatile uint32_t *)0x100A0000UL; static volatile uint32_t *GEMGXL_speed_mode = (volatile uint32_t *)0x100A0020UL; #endif /************************************************************************** * Global variables * * * * Note: there are two instances of the GMAC for G5 SOC and each has a * * primary MAC and a secondary eMAC for time sensative traffic. The FU540 * * device on the Aloe board has a single primary MAC. * **************************************************************************/ #if defined(TARGET_G5_SOC) mss_mac_instance_t g_mac0; mss_mac_instance_t g_mac1; mss_mac_instance_t g_emac0; mss_mac_instance_t g_emac1; #endif #if defined(MSS_MAC_USE_DDR) #if MSS_MAC_USE_DDR == MSS_MAC_MEM_DDR uint8_t *g_mss_mac_ddr_ptr = (uint8_t *)0xC0000000LLU; #elif MSS_MAC_USE_DDR == MSS_MAC_MEM_FIC0 uint8_t *g_mss_mac_ddr_ptr = (uint8_t *)0x60000000LLU; #elif MSS_MAC_USE_DDR == MSS_MAC_MEM_FIC1 uint8_t *g_mss_mac_ddr_ptr = (uint8_t *)0xE0000000LLU; #elif MSS_MAC_USE_DDR == MSS_MAC_MEM_CRYPTO uint8_t *g_mss_mac_ddr_ptr = (uint8_t *)0x22002000LLU; #else #error "bad memory region defined" #endif #endif #if defined(TARGET_ALOE) mss_mac_instance_t g_mac0; #endif /**************************************************************************/ /* Private Functions */ /**************************************************************************/ static void mac_reset(void); static void config_mac_hw(mss_mac_instance_t *this_mac, const mss_mac_cfg_t * cfg); static void tx_desc_ring_init(mss_mac_instance_t *this_mac); static void rx_desc_ring_init(mss_mac_instance_t *this_mac); static void assign_station_addr(mss_mac_instance_t *this_mac, const uint8_t mac_addr[MSS_MAC_MAC_LEN]); static void generic_mac_irq_handler(mss_mac_instance_t *this_mac, uint32_t queue_no); static void rxpkt_handler(mss_mac_instance_t *this_mac, uint32_t queue_no); static void txpkt_handler(mss_mac_instance_t *this_mac, uint32_t queue_no); static void update_mac_cfg(const mss_mac_instance_t *this_mac); static uint8_t probe_phy(const mss_mac_instance_t *this_mac); static void instances_init(mss_mac_instance_t *this_mac, mss_mac_cfg_t *cfg); static void msgmii_init(const mss_mac_instance_t *this_mac); static void msgmii_autonegotiate(const mss_mac_instance_t *this_mac); /**************************************************************************/ /* Public Functions */ /**************************************************************************/ /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_init ( mss_mac_instance_t *this_mac, mss_mac_cfg_t *cfg ) { int32_t queue_no; ASSERT(cfg != NULL_POINTER); #if defined(TARGET_ALOE) ASSERT(this_mac == &g_mac0); instances_init(this_mac, cfg); if((cfg != NULL_POINTER) && (this_mac == &g_mac0)) #endif #if defined(TARGET_G5_SOC) ASSERT((this_mac == &g_mac0) || (this_mac == &g_mac1) || (this_mac == &g_emac0) || (this_mac == &g_emac1)); instances_init(this_mac, cfg); /* * Always reset GEM if the pMAC is selected for init but not if eMAC * The pMAC should always be initialised first followed by the eMAC so this * is ok... */ if(this_mac == &g_mac0) { SYSREG->SUBBLK_CLOCK_CR |= (uint32_t)2U; /* Reset MAC */ SYSREG->SOFT_RESET_CR |= (uint32_t)2U; { volatile int64_t index; index = 0; while(1000 != index) /* Don't know if necessary, but delay a bit before de-asserting reset... */ { index++; } } /* Take MAC out of reset. */ SYSREG->SOFT_RESET_CR &= (uint32_t)~2U; } if(this_mac == &g_mac1) { SYSREG->SUBBLK_CLOCK_CR |= (uint32_t)4U; /* Reset MAC */ SYSREG->SOFT_RESET_CR |= (uint32_t)4U; { volatile int64_t index; index = 0; while(1000 != index) /* Don't know if necessary, but delay a bit before de-asserting reset... */ { index++; } } /* Take MAC out of reset. */ SYSREG->SOFT_RESET_CR &= (uint32_t)~4U; } /* PMCS: for the Emulation platform we need to select the non default TSU clock * for the moment or TX won't work */ if(0U == this_mac->is_emac) { this_mac->mac_base->USER_IO = 1U; } if((cfg != NULL_POINTER) && ((this_mac == &g_mac0) || (this_mac == &g_mac1) || (this_mac == &g_emac0) || (this_mac == &g_emac1))) #endif /* defined(TARGET_G5_SOC) */ { this_mac->phy_addr = cfg->phy_addr; this_mac->pcs_phy_addr = cfg->pcs_phy_addr; this_mac->interface_type = cfg->interface_type; this_mac->jumbo_frame_enable = cfg->jumbo_frame_enable; this_mac->phy_type = cfg->phy_type; this_mac->phy_autonegotiate = cfg->phy_autonegotiate; this_mac->phy_get_link_status = cfg->phy_get_link_status; this_mac->phy_init = cfg->phy_init; this_mac->phy_set_link_speed = cfg->phy_set_link_speed; this_mac->append_CRC = cfg->append_CRC; #if MSS_MAC_USE_PHY_DP83867 this_mac->phy_extended_read = cfg->phy_extended_read; this_mac->phy_extended_write = cfg->phy_extended_write; #endif #if defined(TARGET_G5_SOC) if(0U != cfg->use_local_ints) { __disable_local_irq(this_mac->mac_q_int[0]); if(0U == this_mac->is_emac) { __disable_local_irq(this_mac->mac_q_int[1]); __disable_local_irq(this_mac->mac_q_int[2]); __disable_local_irq(this_mac->mac_q_int[3]); __disable_local_irq(this_mac->mmsl_int); } } else #endif { /* * In the following if an interrupt is set to NoInterrupt_IRQn then * the PLIC will ignore it as interrupt 0 is a dummy one. */ PLIC_DisableIRQ(this_mac->mac_q_int[0]); PLIC_SetPriority(this_mac->mac_q_int[0], cfg->queue0_int_priority); #if defined(TARGET_G5_SOC) PLIC_DisableIRQ(this_mac->mac_q_int[1]); PLIC_SetPriority(this_mac->mac_q_int[1], cfg->queue1_int_priority); PLIC_DisableIRQ(this_mac->mac_q_int[2]); PLIC_SetPriority(this_mac->mac_q_int[2], cfg->queue2_int_priority); PLIC_DisableIRQ(this_mac->mac_q_int[3]); PLIC_SetPriority(this_mac->mac_q_int[3], cfg->queue3_int_priority); PLIC_DisableIRQ(this_mac->mmsl_int); PLIC_SetPriority(this_mac->mmsl_int, cfg->mmsl_int_priority); #endif } mac_reset(); config_mac_hw(this_mac, cfg); /* Assign MAC station address */ assign_station_addr(this_mac, cfg->mac_addr); /* Intialize Tx & Rx descriptor rings */ tx_desc_ring_init(this_mac); rx_desc_ring_init(this_mac); this_mac->rx_discard = 0U; /* Ensure normal RX operation */ for(queue_no = 0; queue_no < MSS_MAC_QUEUE_COUNT; queue_no++) { /* Initialize Tx descriptors related variables. */ this_mac->queue[queue_no].nb_available_tx_desc = MSS_MAC_TX_RING_SIZE; /* Initialize Rx descriptors related variables. */ this_mac->queue[queue_no].nb_available_rx_desc = MSS_MAC_RX_RING_SIZE; this_mac->queue[queue_no].next_free_rx_desc_index = 0U; this_mac->queue[queue_no].first_rx_desc_index = 0U; /* initialize default interrupt handlers */ this_mac->queue[queue_no].pckt_tx_callback = (mss_mac_transmit_callback_t)NULL_POINTER; this_mac->queue[queue_no].pckt_rx_callback = (mss_mac_receive_callback_t)NULL_POINTER; /* Added these to MAC structure to make them MAC specific... */ this_mac->queue[queue_no].ingress = 0U; this_mac->queue[queue_no].egress = 0U; this_mac->queue[queue_no].rx_overflow = 0U; this_mac->queue[queue_no].hresp_error = 0U; this_mac->queue[queue_no].rx_restart = 0U; } #if 0 /* Initialize PHY interface */ if(MSS_MAC_AUTO_DETECT_PHY_ADDRESS == cfg->phy_addr) { cfg->phy_addr = probe_phy(); } #endif if(0U == this_mac->is_emac) /* Only do the PHY stuff for primary MAC */ { if(TBI == this_mac->interface_type) { msgmii_init(this_mac); } #if defined(TARGET_ALOE) this_mac->phy_addr = 0U; #endif this_mac->phy_init(this_mac, 0U); this_mac->phy_set_link_speed(this_mac, cfg->speed_duplex_select); this_mac->phy_autonegotiate(this_mac); if(TBI == this_mac->interface_type) { msgmii_autonegotiate(this_mac); } } update_mac_cfg(this_mac); /* * Enable TX Packet and TX Packet Bus Error interrupts. * We don't enable the tx underrun interrupt as we only send on demand * and don't need to explicitly note an underrun as that is the "normal" * state for the interface to be in. */ /* * Enable RX Packet, RX Packet Overflow and RX Packet Bus Error * interrupts. */ if(0U != this_mac->is_emac) { this_mac->emac_base->INT_ENABLE = GEM_RECEIVE_OVERRUN_INT | GEM_TRANSMIT_COMPLETE | GEM_RX_USED_BIT_READ | GEM_RECEIVE_COMPLETE | GEM_RESP_NOT_OK_INT; } else { for(queue_no = 0; queue_no < MSS_MAC_QUEUE_COUNT; queue_no++) { /* Enable pause related interrupts if pause control is selected */ if((MSS_MAC_ENABLE == cfg->rx_flow_ctrl) || (MSS_MAC_ENABLE == cfg->tx_flow_ctrl)) { *this_mac->queue[queue_no].int_enable = GEM_RECEIVE_OVERRUN_INT | GEM_TRANSMIT_COMPLETE | GEM_RX_USED_BIT_READ | GEM_RECEIVE_COMPLETE | GEM_RESP_NOT_OK_INT | GEM_PAUSE_FRAME_TRANSMITTED | GEM_PAUSE_TIME_ELAPSED | GEM_PAUSE_FRAME_WITH_NON_0_PAUSE_QUANTUM_RX; } else { *this_mac->queue[queue_no].int_enable = GEM_RECEIVE_OVERRUN_INT | GEM_TRANSMIT_COMPLETE | GEM_RX_USED_BIT_READ | GEM_RECEIVE_COMPLETE | GEM_RESP_NOT_OK_INT; } #if 1 /* PMCS - set this to 0 if you want to check for un-handled interrupt conditions */ *this_mac->queue[queue_no].int_enable |= GEM_PAUSE_FRAME_TRANSMITTED | GEM_PAUSE_TIME_ELAPSED | GEM_PAUSE_FRAME_WITH_NON_0_PAUSE_QUANTUM_RX | GEM_LINK_CHANGE | GEM_TX_LOCKUP_DETECTED | GEM_RX_LOCKUP_DETECTED | GEM_AMBA_ERROR | GEM_RETRY_LIMIT_EXCEEDED_OR_LATE_COLLISION | GEM_TRANSMIT_UNDER_RUN; #endif } } /* * At this stage, the MSS MAC interrupts are disabled and won't be enabled * until at least one of the FIFOs is configured with a buffer(s) for * data transfer. */ } this_mac->mac_available = MSS_MAC_AVAILABLE; } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_update_hw_address ( mss_mac_instance_t *this_mac, const mss_mac_cfg_t * cfg ) { ASSERT(cfg != NULL_POINTER); if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(cfg != NULL_POINTER) { /* Assign MAC station address */ assign_station_addr(this_mac, cfg->mac_addr); } } } /****************************************************************************** * */ static void update_mac_cfg(const mss_mac_instance_t *this_mac) { mss_mac_speed_t speed; uint8_t fullduplex; uint8_t link_up; uint32_t temp_cr; link_up = this_mac->phy_get_link_status(this_mac, &speed, &fullduplex); if(link_up != MSS_MAC_LINK_DOWN) { if(0U != this_mac->is_emac) { temp_cr = this_mac->emac_base->NETWORK_CONFIG; } else { temp_cr = this_mac->mac_base->NETWORK_CONFIG; } temp_cr &= ~(GEM_GIGABIT_MODE_ENABLE | GEM_SPEED | GEM_FULL_DUPLEX); if(MSS_MAC_1000MBPS == speed) { #if defined(TARGET_ALOE) *GEMGXL_tx_clk_sel = (uint32_t)0U; *GEMGXL_speed_mode = (uint32_t)2U; #endif temp_cr |= GEM_GIGABIT_MODE_ENABLE; } else { if(MSS_MAC_100MBPS == speed) { #if defined(TARGET_ALOE) *GEMGXL_tx_clk_sel = (uint32_t)1U; *GEMGXL_speed_mode = (uint32_t)1U; #endif temp_cr |= (uint32_t)GEM_SPEED; } #if defined(TARGET_ALOE) else { *GEMGXL_tx_clk_sel = (uint32_t)1U; *GEMGXL_speed_mode = (uint32_t)0U; } #endif } /* Configure duplex mode */ if(MSS_MAC_FULL_DUPLEX == fullduplex) { temp_cr |= GEM_FULL_DUPLEX; } if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONFIG = temp_cr; } else { this_mac->mac_base->NETWORK_CONFIG = temp_cr; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint8_t MSS_MAC_get_link_status ( const mss_mac_instance_t *this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ) { /* Todo: These statics will only work for the single MAC Aloe case... */ static mss_mac_speed_t previous_speed = INVALID_SPEED; static uint8_t previous_duplex = 0xAAU; mss_mac_speed_t link_speed; uint8_t link_fullduplex; uint8_t link_up; link_up = MSS_MAC_LINK_DOWN; /* Default condition in case we are not active yet */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { link_up = this_mac->phy_get_link_status(this_mac, &link_speed, &link_fullduplex); if(link_up != MSS_MAC_LINK_DOWN) { /*---------------------------------------------------------------------- * Update MAC configuration if link characteristics changed. */ if((link_speed != previous_speed) || (link_fullduplex != previous_duplex)) { uint32_t temp_cr; if(0U != this_mac->is_emac) { temp_cr = this_mac->emac_base->NETWORK_CONFIG; } else { temp_cr = this_mac->mac_base->NETWORK_CONFIG; } temp_cr &= ~(GEM_GIGABIT_MODE_ENABLE | GEM_SPEED | GEM_FULL_DUPLEX); if(MSS_MAC_1000MBPS == link_speed) { #if defined(TARGET_ALOE) *GEMGXL_tx_clk_sel = (uint32_t)0U; *GEMGXL_speed_mode = (uint32_t)2U; #endif temp_cr |= GEM_GIGABIT_MODE_ENABLE; } else { if(MSS_MAC_100MBPS == link_speed) { #if defined(TARGET_ALOE) *GEMGXL_tx_clk_sel = (uint32_t)1U; *GEMGXL_speed_mode = (uint32_t)1U; #endif temp_cr |= (uint32_t)GEM_SPEED; } #if defined(TARGET_ALOE) else { *GEMGXL_tx_clk_sel = (uint32_t)1U; *GEMGXL_speed_mode = (uint32_t)0U; } #endif } /* Configure duplex mode */ if(MSS_MAC_FULL_DUPLEX == link_fullduplex) { temp_cr |= GEM_FULL_DUPLEX; } if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONFIG = temp_cr; } else { this_mac->mac_base->NETWORK_CONFIG = temp_cr; } } previous_speed = link_speed; previous_duplex = link_fullduplex; /*---------------------------------------------------------------------- * Return current link speed and duplex mode. */ if(speed != NULL_POINTER) { *speed = link_speed; } if(fullduplex != NULL_POINTER) { *fullduplex = link_fullduplex; } if(GMII_SGMII == this_mac->interface_type) /* Emulation platform with embedded SGMII link for PHY connection and GMII for MAC connection */ { uint16_t phy_reg; uint16_t sgmii_link_up; /* * Find out if link is up on SGMII link between GMII core and * external PHY. * * The link status bit latches 0 state until read to record fact * link has failed since last read so you need to read it twice to * get the current status... */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMSR); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMSR); sgmii_link_up = phy_reg & BMSR_LSTATUS; if(0U == sgmii_link_up) { /* Initiate auto-negotiation on the SGMII link. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= BMCR_ANENABLE; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); phy_reg |= BMCR_ANRESTART; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); } } #if 0 /* TBD old SF2 stuff keep here for now for guidance... */ #if ((MSS_MAC_PHY_INTERFACE == SGMII) || (MSS_MAC_PHY_INTERFACE == TBI)) #if (MSS_MAC_PHY_INTERFACE == TBI) /*---------------------------------------------------------------------- * Make sure SGMII interface link is up. if interface is TBI */ #define MDIO_PHY_ADDR SF2_MSGMII_PHY_ADDR #endif /* #if (MSS_MAC_PHY_INTERFACE == TBI) */ #if (MSS_MAC_PHY_INTERFACE == SGMII) /*---------------------------------------------------------------------- * Make sure SGMII/1000baseX interface link is up. if interface is * SGMII/1000baseX */ #define MDIO_PHY_ADDR MSS_MAC_INTERFACE_MDIO_ADDR #endif /* #if ((MSS_MAC_PHY_INTERFACE == SGMII) || (MSS_MAC_PHY_INTERFACE == BASEX1000)) */ { uint16_t phy_reg; uint16_t sgmii_link_up; /* Find out if link is up on SGMII link between MAC and external PHY. */ phy_reg = MSS_MAC_read_phy_reg(MDIO_PHY_ADDR, MII_BMSR); sgmii_link_up = phy_reg & BMSR_LSTATUS; if(0U == sgmii_link_up) { /* Initiate auto-negotiation on the SGMII link. */ phy_reg = MSS_MAC_read_phy_reg(MDIO_PHY_ADDR, MII_BMCR); phy_reg |= BMCR_ANENABLE; MSS_MAC_write_phy_reg(MDIO_PHY_ADDR, MII_BMCR, phy_reg); phy_reg |= BMCR_ANRESTART; MSS_MAC_write_phy_reg(MDIO_PHY_ADDR, MII_BMCR, phy_reg); } } #endif #endif } } return link_up; } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_cfg_struct_def_init ( mss_mac_cfg_t * cfg ) { ASSERT(NULL_POINTER != cfg); if(NULL_POINTER != cfg) { (void)memset(cfg, 0, sizeof(mss_mac_cfg_t)); /* Start with clean slate */ cfg->speed_duplex_select = MSS_MAC_ANEG_ALL_SPEEDS; #if defined(TARGET_ALOE) cfg->phy_addr = 0U; #endif #if defined(TARGET_G5_SOC) cfg->phy_addr = PHY_NULL_MDIO_ADDR; #endif cfg->tx_edc_enable = MSS_MAC_ERR_DET_CORR_DISABLE; cfg->rx_edc_enable = MSS_MAC_ERR_DET_CORR_DISABLE; cfg->jumbo_frame_enable = MSS_MAC_JUMBO_FRAME_DISABLE; cfg->jumbo_frame_default = MSS_MAC_MAX_PACKET_SIZE; cfg->length_field_check = MSS_MAC_LENGTH_FIELD_CHECK_ENABLE; cfg->append_CRC = MSS_MAC_CRC_ENABLE; cfg->loopback = MSS_MAC_LOOPBACK_DISABLE; cfg->rx_flow_ctrl = MSS_MAC_RX_FLOW_CTRL_ENABLE; cfg->tx_flow_ctrl = MSS_MAC_TX_FLOW_CTRL_ENABLE; cfg->ipg_multiplier = MSS_MAC_IPG_DEFVAL; cfg->ipg_divisor = MSS_MAC_IPG_DEFVAL; cfg->phyclk = MSS_MAC_DEF_PHY_CLK; cfg->mac_addr[0] = 0x00U; cfg->mac_addr[1] = 0x00U; cfg->mac_addr[2] = 0x00U; cfg->mac_addr[3] = 0x00U; cfg->mac_addr[4] = 0x00U; cfg->mac_addr[5] = 0x00U; cfg->queue_enable[0] = MSS_MAC_QUEUE_DISABLE; cfg->queue_enable[1] = MSS_MAC_QUEUE_DISABLE; cfg->queue_enable[2] = MSS_MAC_QUEUE_DISABLE; cfg->phy_type = MSS_MAC_DEV_PHY_NULL; cfg->interface_type = NULL_PHY; cfg->phy_autonegotiate = MSS_MAC_NULL_phy_autonegotiate; cfg->phy_get_link_status = MSS_MAC_NULL_phy_get_link_status; cfg->phy_init = MSS_MAC_NULL_phy_init; cfg->phy_set_link_speed = MSS_MAC_NULL_phy_set_link_speed; cfg->use_hi_address = MSS_MAC_DISABLE; cfg->use_local_ints = MSS_MAC_DISABLE; cfg->queue0_int_priority = 7U; /* Give them highest priority by default */ cfg->queue1_int_priority = 7U; cfg->queue2_int_priority = 7U; cfg->queue3_int_priority = 7U; cfg->mmsl_int_priority = 7U; #if MSS_MAC_USE_PHY_DP83867 cfg->phy_extended_read = NULL_ti_read_extended_regs; cfg->phy_extended_write = NULL_ti_write_extended_regs; #endif } } /****************************************************************************** * */ static void mac_reset ( void ) { } #if defined(TARGET_ALOE) /****************************************************************************** * PLL and Reset registers after reset in "wait for debug mode" * 0x10000000 : 0x10000000 * Address 0 - 3 4 - 7 8 - B C - F * 10000000 C0000000 030187C1 00000000 030187C1 * 10000010 00000000 00000000 00000000 030187C1 * 10000020 00000000 00000001 00000000 00000004 * * PLL and Reset registers after Linux boot. * * 0x10000000 : 0x10000000 * Address 0 - 3 4 - 7 8 - B C - F * 10000000 C0000000 82110EC0 00000000 82110DC0 * 10000010 80000000 00000000 00000000 82128EC0 * 10000020 80000000 00000000 0000002F 00000004 * */ /****************************************************************************** * */ #define __I const volatile #define __IO volatile #define __O volatile typedef struct { __IO uint32_t HFXOSCCFG; /* 0x0000 */ __IO uint32_t COREPLLCFG0; /* 0x0004 */ __IO uint32_t reserved0; /* 0x0008 */ __IO uint32_t DDRPLLCFG0; /* 0x000C */ __IO uint32_t DDRPLLCFG1; /* 0x0010 */ __IO uint32_t reserved1; /* 0x0014 */ __IO uint32_t reserved2; /* 0x0018 */ __IO uint32_t GEMGXLPLLCFG0; /* 0x001C */ __IO uint32_t GEMGXLPLLCFG1; /* 0x0020 */ __IO uint32_t CORECLKSEL; /* 0x0024 */ __IO uint32_t DEVICERESETREG; /* 0x0028 */ } AloePRCI_TypeDef; AloePRCI_TypeDef *g_aloe_prci = (AloePRCI_TypeDef *)0x10000000UL; typedef struct { __IO uint32_t PWMCFG; /* 0x0000 */ __IO uint32_t reserved0; /* 0x0004 */ __IO uint32_t PWMCOUNT; /* 0x0008 */ __IO uint32_t reserved1; /* 0x000C */ __IO uint32_t PWMS; /* 0x0010 */ __IO uint32_t reserved2; /* 0x0014 */ __IO uint32_t reserved3; /* 0x0018 */ __IO uint32_t reserved4; /* 0x001C */ __IO uint32_t PWMCMP0; /* 0x0020 */ __IO uint32_t PWMCMP1; /* 0x0024 */ __IO uint32_t PWMCMP2; /* 0x0028 */ __IO uint32_t PWMCMP3; /* 0x002C */ } AloePWM_TypeDef; AloePWM_TypeDef *g_aloe_pwm0 = (AloePWM_TypeDef *)0x10020000UL; static void config_mac_pll_and_reset(void); static void config_mac_pll_and_reset(void) { volatile int64_t ix; volatile int64_t counter; volatile int64_t loops = 0; /* * COREPLLCFG0 reset value = 0x030187C1 * divr = 1 * divf = 1F * divq = 3 * range = 0 * bypass = 1 * fse = 1 * lock = 0 * * Desired value = 82110EC0 * divr = 0 * divf = 1D * divq = 2 * range = 4 * bypass = 0 * fse = 1 * lock = 1 */ #if 0 /* Test code for proving Core clock speed switching works */ g_aloe_pwm0->PWMCFG = 0x0000020EU; g_aloe_pwm0->PWMCMP0 = 0x0000FFFFU; g_aloe_pwm0->PWMCMP1 = 0x0000FFFFU; g_aloe_pwm0->PWMCMP2 = 0x0000FFFFU; g_aloe_pwm0->PWMCMP3 = 0x0000FFFFU; while(loops < 16) { if(ix & 1) { g_aloe_pwm0->PWMCMP0 = 0x00000000U; } else { g_aloe_pwm0->PWMCMP0 = 0x0000FFFFU; } if(ix & 2) { g_aloe_pwm0->PWMCMP1 = 0x00000000U; } else { g_aloe_pwm0->PWMCMP1 = 0x0000FFFFU; } if(ix & 4) { g_aloe_pwm0->PWMCMP2 = 0x00000000U; } else { g_aloe_pwm0->PWMCMP2 = 0x0000FFFFU; } if(ix & 8) { g_aloe_pwm0->PWMCMP3 = 0x00000000U; } else { g_aloe_pwm0->PWMCMP3 = 0x0000FFFFU; } ix++; for(counter = 0; counter != 100000; counter++) ; loops++; } #endif g_aloe_prci->COREPLLCFG0 = 0x03110EC0U; /* Configure Core Clock PLL */ while(g_aloe_prci->COREPLLCFG0 & 0x80000000U) /* Wait for lock with PLL bypassed */ ix++; g_aloe_prci->COREPLLCFG0 = 0x02110EC0U; /* Take PLL out of bypass */ g_aloe_prci->CORECLKSEL = 0x00000000U; /* Switch to PLL as clock source */ #if 0 /* Test code for proving Core clock speed switching works */ loops = 0; while(loops < 20) { if(ix & 1) { g_aloe_pwm0->PWMCMP0 = 0x0000FFFFU; } else { g_aloe_pwm0->PWMCMP0 = 0x00000000U; } ix++; for(counter = 0; counter != 3000000; counter++) ; loops++; } #endif /* * GEMGXLPLLCFG0 reset value = 0x030187C1 * divr = 1 * divf = 1F * divq = 3 * range = 0 * bypass = 1 * fse = 1 * lock = 0 * * Desired value = 82128EC0 * divr = 0 * divf = 3B * divq = 5 * range = 4 * bypass = 0 * fse = 1 * lock = 1 */ g_aloe_prci->GEMGXLPLLCFG0 = 0x03128EC0U; /* Configure GEM Clock PLL */ while(g_aloe_prci->GEMGXLPLLCFG0 & 0x80000000U) /* Wait for lock with PLL bypassed */ ix++; g_aloe_prci->GEMGXLPLLCFG0 = 0x02128EC0U; /* Take PLL out of bypass */ g_aloe_prci->GEMGXLPLLCFG1 = 0x80000000U; /* Switch to PLL as clock source */ g_aloe_prci->DEVICERESETREG |= 0x00000020U; /* Release MAC from reset */ } #endif /****************************************************************************** * */ static void config_mac_hw(mss_mac_instance_t *this_mac, const mss_mac_cfg_t * cfg) { uint32_t temp_net_config = 0U; uint32_t temp_net_control = 0U; uint32_t temp_length; /* Check for validity of configuration parameters */ ASSERT( IS_STATE(cfg->tx_edc_enable) ); ASSERT( IS_STATE(cfg->rx_edc_enable) ); ASSERT( MSS_MAC_PREAMLEN_MAXVAL >= cfg->preamble_length ); ASSERT( IS_STATE(cfg->jumbo_frame_enable) ); ASSERT( IS_STATE(cfg->length_field_check) ); ASSERT( IS_STATE(cfg->append_CRC) ); ASSERT( IS_STATE(cfg->loopback) ); ASSERT( IS_STATE(cfg->rx_flow_ctrl) ); ASSERT( IS_STATE(cfg->tx_flow_ctrl) ); #if defined(TARGET_ALOE) config_mac_pll_and_reset(); #endif /*-------------------------------------------------------------------------- * Configure MAC Network Control register */ temp_net_control = GEM_MAN_PORT_EN | GEM_CLEAR_ALL_STATS_REGS | GEM_PFC_ENABLE; #if 0 temp_net_control |= GEM_LOOPBACK_LOCAL; /* PMCS: Enable this to force local loop back */ #endif if(MSS_MAC_ENABLE == cfg->loopback) { temp_net_control |= GEM_LOOPBACK_LOCAL; } #if defined(MSS_MAC_TIME_STAMPED_MODE) temp_net_control |= GEM_PTP_UNICAST_ENA; #endif /* * eMAC has to be configured as external TSU although it is actually using * the pMAC TSU. There is only really 1 TSU per GEM instance and all * adjustments etc should really be done via the pMAC. */ if(0U != this_mac->is_emac) { temp_net_control |= GEM_EXT_TSU_PORT_ENABLE; } /*-------------------------------------------------------------------------- * Configure MAC Network Config and Network Control registers */ #if defined(TARGET_G5_SOC) if(TBI == this_mac->interface_type) { temp_net_config = (((uint32_t)(1UL)) << GEM_DATA_BUS_WIDTH_SHIFT) | ((cfg->phyclk & GEM_MDC_CLOCK_DIVISOR_MASK) << GEM_MDC_CLOCK_DIVISOR_SHIFT) | GEM_PCS_SELECT | GEM_SGMII_MODE_ENABLE; } else { /* Actually for the G5 SoC Emulation Platform the interface is GMII... */ temp_net_config = (((uint32_t)(1UL)) << GEM_DATA_BUS_WIDTH_SHIFT) | ((cfg->phyclk & GEM_MDC_CLOCK_DIVISOR_MASK) << GEM_MDC_CLOCK_DIVISOR_SHIFT); } #endif #if defined(TARGET_ALOE) /* No pause frames received in memory, divide PCLK by 224 for MDC */ temp_net_config = (cfg->phyclk & GEM_MDC_CLOCK_DIVISOR_MASK) << GEM_MDC_CLOCK_DIVISOR_SHIFT; #endif if((MSS_MAC_ENABLE == cfg->rx_flow_ctrl) || (MSS_MAC_ENABLE == cfg->tx_flow_ctrl)) { temp_net_config |= GEM_FCS_REMOVE | GEM_DISABLE_COPY_OF_PAUSE_FRAMES | GEM_RECEIVE_1536_BYTE_FRAMES | GEM_PAUSE_ENABLE | GEM_FULL_DUPLEX | GEM_GIGABIT_MODE_ENABLE; } else { temp_net_config |= GEM_FCS_REMOVE | GEM_DISABLE_COPY_OF_PAUSE_FRAMES | GEM_RECEIVE_1536_BYTE_FRAMES | GEM_FULL_DUPLEX | GEM_GIGABIT_MODE_ENABLE; } if(MSS_MAC_ENABLE == cfg->length_field_check) { temp_net_config |= GEM_LENGTH_FIELD_ERROR_FRAME_DISCARD; } if(MSS_MAC_IPG_DEFVAL != cfg->ipg_multiplier) /* If we have a non zero value here then enable IPG stretching */ { uint32_t stretch; temp_net_config |= GEM_IPG_STRETCH_ENABLE; stretch = cfg->ipg_multiplier & GEM_IPG_STRETCH_MUL_MASK; stretch |= (cfg->ipg_divisor & GEM_IPG_STRETCH_DIV_MASK) << GEM_IPG_STRETCH_DIV_SHIFT; if(0U != this_mac->is_emac) { this_mac->emac_base->STRETCH_RATIO = stretch; } else { this_mac->mac_base->STRETCH_RATIO = stretch; } } if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL = temp_net_control; this_mac->emac_base->NETWORK_CONFIG = temp_net_config; this_mac->mac_base->NETWORK_CONFIG = temp_net_config; } else { this_mac->mac_base->NETWORK_CONTROL = temp_net_control; this_mac->mac_base->NETWORK_CONFIG = temp_net_config; #if defined(TARGET_G5_SOC) this_mac->emac_base->NETWORK_CONFIG = temp_net_config; #endif } /*-------------------------------------------------------------------------- * Reset PCS */ if(0U == this_mac->is_emac) { this_mac->mac_base->PCS_CONTROL |= (uint32_t)0x8000UL; } /*-------------------------------------------------------------------------- * Configure MAC Network DMA Config register */ if(0U != this_mac->is_emac) { #if defined(MSS_MAC_TIME_STAMPED_MODE) this_mac->emac_base->DMA_CONFIG = GEM_DMA_ADDR_BUS_WIDTH_1 | (MSS_MAC_RX_BUF_VALUE << GEM_RX_BUF_SIZE_SHIFT) | GEM_TX_PBUF_SIZE | (((uint32_t)(0x3UL)) << GEM_RX_PBUF_SIZE_SHIFT) | ((uint32_t)(16UL)) | GEM_TX_BD_EXTENDED_MODE_EN | GEM_RX_BD_EXTENDED_MODE_EN; /* Record TS for all packets by default */ this_mac->emac_base->TX_BD_CONTROL = GEM_BD_TS_MODE; this_mac->emac_base->RX_BD_CONTROL = GEM_BD_TS_MODE; #else this_mac->emac_base->DMA_CONFIG = GEM_DMA_ADDR_BUS_WIDTH_1 | (MSS_MAC_RX_BUF_VALUE << GEM_RX_BUF_SIZE_SHIFT) | GEM_TX_PBUF_SIZE | (((uint32_t)(0x3UL)) << GEM_RX_PBUF_SIZE_SHIFT) | ((uint32_t)(16UL)); #endif } else { int32_t queue_index; #if defined(MSS_MAC_TIME_STAMPED_MODE) this_mac->mac_base->DMA_CONFIG = GEM_DMA_ADDR_BUS_WIDTH_1 | (MSS_MAC_RX_BUF_VALUE << GEM_RX_BUF_SIZE_SHIFT) | GEM_TX_PBUF_SIZE | (((uint32_t)(0x3UL)) << GEM_RX_PBUF_SIZE_SHIFT) | ((uint32_t)(16UL)) | GEM_TX_BD_EXTENDED_MODE_EN | GEM_RX_BD_EXTENDED_MODE_EN; /* Record TS for all packets by default */ this_mac->mac_base->TX_BD_CONTROL = GEM_BD_TS_MODE; this_mac->mac_base->RX_BD_CONTROL = GEM_BD_TS_MODE; #else this_mac->mac_base->DMA_CONFIG = GEM_DMA_ADDR_BUS_WIDTH_1 | (MSS_MAC_RX_BUF_VALUE << GEM_RX_BUF_SIZE_SHIFT) | GEM_TX_PBUF_SIZE | (((uint32_t)(0x3UL)) << GEM_RX_PBUF_SIZE_SHIFT) | (uint32_t)(16UL); #endif #if (MSS_MAC_QUEUE_COUNT > 1) for(queue_index = 1; queue_index < MSS_MAC_QUEUE_COUNT; queue_index++) { *(this_mac->queue[queue_index].dma_rxbuf_size) = ((uint32_t)MSS_MAC_RX_BUF_VALUE); } #endif } /* * Disable the other queues as the GEM reset leaves them enabled with an * address pointer of 0 for some unfathomable reason... This screws things * up when we enable transmission or reception. * * Setting b0 of the queue pointer disables a queue. */ #if (MSS_MAC_QUEUE_COUNT > 1) if(0U == this_mac->is_emac) { /* Added these to MAC structure to make them MAC specific... */ this_mac->mac_base->TRANSMIT_Q1_PTR = ((uint32_t)(uint64_t)this_mac->queue[0].tx_desc_tab) | 1U; /* Use address of valid descriptor but set b0 to disable */ this_mac->mac_base->TRANSMIT_Q2_PTR = ((uint32_t)(uint64_t)this_mac->queue[0].tx_desc_tab) | 1U; this_mac->mac_base->TRANSMIT_Q3_PTR = ((uint32_t)(uint64_t)this_mac->queue[0].tx_desc_tab) | 1U; this_mac->mac_base->RECEIVE_Q1_PTR = ((uint32_t)(uint64_t)this_mac->queue[0].rx_desc_tab) | 1U; this_mac->mac_base->RECEIVE_Q2_PTR = ((uint32_t)(uint64_t)this_mac->queue[0].rx_desc_tab) | 1U; this_mac->mac_base->RECEIVE_Q3_PTR = ((uint32_t)(uint64_t)this_mac->queue[0].rx_desc_tab) | 1U; } #endif /* Set up maximum initial jumbo frame size - but bounds check first */ if(cfg->jumbo_frame_default > MSS_MAC_JUMBO_MAX) { temp_length = MSS_MAC_JUMBO_MAX; } else { temp_length = cfg->jumbo_frame_default; } if(0U != this_mac->is_emac) { this_mac->emac_base->JUMBO_MAX_LENGTH = temp_length; } else { this_mac->mac_base->JUMBO_MAX_LENGTH = temp_length; } /*-------------------------------------------------------------------------- * Disable all ints for now */ if(0U != this_mac->is_emac) { this_mac->emac_base->INT_DISABLE = ((uint32_t)0xFFFFFFFFUL); /* Only one queue here... */ } else { int32_t queue_no; for(queue_no = 0; queue_no < MSS_MAC_QUEUE_COUNT; queue_no++) { *(this_mac->queue[queue_no].int_disable) = ((uint32_t)0xFFFFFFFFUL); } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_write_phy_reg ( const mss_mac_instance_t *this_mac, uint8_t phyaddr, uint8_t regaddr, uint16_t regval ) { volatile uint32_t phy_op; psr_t lev; ASSERT(MSS_MAC_PHYADDR_MAXVAL >= phyaddr); ASSERT(MSS_MAC_PHYREGADDR_MAXVAL >= regaddr); /* * Write PHY address in MII Mgmt address register. * Makes previous register address 0 & invalid. * * Don't check mac_available flag here as we may be called in the MAC init * phase before everything else is in place... */ if((MSS_MAC_PHYADDR_MAXVAL >= phyaddr) && (MSS_MAC_PHYREGADDR_MAXVAL >= regaddr)) { phy_op = GEM_WRITE1 | (GEM_PHY_OP_CL22_WRITE << GEM_OPERATION_SHIFT) | (((uint32_t)(2UL)) << GEM_WRITE10_SHIFT) | (uint32_t)regval; phy_op |= ((uint32_t)phyaddr << GEM_PHY_ADDRESS_SHIFT) & GEM_PHY_ADDRESS; phy_op |= ((uint32_t)regaddr << GEM_REGISTER_ADDRESS_SHIFT) & GEM_REGISTER_ADDRESS; lev = HAL_disable_interrupts(); /* * Always use the pMAC for this as the eMAC MDIO interface is not * connected to the outside world... */ /* Wait for MII Mgmt interface to complete previous operation. */ do { volatile int32_t ix; ix++; } while(0U == (this_mac->mac_base->NETWORK_STATUS & GEM_MAN_DONE)); this_mac->mac_base->PHY_MANAGEMENT = phy_op; HAL_restore_interrupts(lev); } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint16_t MSS_MAC_read_phy_reg ( const mss_mac_instance_t *this_mac, uint8_t phyaddr, uint8_t regaddr ) { volatile uint32_t phy_op; psr_t lev; ASSERT(MSS_MAC_PHYADDR_MAXVAL >= phyaddr); ASSERT(MSS_MAC_PHYREGADDR_MAXVAL >= regaddr); /* * Write PHY address in MII Mgmt address register. * Makes previous register address 0 & invalid. * * Don't check mac_available flag here as we may be called in the MAC init * phase before everything else is in place... */ if((MSS_MAC_PHYADDR_MAXVAL >= phyaddr) && (MSS_MAC_PHYREGADDR_MAXVAL >= regaddr)) { phy_op = GEM_WRITE1 | (GEM_PHY_OP_CL22_READ << GEM_OPERATION_SHIFT) | (((uint32_t)(2UL)) << GEM_WRITE10_SHIFT); phy_op |= ((uint32_t)phyaddr << GEM_PHY_ADDRESS_SHIFT) & GEM_PHY_ADDRESS; phy_op |= ((uint32_t)regaddr << GEM_REGISTER_ADDRESS_SHIFT) & GEM_REGISTER_ADDRESS; /* * Always use the pMAC for this as the eMAC MDIO interface is not * connected to the outside world... */ lev = HAL_disable_interrupts(); /* Wait for MII Mgmt interface to complete previous operation. */ do { volatile int32_t ix; ix++; } while(0U == (this_mac->mac_base->NETWORK_STATUS & GEM_MAN_DONE)); this_mac->mac_base->PHY_MANAGEMENT = phy_op; do { volatile int32_t ix; ix++; } while(0U == (this_mac->mac_base->NETWORK_STATUS & GEM_MAN_DONE)); phy_op = this_mac->mac_base->PHY_MANAGEMENT; HAL_restore_interrupts(lev); } else { phy_op = 0U; } return((uint16_t)phy_op); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ /* Divide by 4 as offset is in bytes but pointer is 4 bytes */ #define GEM_REG_OFFSET(x) (offsetof(MAC_TypeDef, x) / 4) uint32_t MSS_MAC_read_stat ( const mss_mac_instance_t *this_mac, mss_mac_stat_t stat ) { uint32_t stat_val = 0u; static uint64_t const stat_regs_lut[] = { GEM_REG_OFFSET(OCTETS_TXED_BOTTOM), GEM_REG_OFFSET(OCTETS_TXED_TOP), GEM_REG_OFFSET(FRAMES_TXED_OK), GEM_REG_OFFSET(BROADCAST_TXED), GEM_REG_OFFSET(MULTICAST_TXED), GEM_REG_OFFSET(PAUSE_FRAMES_TXED), GEM_REG_OFFSET(FRAMES_TXED_64), GEM_REG_OFFSET(FRAMES_TXED_65), GEM_REG_OFFSET(FRAMES_TXED_128), GEM_REG_OFFSET(FRAMES_TXED_256), GEM_REG_OFFSET(FRAMES_TXED_512), GEM_REG_OFFSET(FRAMES_TXED_1024), GEM_REG_OFFSET(FRAMES_TXED_1519), GEM_REG_OFFSET(TX_UNDERRUNS), GEM_REG_OFFSET(SINGLE_COLLISIONS), GEM_REG_OFFSET(MULTIPLE_COLLISIONS), GEM_REG_OFFSET(EXCESSIVE_COLLISIONS), GEM_REG_OFFSET(LATE_COLLISIONS), GEM_REG_OFFSET(DEFERRED_FRAMES), GEM_REG_OFFSET(CRS_ERRORS), GEM_REG_OFFSET(OCTETS_RXED_BOTTOM), GEM_REG_OFFSET(OCTETS_RXED_TOP), GEM_REG_OFFSET(FRAMES_RXED_OK), GEM_REG_OFFSET(BROADCAST_RXED), GEM_REG_OFFSET(MULTICAST_RXED), GEM_REG_OFFSET(PAUSE_FRAMES_RXED), GEM_REG_OFFSET(FRAMES_RXED_64), GEM_REG_OFFSET(FRAMES_RXED_65), GEM_REG_OFFSET(FRAMES_RXED_128), GEM_REG_OFFSET(FRAMES_RXED_256), GEM_REG_OFFSET(FRAMES_RXED_512), GEM_REG_OFFSET(FRAMES_RXED_1024), GEM_REG_OFFSET(FRAMES_RXED_1519), GEM_REG_OFFSET(UNDERSIZE_FRAMES), GEM_REG_OFFSET(EXCESSIVE_RX_LENGTH), GEM_REG_OFFSET(RX_JABBERS), GEM_REG_OFFSET(FCS_ERRORS), GEM_REG_OFFSET(RX_LENGTH_ERRORS), GEM_REG_OFFSET(RX_SYMBOL_ERRORS), GEM_REG_OFFSET(ALIGNMENT_ERRORS), GEM_REG_OFFSET(RX_RESOURCE_ERRORS), GEM_REG_OFFSET(RX_OVERRUNS), GEM_REG_OFFSET(RX_IP_CK_ERRORS), GEM_REG_OFFSET(RX_TCP_CK_ERRORS), GEM_REG_OFFSET(RX_UDP_CK_ERRORS), GEM_REG_OFFSET(AUTO_FLUSHED_PKTS) }; ASSERT(MSS_MAC_LAST_STAT > stat); if((MSS_MAC_LAST_STAT > stat) && (MSS_MAC_AVAILABLE == this_mac->mac_available)) { if(0U != this_mac->is_emac) { stat_val = *(((uint32_t *)this_mac->emac_base) + stat_regs_lut[stat]); } else { stat_val = *(((uint32_t *)this_mac->mac_base) + stat_regs_lut[stat]); } } return stat_val; } /******************************************************************************* See mss_ethernet_mac.h for details of how to use this function */ void MSS_MAC_clear_statistics ( const mss_mac_instance_t *this_mac ) { if((0U != this_mac->is_emac) && (MSS_MAC_AVAILABLE == this_mac->mac_available)) { this_mac->emac_base->NETWORK_CONTROL |= GEM_CLEAR_ALL_STATS_REGS; } else { this_mac->mac_base->NETWORK_CONTROL |= GEM_CLEAR_ALL_STATS_REGS; } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint8_t MSS_MAC_receive_pkt ( mss_mac_instance_t *this_mac, uint32_t queue_no, uint8_t * rx_pkt_buffer, void * p_user_data, mss_mac_rx_int_ctrl_t enable ) { uint8_t status = MSS_MAC_FAILED; /* Make this function atomic w.r.to EMAC interrupt */ /* PLIC_DisableIRQ() et al should not be called from the associated interrupt... */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U == this_mac->queue[queue_no].in_isr) { if(0U != this_mac->use_local_ints) { __disable_local_irq(this_mac->mac_q_int[queue_no]); } else { PLIC_DisableIRQ(this_mac->mac_q_int[queue_no]); /* Single interrupt from GEM? */ } } ASSERT(NULL_POINTER != rx_pkt_buffer); ASSERT(IS_WORD_ALIGNED(rx_pkt_buffer)); if(this_mac->queue[queue_no].nb_available_rx_desc > 0U) { uint32_t next_rx_desc_index; if(MSS_MAC_INT_DISABLE == enable) { /* * When setting up the chain of buffers, we don't want the DMA * engine active so shut down reception. */ if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL &= ~GEM_ENABLE_RECEIVE; } else { this_mac->mac_base->NETWORK_CONTROL &= ~GEM_ENABLE_RECEIVE; } } --this_mac->queue[queue_no].nb_available_rx_desc; next_rx_desc_index = this_mac->queue[queue_no].next_free_rx_desc_index; if((MSS_MAC_RX_RING_SIZE - 1U) == next_rx_desc_index) { this_mac->queue[queue_no].rx_desc_tab[next_rx_desc_index].addr_low = (uint32_t)((uint64_t)rx_pkt_buffer | 2UL); /* Set wrap bit */ } else { this_mac->queue[queue_no].rx_desc_tab[next_rx_desc_index].addr_low = (uint32_t)((uint64_t)rx_pkt_buffer); } #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->queue[queue_no].rx_desc_tab[next_rx_desc_index].addr_high = (uint32_t)((uint64_t)rx_pkt_buffer >> 32); #endif this_mac->queue[queue_no].rx_caller_info[next_rx_desc_index] = p_user_data; /* If the RX is found disabled, then it might be because this is the first time a packet is scheduled for reception or the RX ENABLE is made zero by RX overflow or RX bus error. In either case, this function tries to schedule the current packet for reception. Don't bother if we are not enabling interrupt at the end of all this... */ if(MSS_MAC_INT_ARM == enable) { /* * Starting receive operations off with a chain of buffers set up. */ if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL &= ~GEM_ENABLE_RECEIVE; this_mac->emac_base->RECEIVE_Q_PTR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab); #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->emac_base->UPPER_RX_Q_BASE_ADDR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab >> 32); #endif this_mac->emac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } else { this_mac->mac_base->NETWORK_CONTROL &= ~GEM_ENABLE_RECEIVE; *(this_mac->queue[queue_no].receive_q_ptr) = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab); #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->mac_base->UPPER_RX_Q_BASE_ADDR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab >> 32); #endif this_mac->mac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } } else { if(MSS_MAC_INT_DISABLE != enable) { uint32_t temp_cr; if(0U != this_mac->is_emac) { temp_cr = this_mac->emac_base->NETWORK_CONFIG; } else { temp_cr = this_mac->mac_base->NETWORK_CONFIG; } if(0U == (temp_cr & GEM_ENABLE_RECEIVE)) { /* RX disabled so restart it... */ if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } else { this_mac->mac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } } } } /* Point the next_rx_desc to next free descriptor in the ring */ /* Wrap around in case next descriptor is pointing to last in the ring */ ++this_mac->queue[queue_no].next_free_rx_desc_index; this_mac->queue[queue_no].next_free_rx_desc_index %= MSS_MAC_RX_RING_SIZE; } /* * Only call Ethernet Interrupt Enable function if the user says so. * See note above for disable... */ if((MSS_MAC_INT_ARM == enable) && (0U == this_mac->queue[queue_no].in_isr)) { if(0U != this_mac->use_local_ints) { __enable_local_irq(this_mac->mac_q_int[queue_no]); } else { PLIC_EnableIRQ(this_mac->mac_q_int[queue_no]); /* Single interrupt from GEM? */ } } } return status; } /******************************************************************************* * See mss_ethernet_mac.h for details of how to use this function. */ uint8_t MSS_MAC_send_pkt ( mss_mac_instance_t *this_mac, uint32_t queue_no, uint8_t const * tx_buffer, uint32_t length, void * p_user_data ) { /* * Simplified transmit operation which depends on the following assumptions: * * 1. The TX DMA buffer size is big enough to contain a full packet. * 2. We will only transmit one packet at a time. * * We do transmission by using two buffer descriptors. The first contains the * packet to transmit and the second is a dummy one with the USED bit set. This * halts transmission once the first packet is transmitted. We always reset the * TX DMA to point to the first packet when we send a packet so we don't have * to juggle buffer positions or worry about wrap. */ uint32_t tx_length = length; uint8_t status = MSS_MAC_FAILED; /* Hack for system testing. If b31 of the tx_length is 1 then we want to * send without a CRC appended. This is used for loopback testing where we * can get the GEM to receive packets with CRC appended and send them * straight back. * */ int32_t no_crc = 0; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { /* Is config option for disabling CRC set? */ if(MSS_MAC_CRC_DISABLE == this_mac->append_CRC) { no_crc = 1; } /* Or has the user requested just this packet? */ if(0U != (tx_length & 0x80000000U)) { no_crc = 1; } tx_length &= 0x7FFFFFFFU; /* Make sure high bit is now clear */ /* Make this function atomic w.r.to EMAC interrupt */ /* PLIC_DisableIRQ() et al should not be called from the associated interrupt... */ if(0U == this_mac->queue[queue_no].in_isr) { if(0U != this_mac->use_local_ints) { __disable_local_irq(this_mac->mac_q_int[queue_no]); } else { PLIC_DisableIRQ(this_mac->mac_q_int[queue_no]); /* Single interrupt from GEM? */ } } ASSERT(NULL_POINTER != tx_buffer); ASSERT(0U != tx_length); ASSERT(IS_WORD_ALIGNED(tx_buffer)); #if defined(MSS_MAC_SIMPLE_TX_QUEUE) if(this_mac->queue[queue_no].nb_available_tx_desc == (uint32_t)MSS_MAC_TX_RING_SIZE) { this_mac->queue[queue_no].nb_available_tx_desc = 0U; this_mac->queue[queue_no].tx_desc_tab[0].addr_low = (uint32_t)((uint64_t)tx_buffer); this_mac->queue[queue_no].tx_desc_tab[0].status = (tx_length & GEM_TX_DMA_BUFF_LEN) | GEM_TX_DMA_LAST; /* Mark as last buffer for frame */ if(0 != no_crc) { this_mac->queue[queue_no].tx_desc_tab[0].status |= GEM_TX_DMA_NO_CRC; } #if 0 this_mac->tx_desc_tab[0].status = (tx_length & GEM_TX_DMA_BUFF_LEN) | GEM_TX_DMA_LAST | GEM_TX_DMA_USED; /* PMCS deliberate error ! */ #endif #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->queue[queue_no].tx_desc_tab[0].addr_high = (uint32_t)((uint64_t)tx_buffer >> 32); this_mac->queue[queue_no].tx_desc_tab[0].unused = 0U; #endif this_mac->queue[queue_no].tx_caller_info[0] = p_user_data; if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL |= GEM_ENABLE_TRANSMIT | GEM_TRANSMIT_HALT; this_mac->emac_base->TRANSMIT_Q_PTR = (uint32_t)((uint64_t)this_mac->queue[queue_no].tx_desc_tab); this_mac->emac_base->NETWORK_CONTROL |= GEM_TRANSMIT_START; } else { this_mac->mac_base->NETWORK_CONTROL |= GEM_ENABLE_TRANSMIT | GEM_TRANSMIT_HALT; *this_mac->queue[queue_no].transmit_q_ptr = (uint32_t)((uint64_t)this_mac->queue[queue_no].tx_desc_tab); this_mac->mac_base->NETWORK_CONTROL |= GEM_TRANSMIT_START; } this_mac->queue[queue_no].egress += tx_length; status = MSS_MAC_SUCCESS; } #else /* TBD PMCS need to implement multi packet queuing... */ #warning "Nothing implemented for multi packet tx yet" #endif /* Ethernet Interrupt Enable function. */ /* PLIC_DisableIRQ() et al should not be called from the associated interrupt... */ if(0U == this_mac->queue[queue_no].in_isr) { if(0U != this_mac->use_local_ints) { __enable_local_irq(this_mac->mac_q_int[queue_no]); } else { PLIC_EnableIRQ(this_mac->mac_q_int[queue_no]); /* Single interrupt from GEM? */ } } } return status; } /****************************************************************************** * */ #if defined(USING_LWIP) extern BaseType_t g_mac_context_switch; #endif #if defined(USING_FREERTOS) extern UBaseType_t uxCriticalNesting; #endif #if defined(TARGET_ALOE) uint8_t MAC0_plic_53_IRQHandler(void); uint8_t MAC0_plic_53_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 0U); #endif return(EXT_IRQ_KEEP_ENABLED); } #else /****************************************************************************** * */ uint8_t mac0_int_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 0U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac0_queue1_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 1U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 1U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac0_queue2_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 2U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 2U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac0_queue3_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 3U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 3U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac0_emac_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_emac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_emac0, 0U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac0_mmsl_plic_IRQHandler(void) { return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac1_int_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 0U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac1_queue1_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 1U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 1U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac1_queue2_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 2U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 2U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac1_queue3_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 3U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 3U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac1_emac_plic_IRQHandler(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_emac1, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_emac1, 0U); #endif return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ uint8_t mac1_mmsl_plic_IRQHandler(void) { return(EXT_IRQ_KEEP_ENABLED); } /****************************************************************************** * */ /* U54 1 */ void mac_mmsl_u54_1_local_IRQHandler_3(void) { } /****************************************************************************** * */ void mac_emac_u54_1_local_IRQHandler_4(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_emac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_emac0, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue3_u54_1_local_IRQHandler_5(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 3U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 3U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue2_u54_1_local_IRQHandler_6(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 2U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 2U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue1_u54_1_local_IRQHandler_7(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 1U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 1U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_int_u54_1_local_IRQHandler_8(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ /* U54 2 */ void mac_mmsl_u54_2_local_IRQHandler_3(void) { } /****************************************************************************** * */ void mac_emac_u54_2_local_IRQHandler_4(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_emac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_emac0, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue3_u54_2_local_IRQHandler_5(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 3U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 3U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue2_u54_2_local_IRQHandler_6(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 2U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 2U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue1_u54_2_local_IRQHandler_7(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 1U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 1U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_int_u54_2_local_IRQHandler_8(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac0, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac0, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ /* U54 3 */ void mac_mmsl_u54_3_local_IRQHandler_3(void) { } /****************************************************************************** * */ void mac_emac_u54_3_local_IRQHandler_4(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_emac1, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_emac1, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue3_u54_3_local_IRQHandler_5(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 3U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 3U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue2_u54_3_local_IRQHandler_6(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 2U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 2U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue1_u54_3_local_IRQHandler_7(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 1U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 1U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_int_u54_3_local_IRQHandler_8(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ /* U54 4 */ void mac_mmsl_u54_4_local_IRQHandler_3(void) { } /****************************************************************************** * */ void mac_emac_u54_4_local_IRQHandler_4(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_emac1, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_emac1, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue3_u54_4_local_IRQHandler_5(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 3U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 3U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue2_u54_4_local_IRQHandler_6(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 2U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 2U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_queue1_u54_4_local_IRQHandler_7(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 1U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 1U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } /****************************************************************************** * */ void mac_int_u54_4_local_IRQHandler_8(void) { #if defined(USING_FREERTOS) uxCriticalNesting++; generic_mac_irq_handler(&g_mac1, 0U); uxCriticalNesting--; #else generic_mac_irq_handler(&g_mac1, 0U); #endif #if defined(USING_LWIP) if(0 != g_mac_context_switch) { g_mac_context_switch = 0; vPortYieldISR(); } #endif } #endif /* Define the following if your GEM is configured to clear on read for int flags * In this case you should not write to the int status reg ... */ /* #define GEM_FLAGS_CLR_ON_RD */ static void generic_mac_irq_handler(mss_mac_instance_t *this_mac, uint32_t queue_no) { volatile uint32_t int_pending; /* We read and hold a working copy as many * of the bits can be clear on read if * the GEM is configured that way... */ volatile uint32_t *rx_status; /* Address of receive status register */ volatile uint32_t *tx_status; /* Address of transmit status register */ volatile uint32_t *int_status; /* Address of interrupt status register */ this_mac->queue[queue_no].in_isr = 1U; int_status = this_mac->queue[queue_no].int_status; int_pending = *int_status & ~(*this_mac->queue[queue_no].int_mask); if(0U != this_mac->is_emac) { rx_status = &this_mac->emac_base->RECEIVE_STATUS; tx_status = &this_mac->emac_base->TRANSMIT_STATUS; } else { rx_status = &this_mac->mac_base->RECEIVE_STATUS; tx_status = &this_mac->mac_base->TRANSMIT_STATUS; } /* * Note, in the following code we generally clear any flags first and then * handle the condition as this allows any new events which occur in the * course of the ISR to be picked up later. */ /* Packet received interrupt - first in line as most time critical */ if((int_pending & GEM_RECEIVE_COMPLETE) != 0U) { *rx_status = GEM_FRAME_RECEIVED; #if !defined(GEM_FLAGS_CLR_ON_RD) #if defined(TARGET_ALOE) *int_status = (uint32_t)3U; /* PMCS: Should be 2 but that does not work on Aloe... */ #else *int_status = (uint32_t)2U; #endif rxpkt_handler(this_mac, queue_no); this_mac->queue[queue_no].overflow_counter = 0U; /* Reset counter as we have received something */ #endif } if((int_pending & GEM_RECEIVE_OVERRUN_INT) != 0U) { *rx_status = GEM_RECEIVE_OVERRUN; #if !defined(GEM_FLAGS_CLR_ON_RD) *int_status = GEM_RECEIVE_OVERRUN_INT; #endif rxpkt_handler(this_mac, queue_no); this_mac->queue[queue_no].overflow_counter++; this_mac->queue[queue_no].rx_overflow++; } if((int_pending & GEM_RX_USED_BIT_READ) != 0U) { *rx_status = GEM_BUFFER_NOT_AVAILABLE; #if !defined(GEM_FLAGS_CLR_ON_RD) *int_status = GEM_RX_USED_BIT_READ; #endif rxpkt_handler(this_mac, queue_no); this_mac->queue[queue_no].rx_overflow++; this_mac->queue[queue_no].overflow_counter++; } if((int_pending & GEM_RESP_NOT_OK_INT) != 0U) /* Hope this is transient and restart rx... */ { *rx_status = GEM_RX_RESP_NOT_OK; #if !defined(GEM_FLAGS_CLR_ON_RD) *int_status = GEM_RESP_NOT_OK_INT; #endif rxpkt_handler(this_mac, queue_no); if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } else { this_mac->mac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } this_mac->queue[queue_no].hresp_error++; } /* Transmit packet sent interrupt */ if((int_pending & GEM_TRANSMIT_COMPLETE) != 0U) { if((*tx_status & GEM_STAT_TRANSMIT_COMPLETE) != 0U) /* If loopback test or other hasn't taken care of this... */ { *tx_status = GEM_STAT_TRANSMIT_COMPLETE; #if !defined(GEM_FLAGS_CLR_ON_RD) *int_status = GEM_TRANSMIT_COMPLETE; #endif txpkt_handler(this_mac, queue_no); } } if(this_mac->queue[queue_no].overflow_counter > 4U) /* looks like we are stuck in a rut here... */ { uint32_t descriptor; /* Restart receive operation from scratch */ this_mac->queue[queue_no].overflow_counter = 0U; this_mac->queue[queue_no].rx_restart++; if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL &= ~GEM_ENABLE_RECEIVE; } else { this_mac->mac_base->NETWORK_CONTROL &= ~GEM_ENABLE_RECEIVE; } this_mac->queue[queue_no].nb_available_rx_desc = MSS_MAC_RX_RING_SIZE; this_mac->queue[queue_no].next_free_rx_desc_index = 0U; this_mac->queue[queue_no].first_rx_desc_index = 0U; for(descriptor = 0U; descriptor < MSS_MAC_RX_RING_SIZE; descriptor++) /* Discard everything */ { this_mac->queue[queue_no].rx_desc_tab[descriptor].addr_low &= GEM_RX_DMA_USED; } if(0U != this_mac->is_emac) { this_mac->emac_base->RECEIVE_Q_PTR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab); #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->emac_base->UPPER_RX_Q_BASE_ADDR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab >> 32); #endif this_mac->emac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } else { this_mac->mac_base->RECEIVE_Q_PTR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab); #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->mac_base->UPPER_RX_Q_BASE_ADDR = (uint32_t)((uint64_t)this_mac->queue[queue_no].rx_desc_tab >> 32); #endif this_mac->mac_base->NETWORK_CONTROL |= GEM_ENABLE_RECEIVE; } } if((int_pending & GEM_PAUSE_FRAME_TRANSMITTED) != 0U) { *int_status = GEM_PAUSE_FRAME_TRANSMITTED; this_mac->tx_pause++; } if((int_pending & GEM_PAUSE_TIME_ELAPSED) != 0U) { *int_status = GEM_PAUSE_TIME_ELAPSED; this_mac->pause_elapsed++; } if((int_pending & GEM_PAUSE_FRAME_WITH_NON_0_PAUSE_QUANTUM_RX) != 0U) { *int_status = GEM_PAUSE_FRAME_WITH_NON_0_PAUSE_QUANTUM_RX; this_mac->rx_pause++; } /* Mask off checked ints and see if any left pending */ int_pending &= ~(GEM_RECEIVE_OVERRUN_INT | GEM_RX_USED_BIT_READ | GEM_RECEIVE_COMPLETE | GEM_TRANSMIT_COMPLETE | GEM_RESP_NOT_OK_INT | GEM_PAUSE_FRAME_TRANSMITTED | GEM_PAUSE_TIME_ELAPSED | GEM_PAUSE_FRAME_WITH_NON_0_PAUSE_QUANTUM_RX); if(0U != int_pending) { if((int_pending & GEM_AMBA_ERROR) != 0U) { *int_status = (uint32_t)0x60U; /* Should be 0x40 but that doesn't clear it... */ *tx_status = GEM_STAT_AMBA_ERROR; this_mac->queue[queue_no].tx_amba_errors++; this_mac->queue[queue_no].nb_available_tx_desc = MSS_MAC_TX_RING_SIZE; } else { volatile int32_t index; ASSERT(0); /* Need to think about how to deal with this... */ while(1) { index++; } } } this_mac->queue[queue_no].in_isr = 0U; } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_tx_callback ( mss_mac_instance_t *this_mac, uint32_t queue_no, mss_mac_transmit_callback_t tx_complete_handler ) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { this_mac->queue[queue_no].pckt_tx_callback = tx_complete_handler; } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_rx_callback ( mss_mac_instance_t *this_mac, uint32_t queue_no, mss_mac_receive_callback_t rx_callback ) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { this_mac->queue[queue_no].pckt_rx_callback = rx_callback; } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_init_TSU(const mss_mac_instance_t *this_mac, const mss_mac_tsu_config_t *tsu_cfg) { uint32_t temp; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { temp = (tsu_cfg->sub_ns_inc & 0xFFU) << 24; temp |= (tsu_cfg->sub_ns_inc >> 8) & 0xFFFFU; if(0U != this_mac->is_emac) { #if 0 /* Shouldn't really allow setting of tsu through eMAC as it is slaved to pMAC TSU */ this_mac->emac_base->TSU_TIMER_INCR_SUB_NSEC = temp; this_mac->emac_base->TSU_TIMER_INCR = tsu_cfg->ns_inc; /* PMCS: I'm not 100% sure about the sequencing here... */ this_mac->emac_base->TSU_TIMER_MSB_SEC = tsu_cfg->secs_msb; this_mac->emac_base->TSU_TIMER_SEC = tsu_cfg->secs_lsb; this_mac->emac_base->TSU_TIMER_NSEC = tsu_cfg->nanoseconds; #endif } else { this_mac->mac_base->TSU_TIMER_INCR_SUB_NSEC = temp; this_mac->mac_base->TSU_TIMER_INCR = tsu_cfg->ns_inc; this_mac->mac_base->TSU_TIMER_MSB_SEC = tsu_cfg->secs_msb; this_mac->mac_base->TSU_TIMER_SEC = tsu_cfg->secs_lsb; this_mac->mac_base->TSU_TIMER_NSEC = tsu_cfg->nanoseconds; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_read_TSU(const mss_mac_instance_t *this_mac, mss_mac_tsu_time_t *tsu_time) { int32_t got_time = 0; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { do { if(0U != this_mac->is_emac) { tsu_time->secs_lsb = this_mac->emac_base->TSU_TIMER_SEC; tsu_time->secs_msb = this_mac->emac_base->TSU_TIMER_MSB_SEC; tsu_time->nanoseconds = this_mac->emac_base->TSU_TIMER_NSEC; /* Check for nanoseconds roll over and exit loop if none otherwise do again */ if(tsu_time->secs_lsb == this_mac->emac_base->TSU_TIMER_SEC) { got_time = 1; } } else { tsu_time->secs_lsb = this_mac->mac_base->TSU_TIMER_SEC; tsu_time->secs_msb = this_mac->mac_base->TSU_TIMER_MSB_SEC; tsu_time->nanoseconds = this_mac->mac_base->TSU_TIMER_NSEC; /* Check for nanoseconds roll over and exit loop if none otherwise do again */ if(tsu_time->secs_lsb == this_mac->mac_base->TSU_TIMER_SEC) { got_time = 1; } } } while(0 == got_time); } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_TSU_rx_mode(const mss_mac_instance_t *this_mac, mss_mac_tsu_mode_t tsu_mode) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { this_mac->emac_base->RX_BD_CONTROL = ((uint32_t)tsu_mode << GEM_BD_TS_MODE_SHIFT) & GEM_BD_TS_MODE; } else { this_mac->mac_base->RX_BD_CONTROL = ((uint32_t)tsu_mode << GEM_BD_TS_MODE_SHIFT) & GEM_BD_TS_MODE; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_TSU_tx_mode(const mss_mac_instance_t *this_mac, mss_mac_tsu_mode_t tsu_mode) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { this_mac->emac_base->TX_BD_CONTROL = ((uint32_t)tsu_mode << GEM_BD_TS_MODE_SHIFT) & GEM_BD_TS_MODE; } else { this_mac->mac_base->TX_BD_CONTROL = ((uint32_t)tsu_mode << GEM_BD_TS_MODE_SHIFT) & GEM_BD_TS_MODE; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ mss_mac_tsu_mode_t MSS_MAC_get_TSU_rx_mode(const mss_mac_instance_t *this_mac) { mss_mac_tsu_mode_t ret_val = MSS_MAC_TSU_MODE_DISABLED; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { ret_val = (mss_mac_tsu_mode_t)((this_mac->emac_base->RX_BD_CONTROL & GEM_BD_TS_MODE) >> GEM_BD_TS_MODE_SHIFT); } else { ret_val = (mss_mac_tsu_mode_t)((this_mac->mac_base->RX_BD_CONTROL & GEM_BD_TS_MODE) >> GEM_BD_TS_MODE_SHIFT); } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ mss_mac_tsu_mode_t MSS_MAC_get_TSU_tx_mode(const mss_mac_instance_t *this_mac) { mss_mac_tsu_mode_t ret_val= MSS_MAC_TSU_MODE_DISABLED; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { ret_val = (mss_mac_tsu_mode_t)((this_mac->emac_base->TX_BD_CONTROL & GEM_BD_TS_MODE) >> GEM_BD_TS_MODE_SHIFT); } else { ret_val = (mss_mac_tsu_mode_t)((this_mac->mac_base->TX_BD_CONTROL & GEM_BD_TS_MODE) >> GEM_BD_TS_MODE_SHIFT); } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_TSU_oss_mode(const mss_mac_instance_t *this_mac, mss_mac_oss_mode_t oss_mode) { volatile uint32_t temp_control; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { temp_control = this_mac->emac_base->NETWORK_CONTROL; } else { temp_control = this_mac->mac_base->NETWORK_CONTROL; } /* * Note. The docs don't say these are mutually exclusive but I don't think * it makes sense to allow both modes at once... */ if(MSS_MAC_OSS_MODE_DISABLED == oss_mode) { temp_control &= ~(GEM_OSS_CORRECTION_FIELD | GEM_ONE_STEP_SYNC_MODE); } else if(MSS_MAC_OSS_MODE_REPLACE == oss_mode) { temp_control &= ~GEM_OSS_CORRECTION_FIELD; temp_control |= GEM_ONE_STEP_SYNC_MODE; } else { if(MSS_MAC_OSS_MODE_ADJUST == oss_mode) { temp_control |= GEM_OSS_CORRECTION_FIELD; temp_control &= ~GEM_ONE_STEP_SYNC_MODE; } } if(0U != this_mac->is_emac) { this_mac->emac_base->NETWORK_CONTROL = temp_control; } else { this_mac->mac_base->NETWORK_CONTROL = temp_control; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ mss_mac_oss_mode_t MSS_MAC_get_TSU_oss_mode(const mss_mac_instance_t *this_mac) { mss_mac_oss_mode_t ret_val = MSS_MAC_OSS_MODE_DISABLED; volatile uint32_t temp_control; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { temp_control = this_mac->emac_base->NETWORK_CONTROL; } else { temp_control = this_mac->mac_base->NETWORK_CONTROL; } /* * Note. The docs don't say these are mutually exclusive but I don't think * it makes sense to allow both modes at once so report this as invalid... */ if((GEM_OSS_CORRECTION_FIELD | GEM_ONE_STEP_SYNC_MODE) == (temp_control & (GEM_OSS_CORRECTION_FIELD | GEM_ONE_STEP_SYNC_MODE))) { ret_val = MSS_MAC_OSS_MODE_INVALID; } else if(GEM_OSS_CORRECTION_FIELD == (temp_control & GEM_OSS_CORRECTION_FIELD)) { ret_val = MSS_MAC_OSS_MODE_ADJUST; } else if(GEM_ONE_STEP_SYNC_MODE == (temp_control & GEM_ONE_STEP_SYNC_MODE)) { ret_val = MSS_MAC_OSS_MODE_REPLACE; } else { ret_val = MSS_MAC_OSS_MODE_DISABLED; } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_TSU_unicast_addr(const mss_mac_instance_t *this_mac, mss_mac_tsu_addr_t select, uint32_t ip_address) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(MSS_MAC_TSU_UNICAST_RX == select) { this_mac->emac_base->RX_PTP_UNICAST = ip_address; } else { this_mac->emac_base->TX_PTP_UNICAST = ip_address; } } else { if(MSS_MAC_TSU_UNICAST_RX == select) { this_mac->mac_base->RX_PTP_UNICAST = ip_address; } else { this_mac->mac_base->TX_PTP_UNICAST = ip_address; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint32_t MSS_MAC_get_TSU_unicast_addr(const mss_mac_instance_t *this_mac, mss_mac_tsu_addr_t select) { uint32_t ret_val = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(MSS_MAC_TSU_UNICAST_RX == select) { ret_val = this_mac->emac_base->RX_PTP_UNICAST; } else { ret_val = this_mac->emac_base->TX_PTP_UNICAST; } } else { if(MSS_MAC_TSU_UNICAST_RX == select) { ret_val = this_mac->mac_base->RX_PTP_UNICAST; } else { ret_val = this_mac->mac_base->TX_PTP_UNICAST; } } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_VLAN_only_mode(const mss_mac_instance_t *this_mac, bool enable) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(false == enable) { this_mac->emac_base->NETWORK_CONFIG &= ~GEM_DISCARD_NON_VLAN_FRAMES; } else { this_mac->emac_base->NETWORK_CONFIG |= GEM_DISCARD_NON_VLAN_FRAMES; } } else { if(false == enable) { this_mac->mac_base->NETWORK_CONFIG &= ~GEM_DISCARD_NON_VLAN_FRAMES; } else { this_mac->mac_base->NETWORK_CONFIG |= GEM_DISCARD_NON_VLAN_FRAMES; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ bool MSS_MAC_get_VLAN_only_mode(const mss_mac_instance_t *this_mac) { bool ret_val = false; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { ret_val = 0U != (this_mac->emac_base->NETWORK_CONFIG & GEM_DISCARD_NON_VLAN_FRAMES); } else { ret_val = 0U != (this_mac->mac_base->NETWORK_CONFIG & GEM_DISCARD_NON_VLAN_FRAMES); } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_stacked_VLAN(const mss_mac_instance_t *this_mac, uint16_t tag) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(GEM_VLAN_ETHERTYPE_MIN > tag) { this_mac->emac_base->STACKED_VLAN = 0U; } else { this_mac->emac_base->STACKED_VLAN = (uint32_t)tag | GEM_ENABLE_PROCESSING; } } else { if(GEM_VLAN_ETHERTYPE_MIN > tag) { this_mac->mac_base->STACKED_VLAN = 0U; } else { this_mac->mac_base->STACKED_VLAN = (uint32_t)tag | GEM_ENABLE_PROCESSING; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint16_t MSS_MAC_get_stacked_VLAN(const mss_mac_instance_t *this_mac) { uint16_t ret_val = GEM_VLAN_NO_STACK; /* Return 0 if stacked VLANs not enabled */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(0U != (this_mac->emac_base->STACKED_VLAN & GEM_ENABLE_PROCESSING)) { ret_val = (uint16_t)this_mac->emac_base->STACKED_VLAN; } } else { if(0U != (this_mac->mac_base->STACKED_VLAN & GEM_ENABLE_PROCESSING)) { ret_val = (uint16_t)this_mac->mac_base->STACKED_VLAN; } } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_hash(const mss_mac_instance_t *this_mac, uint64_t hash_in) { uint64_t hash = hash_in; /* Avoids warning about modifying fn parameter passed by value */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(0ULL == hash) /* Short cut for disabling */ { this_mac->emac_base->NETWORK_CONFIG &= ~(GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE); } this_mac->emac_base->HASH_BOTTOM = (uint32_t)hash; hash >>= 32; this_mac->emac_base->HASH_TOP = (uint32_t)hash; } else { if(0ULL == hash) /* Short cut for disabling */ { this_mac->mac_base->NETWORK_CONFIG &= ~(GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE); } this_mac->mac_base->HASH_BOTTOM = (uint32_t)hash; hash >>= 32; this_mac->mac_base->HASH_TOP = (uint32_t)hash; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint64_t MSS_MAC_get_hash(const mss_mac_instance_t *this_mac) { uint64_t ret_val = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { ret_val = (uint64_t)this_mac->emac_base->HASH_TOP; ret_val <<= 32; ret_val |= (uint64_t)this_mac->emac_base->HASH_BOTTOM; } else { ret_val = (uint64_t)this_mac->mac_base->HASH_TOP; ret_val <<= 32; ret_val |= (uint64_t)this_mac->mac_base->HASH_BOTTOM; } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_hash_mode(const mss_mac_instance_t *this_mac, mss_mac_hash_mode_t mode) { uint32_t temp; /* * Enum values are matched to register bits but just to be safe we mask them * to ensure only the two hash control bits are modified... */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { temp = this_mac->emac_base->NETWORK_CONFIG & ~(GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE); temp |= (uint32_t)mode & (GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE); this_mac->emac_base->NETWORK_CONFIG = temp; } else { temp = this_mac->mac_base->NETWORK_CONFIG & ~(GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE); temp |= (uint32_t)mode & (GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE); this_mac->mac_base->NETWORK_CONFIG = temp; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ mss_mac_hash_mode_t MSS_MAC_get_hash_mode(const mss_mac_instance_t *this_mac) { mss_mac_hash_mode_t ret_val = 0; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { ret_val = (mss_mac_hash_mode_t)(this_mac->emac_base->NETWORK_CONFIG & (GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE)); } else { ret_val = (mss_mac_hash_mode_t)(this_mac->mac_base->NETWORK_CONFIG & (GEM_UNICAST_HASH_ENABLE | GEM_MULTICAST_HASH_ENABLE)); } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_type_filter(const mss_mac_instance_t *this_mac, uint32_t filter, uint16_t value) { volatile uint32_t *p_reg; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->SPEC_TYPE1; } else { p_reg = &this_mac->mac_base->SPEC_TYPE1; } if((filter <= 4U) && (filter > 0U)) /* Filter is in range 1 to 4 to match register naming */ { p_reg += filter - 1U; if(0U == value) /* Disable filter if match value is 0 as this should not be a valid type */ { *p_reg = 0U; } else { *p_reg = (uint32_t)(0x80000000UL | (uint32_t)value); } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint16_t MSS_MAC_get_type_filter(const mss_mac_instance_t *this_mac, uint32_t filter) { volatile uint32_t *p_reg; uint16_t ret_val = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->SPEC_TYPE1; } else { p_reg = &this_mac->mac_base->SPEC_TYPE1; } if((filter <= 4U) && (filter > 0U)) /* Filter is in range 1 to 4 to match register naming */ { p_reg += filter - 1U; if(0U != (*p_reg & 0x80000000UL)) /* Not disabled filter... */ { ret_val = (uint16_t)*p_reg; } } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_sa_filter(const mss_mac_instance_t *this_mac, uint32_t filter, uint16_t control, const uint8_t *mac_addr) { volatile uint32_t *p_reg; uint32_t address32_l; uint32_t address32_h; ASSERT(NULL_POINTER!= mac_addr); if((MSS_MAC_AVAILABLE == this_mac->mac_available) && (NULL_POINTER != mac_addr)) { if((filter >= 2U) && (filter <= 4U)) /* SA Filter 1 is for our address */ { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->SPEC_ADD2_BOTTOM; } else { p_reg = &this_mac->mac_base->SPEC_ADD2_BOTTOM; } p_reg = p_reg + ((filter - 2U) * 2U); if(MSS_MAC_SA_FILTER_DISABLE == control) { /* * Clear filter and disable - must be done in this order... * Writing to [0] disables and [1] enables So this sequence * clears the registers and disables the filter as opposed to * setting a destination address filter for 00:00:00:00:00:00. */ p_reg[1] = 0U; p_reg[0] = 0U; } else { /* Assemble correct register values */ address32_l = ((uint32_t)mac_addr[3]) << 24; address32_l |= ((uint32_t)mac_addr[2]) << 16; address32_l |= ((uint32_t)mac_addr[1]) << 8; address32_l |= ((uint32_t)mac_addr[0]); address32_h = ((uint32_t)mac_addr[5]) << 8; address32_h |= ((uint32_t)mac_addr[4]); address32_h |= (uint32_t)control << 16; /* Update hardware registers - must be done in this order... */ p_reg[0] = address32_l; p_reg[1] = address32_h; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint16_t MSS_MAC_get_sa_filter(const mss_mac_instance_t *this_mac, uint32_t filter, uint8_t *mac_addr) { volatile uint32_t *p_reg; uint32_t temp_reg; uint16_t ret_val = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(NULL_POINTER != mac_addr) { (void)memset(mac_addr, 0, 6); /* Consistent result if bad parameters passed... */ } if((filter >= 2U) && (filter <= 4U)) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->SPEC_ADD2_BOTTOM; } else { p_reg = &this_mac->mac_base->SPEC_ADD2_BOTTOM; } p_reg = p_reg + ((filter - 2U) * 2U); if(NULL_POINTER != mac_addr) /* Want MAC address and filter control info? */ { temp_reg = p_reg[0]; mac_addr[0] = (uint8_t)temp_reg & BITS_08; temp_reg >>= 8; mac_addr[1] = (uint8_t)temp_reg & BITS_08; temp_reg >>= 8; mac_addr[2] = (uint8_t)temp_reg & BITS_08; temp_reg >>= 8; mac_addr[3] = (uint8_t)temp_reg & BITS_08; temp_reg = p_reg[1]; mac_addr[4] = (uint8_t)temp_reg & BITS_08; temp_reg >>= 8; mac_addr[5] = (uint8_t)temp_reg & BITS_08; } ret_val = (uint16_t)(p_reg[1] >> 16); } } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_type_1_filter(const mss_mac_instance_t *this_mac, uint32_t filter_no, const mss_mac_type_1_filter_t *filter) { if((MSS_MAC_AVAILABLE == this_mac->mac_available) && (filter_no < MSS_MAC_TYPE_1_SCREENERS)) { volatile uint32_t *p_reg; uint32_t temp_reg; if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->SCREENING_TYPE_1_REGISTER_0; } else { p_reg = &this_mac->mac_base->SCREENING_TYPE_1_REGISTER_0; } temp_reg = (uint32_t)filter->queue_no & GEM_QUEUE_NUMBER; temp_reg |= ((uint32_t)filter->dstc << GEM_DSTC_MATCH_SHIFT) & GEM_DSTC_MATCH; temp_reg |= ((uint32_t)filter->udp_port << GEM_UDP_PORT_MATCH_SHIFT) & GEM_UDP_PORT_MATCH; if(0U != filter->drop_on_match) { temp_reg |= GEM_DROP_ON_MATCH; } if(0U != filter->dstc_enable) { temp_reg |= GEM_DSTC_ENABLE; } if(0U != filter->udp_port_enable) { temp_reg |= GEM_UDP_PORT_MATCH_ENABLE; } p_reg[filter_no] = temp_reg; } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_get_type_1_filter(const mss_mac_instance_t *this_mac, uint32_t filter_no, mss_mac_type_1_filter_t *filter) { if((MSS_MAC_AVAILABLE == this_mac->mac_available) && (filter_no < MSS_MAC_TYPE_1_SCREENERS)) { volatile uint32_t *p_reg; uint32_t temp_reg; (void)memset(filter, 0, sizeof(mss_mac_type_1_filter_t)); /* Blank canvass to start */ if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->SCREENING_TYPE_1_REGISTER_0; } else { p_reg = &this_mac->mac_base->SCREENING_TYPE_1_REGISTER_0; } temp_reg = p_reg[filter_no]; filter->queue_no = (uint8_t)(temp_reg & GEM_QUEUE_NUMBER); temp_reg >>= 4; filter->dstc = (uint8_t)(temp_reg & GEM_DSTC_MATCH); temp_reg >>= GEM_DSTC_MATCH_SHIFT; filter->udp_port = (uint16_t)(temp_reg & GEM_UDP_PORT_MATCH); temp_reg >>= GEM_UDP_PORT_MATCH_SHIFT; filter->dstc_enable = (uint8_t)(temp_reg & 1U); temp_reg >>= 1; filter->udp_port_enable = (uint8_t)(temp_reg & 1U); temp_reg >>= 1; filter->drop_on_match = (uint8_t)(temp_reg & 1U); } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_type_2_ethertype(const mss_mac_instance_t *this_mac, uint32_t ethertype_no, uint16_t ethertype) { volatile uint32_t *p_reg; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U == this_mac->is_emac) /* Ethertype filter not supported on eMAC */ { p_reg = &this_mac->mac_base->SCREENING_TYPE_2_ETHERTYPE_REG_0; if(ethertype_no < MSS_MAC_TYPE_2_ETHERTYPES) { p_reg[ethertype_no] = (uint32_t)ethertype; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint16_t MSS_MAC_get_type_2_ethertype(const mss_mac_instance_t *this_mac, uint32_t ethertype_no) { volatile uint32_t *p_reg; uint16_t temp_reg = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U == this_mac->is_emac) /* Ethertype filter not supported on eMAC */ { p_reg = &this_mac->mac_base->SCREENING_TYPE_2_ETHERTYPE_REG_0; if(ethertype_no < MSS_MAC_TYPE_2_ETHERTYPES) { temp_reg = (uint16_t)p_reg[ethertype_no]; } } } return(temp_reg); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_type_2_compare(const mss_mac_instance_t *this_mac, uint32_t comparer_no_in, const mss_mac_type_2_compare_t *comparer) { volatile uint32_t *p_reg; uint32_t limit; uint32_t temp_reg; uint32_t comparer_no = comparer_no_in; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) /* eMAC limits are different to pMAC ones */ { p_reg = &this_mac->emac_base->TYPE2_COMPARE_0_WORD_0; limit = MSS_MAC_EMAC_TYPE_2_COMPARERS; } else { p_reg = &this_mac->mac_base->TYPE2_COMPARE_0_WORD_0; limit = MSS_MAC_TYPE_2_COMPARERS; } if(comparer_no < limit) { comparer_no *= 2U; /* Working with consecutive pairs of registers for this one */ if(0U != comparer->disable_mask) { p_reg[comparer_no] = comparer->data; /* Mask disabled so just 4 byte compare value */ temp_reg = GEM_DISABLE_MASK; /* and no mask */ } else { temp_reg = comparer->data << 16; /* 16 bit compare value and 16 bit mask */ temp_reg |= (uint32_t)comparer->mask; p_reg[comparer_no] = temp_reg; temp_reg = 0U; } if(0U != comparer->compare_vlan_c_id) { temp_reg |= GEM_COMPARE_VLAN_ID; } else if(0U != comparer->compare_vlan_s_id) { temp_reg |= GEM_COMPARE_VLAN_ID | GEM_COMPARE_S_TAG; } else { temp_reg |= (uint32_t)comparer->offset_value & BITS_07; temp_reg |= ((uint32_t)comparer->compare_offset & BITS_02) << GEM_COMPARE_OFFSET_SHIFT; } p_reg[comparer_no + 1] = temp_reg; /* Set second word of comparer */ } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_get_type_2_compare(const mss_mac_instance_t *this_mac, uint32_t comparer_no_in, mss_mac_type_2_compare_t *comparer) { volatile uint32_t *p_reg; uint32_t limit; uint32_t comparer_no = comparer_no_in; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) /* eMAC limits are different to pMAC ones */ { p_reg = &this_mac->emac_base->TYPE2_COMPARE_0_WORD_0; limit = MSS_MAC_EMAC_TYPE_2_COMPARERS; } else { p_reg = &this_mac->mac_base->TYPE2_COMPARE_0_WORD_0; limit = MSS_MAC_TYPE_2_COMPARERS; } (void)memset(comparer, 0, sizeof(mss_mac_type_2_compare_t)); if(comparer_no < limit) { comparer_no *= 2U; /* Working with consecutive pairs of registers for this one */ if(0U != (p_reg[comparer_no + 1] & GEM_DISABLE_MASK)) { comparer->data = p_reg[comparer_no]; /* Mask disabled so just 4 byte compare value */ comparer->disable_mask = 1; /* and no mask */ } else { comparer->data = p_reg[comparer_no] >> 16; /* 16 bit compare value and 16 bit mask */ comparer->mask = (uint16_t)p_reg[comparer_no]; } if(0U != (p_reg[comparer_no + 1U] & GEM_COMPARE_VLAN_ID)) { if(0U != (p_reg[comparer_no + 1U] & GEM_COMPARE_S_TAG)) { comparer->compare_vlan_s_id = 1U; } else { comparer->compare_vlan_c_id = 1U; } } else { comparer->compare_offset = (uint8_t)((p_reg[comparer_no + 1U] >> GEM_COMPARE_OFFSET_SHIFT) & BITS_02); } comparer->offset_value = (uint8_t)(p_reg[comparer_no + 1U] & GEM_OFFSET_VALUE); } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_type_2_filter(const mss_mac_instance_t *this_mac, uint32_t filter_no, const mss_mac_type_2_filter_t *filter) { volatile uint32_t *p_reg; uint32_t limit; uint32_t temp_reg = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) /* eMAC limits are different to pMAC ones */ { p_reg = &this_mac->emac_base->SCREENING_TYPE_2_REGISTER_0; limit = MSS_MAC_EMAC_TYPE_2_SCREENERS; } else { p_reg = &this_mac->mac_base->SCREENING_TYPE_2_REGISTER_0; limit = MSS_MAC_TYPE_2_SCREENERS; } if(filter_no < limit) /* Lets go build a filter... */ { if(0u != (filter->drop_on_match)) { temp_reg = GEM_T2_DROP_ON_MATCH; } else { temp_reg = 0U; } if(0U != (filter->compare_a_enable)) { temp_reg |= GEM_COMPARE_A_ENABLE; temp_reg |= ((uint32_t)filter->compare_a_index & BITS_05) << GEM_COMPARE_A_SHIFT; } if(0U != (filter->compare_b_enable)) { temp_reg |= GEM_COMPARE_B_ENABLE; temp_reg |= ((uint32_t)filter->compare_b_index & BITS_05) << GEM_COMPARE_B_SHIFT; } if(0U != (filter->compare_c_enable)) { temp_reg |= GEM_COMPARE_C_ENABLE; temp_reg |= ((uint32_t)filter->compare_c_index & BITS_05) << GEM_COMPARE_C_SHIFT; } if(0U != (filter->ethertype_enable)) { temp_reg |= GEM_ETHERTYPE_ENABLE; temp_reg |= ((uint32_t)filter->ethertype_index & BITS_03) << GEM_ETHERTYPE_REG_INDEX_SHIFT; } if(0U != (filter->vlan_priority_enable)) { temp_reg |= GEM_VLAN_ENABLE; temp_reg |= ((uint32_t)filter->vlan_priority & BITS_03) << GEM_VLAN_PRIORITY_SHIFT; } temp_reg |= (uint32_t)filter->queue_no & GEM_QUEUE_NUMBER; p_reg[filter_no] = temp_reg; /* Set filter up at last */ } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_get_type_2_filter(const mss_mac_instance_t *this_mac, uint32_t filter_no, mss_mac_type_2_filter_t *filter) { volatile uint32_t *p_reg; uint32_t limit; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { (void)memset(filter, 0, sizeof(mss_mac_type_2_filter_t)); if(0U != this_mac->is_emac) /* eMAC limits are different to pMAC ones */ { p_reg = &this_mac->emac_base->SCREENING_TYPE_2_REGISTER_0; limit = MSS_MAC_EMAC_TYPE_2_SCREENERS; } else { p_reg = &this_mac->mac_base->SCREENING_TYPE_2_REGISTER_0; limit = MSS_MAC_TYPE_2_SCREENERS; } if(filter_no < limit) /* Lets go fetch a filter... */ { if(0U != (p_reg[filter_no] & GEM_T2_DROP_ON_MATCH)) { filter->drop_on_match = 1; } if(0U != (p_reg[filter_no] & GEM_COMPARE_A_ENABLE)) { filter->compare_a_enable = 1; } if(0U != (p_reg[filter_no] & GEM_COMPARE_B_ENABLE)) { filter->compare_b_enable = 1; } if(0U != (p_reg[filter_no] & GEM_COMPARE_C_ENABLE)) { filter->compare_c_enable = 1; } if(0U != (p_reg[filter_no] & GEM_ETHERTYPE_ENABLE)) { filter->ethertype_enable = 1; } if(0U != (p_reg[filter_no] & GEM_VLAN_ENABLE)) { filter->vlan_priority_enable = 1; } filter->compare_a_index = (uint8_t)((p_reg[filter_no] & GEM_COMPARE_A) >> GEM_COMPARE_A_SHIFT); filter->compare_b_index = (uint8_t)((p_reg[filter_no] & GEM_COMPARE_B) >> GEM_COMPARE_B_SHIFT); filter->compare_c_index = (uint8_t)((p_reg[filter_no] & GEM_COMPARE_C) >> GEM_COMPARE_C_SHIFT); filter->ethertype_index = (uint8_t)((p_reg[filter_no] & GEM_ETHERTYPE_REG_INDEX) >> GEM_ETHERTYPE_REG_INDEX_SHIFT); filter->vlan_priority = (uint8_t)((p_reg[filter_no] & GEM_VLAN_PRIORITY) >> GEM_VLAN_PRIORITY_SHIFT); filter->queue_no = (uint8_t)(p_reg[filter_no] & GEM_QUEUE_NUMBER); } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_mmsl_mode(const mss_mac_instance_t *this_mac, const mss_mac_mmsl_config_t *mmsl_cfg) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != mmsl_cfg->preemption) /* Preemption is enabled so deal with it */ { /* * Need to shut preemption down in case it is already enabled * otherwise the new settings may not be recognised properly. */ this_mac->mac_base->MMSL_CONTROL = 0U; if(0U != mmsl_cfg->verify_disable) { this_mac->mac_base->MMSL_CONTROL |= ((uint32_t)(mmsl_cfg->frag_size)) | GEM_VERIFY_DISABLE; this_mac->mac_base->MMSL_CONTROL |= GEM_PRE_ENABLE; } else { this_mac->mac_base->MMSL_CONTROL |= (uint32_t)(mmsl_cfg->frag_size); this_mac->mac_base->MMSL_CONTROL |= GEM_PRE_ENABLE; } } else /* Preemption is not enabled so see which MAC we want to use */ { if(0U != mmsl_cfg->use_pmac) { this_mac->mac_base->MMSL_CONTROL = GEM_ROUTE_RX_TO_PMAC; } else { this_mac->mac_base->MMSL_CONTROL = 0U; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_get_mmsl_mode(const mss_mac_instance_t *this_mac, mss_mac_mmsl_config_t *mmsl_cfg) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { (void)memset(mmsl_cfg, 0, sizeof(mss_mac_mmsl_config_t)); if(0U != (this_mac->mac_base->MMSL_CONTROL & GEM_ROUTE_RX_TO_PMAC)) { mmsl_cfg->use_pmac = 1U; } if(0U != (this_mac->mac_base->MMSL_CONTROL & GEM_PRE_ENABLE)) { mmsl_cfg->preemption = 1U; } if(0U != (this_mac->mac_base->MMSL_CONTROL & GEM_VERIFY_DISABLE)) { mmsl_cfg->verify_disable = 1U; } mmsl_cfg->frag_size = (mss_mac_frag_size_t)(this_mac->mac_base->MMSL_CONTROL & BITS_02); } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_start_preemption_verify(const mss_mac_instance_t *this_mac) { if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != (this_mac->mac_base->MMSL_CONTROL & GEM_PRE_ENABLE)) /* Preemption is enabled */ { this_mac->mac_base->MMSL_CONTROL |= GEM_RESTART_VER; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint32_t MSS_MAC_get_mmsl_status(const mss_mac_instance_t *this_mac) { uint32_t ret_val = 0U; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { ret_val = this_mac->mac_base->MMSL_STATUS; /* Just return raw value, user can decode using defined bits */ } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_get_mmsl_stats(const mss_mac_instance_t *this_mac, mss_mac_mmsl_stats_t *stats) { /* * We return these differently to the general statistics as they are pMAC * specific and don't have a corresponding eMAC equivalent. */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { (void)memset(stats, 0, sizeof(mss_mac_mmsl_stats_t)); stats->smd_err_count = (this_mac->mac_base->MMSL_ERR_STATS & GEM_SMD_ERR_COUNT) >> GEM_SMD_ERR_COUNT_SHIFT; stats->ass_err_count = this_mac->mac_base->MMSL_ERR_STATS & GEM_ASS_ERR_COUNT; stats->ass_ok_count = this_mac->mac_base->MMSL_ASS_OK_COUNT; stats->frag_count_rx = this_mac->mac_base->MMSL_FRAG_COUNT_RX; stats->frag_count_tx = this_mac->mac_base->MMSL_FRAG_COUNT_TX; } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_tx_cutthru(const mss_mac_instance_t *this_mac, uint32_t level) { volatile uint32_t *p_reg; uint32_t mask; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { p_reg = (0U != this_mac->is_emac) ? &this_mac->emac_base->PBUF_TXCUTTHRU : &this_mac->mac_base->PBUF_TXCUTTHRU; mask = (0U != this_mac->is_emac) ? GEM_DMA_EMAC_CUTTHRU_THRESHOLD : GEM_DMA_TX_CUTTHRU_THRESHOLD; if(0U == level) /* Disabling cutthru? */ { *p_reg = 0U; } else { *p_reg = GEM_DMA_CUTTHRU | (level & mask); } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_rx_cutthru(const mss_mac_instance_t *this_mac, uint32_t level) { volatile uint32_t *p_reg; uint32_t mask; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { p_reg = (0U != this_mac->is_emac) ? &this_mac->emac_base->PBUF_RXCUTTHRU : &this_mac->mac_base->PBUF_RXCUTTHRU; mask = (0U != this_mac->is_emac) ? GEM_DMA_EMAC_CUTTHRU_THRESHOLD : GEM_DMA_RX_CUTTHRU_THRESHOLD; if(0U == level) /* Disabling cutthru? */ { *p_reg = 0U; } else { *p_reg = GEM_DMA_CUTTHRU | (level & mask); } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint32_t MSS_MAC_get_tx_cutthru(const mss_mac_instance_t *this_mac) { uint32_t temp_reg = 0U; volatile uint32_t *p_reg; uint32_t mask; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { p_reg = (0U != this_mac->is_emac) ? &this_mac->emac_base->PBUF_TXCUTTHRU : &this_mac->mac_base->PBUF_TXCUTTHRU; mask = (0U != this_mac->is_emac) ? GEM_DMA_EMAC_CUTTHRU_THRESHOLD : GEM_DMA_TX_CUTTHRU_THRESHOLD; temp_reg = *p_reg; if(0U == (temp_reg & GEM_DMA_CUTTHRU)) { temp_reg = 0U; } else { temp_reg &= mask; } } return(temp_reg); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint32_t MSS_MAC_get_rx_cutthru(const mss_mac_instance_t *this_mac) { uint32_t temp_reg = 0U; volatile uint32_t *p_reg; uint32_t mask; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { p_reg = (0U != this_mac->is_emac) ? &this_mac->emac_base->PBUF_RXCUTTHRU : &this_mac->mac_base->PBUF_RXCUTTHRU; mask = (0U != this_mac->is_emac) ? GEM_DMA_EMAC_CUTTHRU_THRESHOLD : GEM_DMA_RX_CUTTHRU_THRESHOLD; temp_reg = *p_reg; if(0U == (temp_reg & GEM_DMA_CUTTHRU)) { temp_reg = 0U; } else { temp_reg &= mask; } } return(temp_reg); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_tx_enable(const mss_mac_instance_t *this_mac) { /* Don't do this if already done in case it has side effects... */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { if(0U == (this_mac->emac_base->NETWORK_CONTROL & GEM_ENABLE_TRANSMIT)) { this_mac->emac_base->NETWORK_CONTROL |= GEM_ENABLE_TRANSMIT; } } else { if(0U == (this_mac->mac_base->NETWORK_CONTROL & GEM_ENABLE_TRANSMIT)) { this_mac->mac_base->NETWORK_CONTROL |= GEM_ENABLE_TRANSMIT; } } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_jumbo_frames_mode(const mss_mac_instance_t *this_mac, bool state) { volatile uint32_t *p_reg = &this_mac->mac_base->NETWORK_CONFIG; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->NETWORK_CONFIG; } if(0U != this_mac->jumbo_frame_enable) /* Only look at this if the feature is enabled in config */ { if(state) { *p_reg |= GEM_JUMBO_FRAMES; } else { *p_reg &= ~GEM_JUMBO_FRAMES; } } else /* Ensure it is disabled if not allowed... */ { *p_reg &= ~GEM_JUMBO_FRAMES; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ bool MSS_MAC_get_jumbo_frames_mode(const mss_mac_instance_t *this_mac) { bool ret_val = false; volatile uint32_t *p_reg = &this_mac->mac_base->NETWORK_CONFIG; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->NETWORK_CONFIG; } ret_val = ((*p_reg & GEM_JUMBO_FRAMES) != 0U); } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_jumbo_frame_length(const mss_mac_instance_t *this_mac, uint32_t length_in) { volatile uint32_t *p_reg = &this_mac->mac_base->JUMBO_MAX_LENGTH; uint32_t length = length_in; /* Avoids warning about modifying parameter passed by value */ if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->JUMBO_MAX_LENGTH; } /* Set up maximum jumbo frame size - but bounds check first */ if(length > MSS_MAC_JUMBO_MAX) { length = MSS_MAC_JUMBO_MAX; } if(0U != this_mac->jumbo_frame_enable) /* Only look at this if the feature is enabled in config */ { *p_reg = length; } else /* Ensure it is set to reset value if not allowed... */ { *p_reg = MSS_MAC_JUMBO_MAX; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ uint32_t MSS_MAC_get_jumbo_frame_length(const mss_mac_instance_t *this_mac) { uint32_t ret_val = 0; volatile uint32_t *p_reg = &this_mac->mac_base->JUMBO_MAX_LENGTH; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->JUMBO_MAX_LENGTH; } ret_val = *p_reg; } return(ret_val); } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ void MSS_MAC_set_pause_frame_copy_to_mem(const mss_mac_instance_t *this_mac, bool state) { volatile uint32_t *p_reg = &this_mac->mac_base->NETWORK_CONFIG; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->NETWORK_CONFIG; } /* * Logic is inverted as enabling copy to memory means disabling * GEM_DISABLE_COPY_OF_PAUSE_FRAMES */ if(state) { *p_reg &= ~GEM_DISABLE_COPY_OF_PAUSE_FRAMES; } else { *p_reg |= GEM_DISABLE_COPY_OF_PAUSE_FRAMES; } } } /****************************************************************************** * See mss_ethernet_mac.h for details of how to use this function. */ bool MSS_MAC_get_pause_frame_copy_to_mem(const mss_mac_instance_t *this_mac) { bool ret_val = false; volatile uint32_t *p_reg = &this_mac->mac_base->NETWORK_CONFIG; if(MSS_MAC_AVAILABLE == this_mac->mac_available) { if(0U != this_mac->is_emac) { p_reg = &this_mac->emac_base->NETWORK_CONFIG; } /* * Logic is inverted as enabling copy to memory means disabling * GEM_DISABLE_COPY_OF_PAUSE_FRAMES */ ret_val = 0U == (*p_reg & GEM_DISABLE_COPY_OF_PAUSE_FRAMES); } return(ret_val); } /**************************************************************************/ /* Private Function definitions */ /**************************************************************************/ /****************************************************************************** * This is default "Receive packet interrupt handler. This function finds the * descriptor that received the packet and caused the interrupt. * This informs the received packet size to the application and * relinquishes the packet buffer from the associated DMA descriptor. */ static void rxpkt_handler ( mss_mac_instance_t *this_mac, uint32_t queue_no ) { mss_mac_queue_t *this_queue = &this_mac->queue[queue_no]; mss_mac_rx_desc_t * cdesc = &this_queue->rx_desc_tab[this_queue->first_rx_desc_index]; if(0U != (cdesc->addr_low & GEM_RX_DMA_USED)) /* Check in case we already got it... */ { /* Execution comes here because at-least one packet is received. */ do { uint8_t * p_rx_packet; uint32_t pckt_length; #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) uint64_t addr_temp; #else uint32_t addr_temp; #endif ++this_queue->nb_available_rx_desc; #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) addr_temp = (uint64_t)(cdesc->addr_low & ~(GEM_RX_DMA_WRAP | GEM_RX_DMA_USED | GEM_RX_DMA_TS_PRESENT)); addr_temp |= (uint64_t)cdesc->addr_high << 32; #else addr_temp = (cdesc->addr_low & ~(GEM_RX_DMA_WRAP | GEM_RX_DMA_USED | GEM_RX_DMA_TS_PRESENT)); #endif p_rx_packet = (uint8_t *)addr_temp; /* * Pass received packet up to application layer - if enabled... * * Note if rx_packet comes back as 0 we can't recover and will leave a * used packet stuck in the queue... */ if((NULL_POINTER != this_queue->pckt_rx_callback) && (NULL_POINTER != p_rx_packet) && (0U == this_mac->rx_discard)) { pckt_length = cdesc->status & (GEM_RX_DMA_BUFF_LEN | GEM_RX_DMA_JUMBO_BIT_13); this_queue->ingress += pckt_length; this_queue->pckt_rx_callback(this_mac, queue_no, p_rx_packet, pckt_length, cdesc, this_queue->rx_caller_info[this_queue->first_rx_desc_index]); } if((NULL_POINTER != p_rx_packet) && (0U != this_mac->rx_discard)) { /* * Need to return receive packet buffer to the queue as rx handler * hasn't been called to do it for us... */ (void)MSS_MAC_receive_pkt(this_mac, queue_no, p_rx_packet, this_queue->rx_caller_info[this_queue->first_rx_desc_index], MSS_MAC_INT_ENABLE); } cdesc->addr_low &= ~GEM_RX_DMA_USED; /* Mark buffer as unused again */ /* Point the curr_rx_desc to next descriptor in the ring */ /* Wrap around in case next descriptor is pointing to last in the ring */ ++this_queue->first_rx_desc_index; this_queue->first_rx_desc_index %= MSS_MAC_RX_RING_SIZE; cdesc = &this_queue->rx_desc_tab[this_queue->first_rx_desc_index]; } while(0 != (cdesc->addr_low & GEM_RX_DMA_USED)); /* loop while there are packets available */ } } /****************************************************************************** * This is default "Transmit packet interrupt handler. This function finds the * descriptor that transmitted the packet and caused the interrupt. * This relinquishes the packet buffer from the associated DMA descriptor. */ static void txpkt_handler ( mss_mac_instance_t *this_mac, uint32_t queue_no ) { #if defined(MSS_MAC_SIMPLE_TX_QUEUE) mss_mac_queue_t *this_queue = &this_mac->queue[queue_no]; /* * Simple single packet TX queue where only the one packet buffer is needed * but two descriptors are required to stop DMA engine running over itself... */ if(NULL_POINTER != this_queue->pckt_tx_callback) { this_queue->pckt_tx_callback(this_mac, queue_no, this_queue->tx_desc_tab, this_queue->tx_caller_info[0]); } this_queue->nb_available_tx_desc = MSS_MAC_TX_RING_SIZE; /* Release transmit queue... */ #else uint32_t empty_flag; uint32_t index; uint32_t completed = 0U; ASSERT(g_mac.first_tx_index != INVALID_INDEX); ASSERT(g_mac.last_tx_index != INVALID_INDEX); /* TBD PMCS multi packet tx queue not implemented yet */ index = g_mac.first_tx_index; do { ++g_mac.nb_available_tx_desc; /* Call packet Tx completion handler if it exists. */ if(NULL_POINTER != g_mac.pckt_tx_callback) { g_mac.pckt_tx_callback(g_mac.tx_desc_tab[index].caller_info); } if(index == g_mac.last_tx_index) { /* all pending tx packets sent. */ g_mac.first_tx_index = INVALID_INDEX; g_mac.last_tx_index = INVALID_INDEX; completed = 1U; } else { /* Move on to next transmit descriptor. */ ++index; index %= MSS_MAC_TX_RING_SIZE; g_mac.first_tx_index = index; /* Check if we reached a descriptor still pending tx. */ empty_flag = g_mac.tx_desc_tab[index].pkt_size & DMA_DESC_EMPTY_FLAG_MASK; if(0U == empty_flag) { completed = 1U; } } /* Clear the tx packet sent interrupt. Please note that this must be * done for every packet sent as it decrements the TXPKTCOUNT. */ set_bit_reg32(&MAC->DMA_TX_STATUS, DMA_TXPKTSENT); } while(0U == completed); #endif } /****************************************************************************** * */ static void tx_desc_ring_init(mss_mac_instance_t *this_mac) { int32_t inc; int32_t queue_no; for(queue_no = 0; queue_no < MSS_MAC_QUEUE_COUNT; queue_no++) { #if defined(MSS_MAC_USE_DDR) this_mac->queue[queue_no].tx_desc_tab = g_mss_mac_ddr_ptr; g_mss_mac_ddr_ptr += MSS_MAC_TX_RING_SIZE * sizeof(mss_mac_tx_desc_t); #endif for(inc = 0; inc < MSS_MAC_TX_RING_SIZE; ++inc) { this_mac->queue[queue_no].tx_desc_tab[inc].addr_low = 0U; #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->queue[queue_no].tx_desc_tab[inc].addr_high = 0U; #endif this_mac->queue[queue_no].tx_desc_tab[inc].status = GEM_TX_DMA_USED; } inc--; /* Step back to last buffer descriptor and mark as end of list */ this_mac->queue[queue_no].tx_desc_tab[inc].status |= GEM_TX_DMA_WRAP; } } /****************************************************************************** * */ static void rx_desc_ring_init(mss_mac_instance_t *this_mac) { uint32_t inc; int32_t queue_no; for(queue_no = 0; queue_no < MSS_MAC_QUEUE_COUNT; queue_no++) { #if defined(MSS_MAC_USE_DDR) this_mac->queue[queue_no].rx_desc_tab = g_mss_mac_ddr_ptr; g_mss_mac_ddr_ptr += MSS_MAC_RX_RING_SIZE * sizeof(mss_mac_rx_desc_t); #endif for(inc = 0U; inc < MSS_MAC_RX_RING_SIZE; ++inc) { this_mac->queue[queue_no].rx_desc_tab[inc].addr_low = 0U; /* Mark buffers as used for now in case DMA gets enabled before we attach a buffer */ #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) this_mac->queue[queue_no].rx_desc_tab[inc].addr_high = 0U; #endif this_mac->queue[queue_no].rx_desc_tab[inc].status = 0U; } inc--; /* Step back to last buffer descriptor and mark as end of list */ this_mac->queue[queue_no].rx_desc_tab[inc].addr_low |= GEM_RX_DMA_WRAP; } } /****************************************************************************** * */ static void assign_station_addr ( mss_mac_instance_t *this_mac, const uint8_t mac_addr[MSS_MAC_MAC_LEN] ) { uint32_t address32_l; uint32_t address32_h; ASSERT(NULL_POINTER != mac_addr); if((NULL_POINTER != mac_addr) && (NULL_POINTER != this_mac)) { /* Update current instance data */ (void)memcpy(this_mac->mac_addr, mac_addr, MSS_MAC_MAC_LEN); /* Assemble correct register values */ address32_l = ((uint32_t)mac_addr[3]) << 24; address32_l |= ((uint32_t)mac_addr[2]) << 16; address32_l |= ((uint32_t)mac_addr[1]) << 8; address32_l |= ((uint32_t)mac_addr[0]); address32_h = ((uint32_t)mac_addr[5]) << 8; address32_h |= ((uint32_t)mac_addr[4]); /* Update hardware registers */ if(0U != this_mac->is_emac) { this_mac->emac_base->SPEC_ADD1_BOTTOM = address32_l; this_mac->emac_base->SPEC_ADD1_TOP = address32_h; this_mac->emac_base->SPEC_ADD2_BOTTOM = 0U; this_mac->emac_base->SPEC_ADD2_TOP = 0U; this_mac->emac_base->SPEC_ADD3_BOTTOM = 0U; this_mac->emac_base->SPEC_ADD3_TOP = 0U; this_mac->emac_base->SPEC_ADD4_BOTTOM = 0U; this_mac->emac_base->SPEC_ADD4_TOP = 0U; } else { this_mac->mac_base->SPEC_ADD1_BOTTOM = address32_l; this_mac->mac_base->SPEC_ADD1_TOP = address32_h; this_mac->mac_base->SPEC_ADD2_BOTTOM = 0U; this_mac->mac_base->SPEC_ADD2_TOP = 0U; this_mac->mac_base->SPEC_ADD3_BOTTOM = 0U; this_mac->mac_base->SPEC_ADD3_TOP = 0U; this_mac->mac_base->SPEC_ADD4_BOTTOM = 0U; this_mac->mac_base->SPEC_ADD4_TOP = 0U; } } } /******************************************************************************* * Auto-detect the PHY's address by attempting to read the PHY identification * register containing the PHY manufacturer's identifier. * Attempting to read a PHY register using an incorrect PHY address will result * in a value with all bits set to one on the MDIO bus. Reading any other value * means that a PHY responded to the read request, therefore we have found the * PHY's address. * This function returns the detected PHY's address or 32 (PHY_ADDRESS_MAX + 1) * if no PHY is responding. */ static uint8_t probe_phy(const mss_mac_instance_t *this_mac) { uint8_t phy_address = PHY_ADDRESS_MIN; const uint16_t ALL_BITS_HIGH = 0xFFFFU; const uint8_t PHYREG_PHYID1R = 0x02U; /* PHY Identifier 1 register address. */ uint32_t found; do { uint16_t reg; reg = MSS_MAC_read_phy_reg(this_mac, phy_address, PHYREG_PHYID1R); if (reg != ALL_BITS_HIGH) { found = 1U; } else { found = 0U; ++phy_address; } } while ((phy_address <= PHY_ADDRESS_MAX) && (0U == found)); return phy_address; } /******************************************************************************* * MSS MAC TBI interface */ static void msgmii_init(const mss_mac_instance_t *this_mac) { if(GMII_SGMII == this_mac->interface_type) { if(0U == this_mac->is_emac) { this_mac->mac_base->PCS_CONTROL = 0x9000UL; /* Reset and enable autonegotiation */ } } if(TBI == this_mac->interface_type) { if(0U == this_mac->is_emac) { this_mac->mac_base->PCS_CONTROL = 0x9000UL; /* Reset and enable autonegotiation */ } } } /******************************************************************************* * */ static void msgmii_autonegotiate(const mss_mac_instance_t *this_mac) { uint16_t phy_reg; uint16_t autoneg_complete; uint8_t link_fullduplex; mss_mac_speed_t link_speed; uint8_t copper_link_up; volatile uint32_t sgmii_aneg_timeout = 100000U; copper_link_up = this_mac->phy_get_link_status(this_mac, &link_speed, &link_fullduplex); if(MSS_MAC_LINK_UP == copper_link_up) { /* Initiate auto-negotiation on the TBI SGMII link. */ if(TBI == this_mac->interface_type) { phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL; phy_reg |= 0x1000U; this_mac->mac_base->PCS_CONTROL = phy_reg; phy_reg |= 0x0200U; this_mac->mac_base->PCS_CONTROL = phy_reg; /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS; autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while(((0U == autoneg_complete) && (sgmii_aneg_timeout != 0U)) || (0xFFFFU == phy_reg)); } } } #if 0 /******************************************************************************* * SGMII or 1000BaseX interface with CoreSGMII */ #if (MSS_MAC_PHY_INTERFACE == SGMII) #define CORE_SGMII_PHY_ADDR MSS_MAC_INTERFACE_MDIO_ADDR /******************************************************************************* * */ static void coresgmii_init(void) { uint16_t phy_reg; /* Reset C-SGMII. */ MSS_MAC_write_phy_reg(CORE_SGMII_PHY_ADDR, 0x00U, 0x9000U); /* Register 0x04 of C-SGMII must be always be set to 0x0001. */ MSS_MAC_write_phy_reg(CORE_SGMII_PHY_ADDR, 0x04U, 0x0001U); /* Enable auto-negotiation inside CoreSGMII block. */ phy_reg = MSS_MAC_read_phy_reg(CORE_SGMII_PHY_ADDR, 0x00U); phy_reg |= 0x1000U; MSS_MAC_write_phy_reg(CORE_SGMII_PHY_ADDR, 0x00U, phy_reg); } /******************************************************************************* * */ static void coresgmii_autonegotiate(void) { uint16_t phy_reg; uint16_t autoneg_complete; volatile uint32_t sgmii_aneg_timeout = 1000000U; uint8_t link_fullduplex; mss_mac_speed_t link_speed; uint8_t copper_link_up; copper_link_up = MSS_MAC_phy_get_link_status(&link_speed, &link_fullduplex); if(MSS_MAC_LINK_UP == copper_link_up) { SYSREG->MAC_CR = (SYSREG->MAC_CR & ~MAC_CONFIG_SPEED_MASK) | link_speed; /* Configure duplex mode */ if(MSS_MAC_HALF_DUPLEX == link_fullduplex) { /* half duplex */ MAC->CFG2 &= ~CFG2_FDX_MASK; } else { /* full duplex */ MAC->CFG2 |= CFG2_FDX_MASK; } /* Initiate auto-negotiation on the SGMII link. */ phy_reg = MSS_MAC_read_phy_reg(CORE_SGMII_PHY_ADDR, 0x00U); phy_reg |= 0x1000U; MSS_MAC_write_phy_reg(CORE_SGMII_PHY_ADDR, 0x00U, phy_reg); phy_reg |= 0x0200U; MSS_MAC_write_phy_reg(CORE_SGMII_PHY_ADDR, 0x00U, phy_reg); /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = MSS_MAC_read_phy_reg(CORE_SGMII_PHY_ADDR, MII_BMSR); autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while(((0U == autoneg_complete) && (sgmii_aneg_timeout != 0U)) || (0xFFFFU == phy_reg)); } } /******************************************************************************* * Generate clock 2.5/25/125MHz for 10/100/1000Mbps using Clock Condition Circuit(CCC) */ static void coresgmii_set_link_speed(uint32_t speed) { uint16_t phy_reg; phy_reg = MSS_MAC_read_phy_reg(CORE_SGMII_PHY_ADDR, 0x11U); phy_reg |= (speed << 2); MSS_MAC_write_phy_reg(CORE_SGMII_PHY_ADDR, 0x11U, phy_reg); } #endif /* #if (MSS_MAC_PHY_INTERFACE == SGMII) */ #endif /******************************************************************************* * Setup hardware addresses etc for instance structure(s). */ static void instances_init(mss_mac_instance_t *this_mac, mss_mac_cfg_t *cfg) { #if defined(TARGET_ALOE) /* These are unused for Aloe as there is only one pMAC and no alternate * address support required */ (void)this_mac; (void)cfg; (void)memset(&g_mac0, 0, sizeof(g_mac0)); g_mac0.use_hi_address = cfg->use_hi_address; /* Not really needed but to be consistent... */ g_mac0.is_emac = 0U; g_mac0.mac_base = (MAC_TypeDef *)MSS_MAC0_BASE; g_mac0.emac_base = (eMAC_TypeDef *)MSS_MAC0_BASE; g_mac0.mac_q_int[0] = ethernet_PLIC_53; g_mac0.queue[0].int_status = &g_mac0.mac_base->INT_STATUS; g_mac0.queue[0].int_mask = &g_mac0.mac_base->INT_MASK; g_mac0.queue[0].int_enable = &g_mac0.mac_base->INT_ENABLE; g_mac0.queue[0].int_disable = &g_mac0.mac_base->INT_DISABLE; g_mac0.queue[0].receive_q_ptr = &g_mac0.mac_base->RECEIVE_Q_PTR; g_mac0.queue[0].transmit_q_ptr = &g_mac0.mac_base->TRANSMIT_Q_PTR; g_mac0.queue[0].dma_rxbuf_size = &g_mac0.mac_base->DMA_RXBUF_SIZE_Q1; /* Not really true as this is done differently for queue 0 */ #endif #if defined(TARGET_G5_SOC) (void)memset(this_mac, 0, sizeof(mss_mac_instance_t)); /* Start with blank canvas */ this_mac->use_hi_address = cfg->use_hi_address; /* Need to remember this for sanity checking */ this_mac->use_local_ints = cfg->use_local_ints; /* Need to remember this for interrupt management */ if(&g_mac0 == this_mac) { if(MSS_MAC_DISABLE == cfg->use_hi_address) { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC0_BASE; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC0_BASE; SYSREG->APBBUS_CR &= ~MSS_MAC_GEM0_ABP_BIT; } else { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC0_BASE_HI; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC0_BASE_HI; SYSREG->APBBUS_CR |= MSS_MAC_GEM0_ABP_BIT; } if(0U != this_mac->use_local_ints) { PLIC_DisableIRQ(MAC0_INT_PLIC); PLIC_DisableIRQ(MAC0_QUEUE1_PLIC); PLIC_DisableIRQ(MAC0_QUEUE2_PLIC); PLIC_DisableIRQ(MAC0_QUEUE3_PLIC); PLIC_DisableIRQ(MAC0_MMSL_PLIC); this_mac->mac_q_int[0] = MAC0_INT_U54_INT; this_mac->mac_q_int[1] = MAC0_QUEUE1_U54_INT; this_mac->mac_q_int[2] = MAC0_QUEUE2_U54_INT; this_mac->mac_q_int[3] = MAC0_QUEUE3_U54_INT; this_mac->mmsl_int = MAC0_MMSL_U54_INT; } else { __disable_local_irq(MAC0_INT_U54_INT); __disable_local_irq(MAC0_QUEUE1_U54_INT); __disable_local_irq(MAC0_QUEUE2_U54_INT); __disable_local_irq(MAC0_QUEUE3_U54_INT); __disable_local_irq(MAC0_MMSL_U54_INT); this_mac->mac_q_int[0] = MAC0_INT_PLIC; this_mac->mac_q_int[1] = MAC0_QUEUE1_PLIC; this_mac->mac_q_int[2] = MAC0_QUEUE2_PLIC; this_mac->mac_q_int[3] = MAC0_QUEUE3_PLIC; this_mac->mmsl_int = MAC0_MMSL_PLIC; } } else if(&g_mac1 == this_mac) { if(MSS_MAC_DISABLE == cfg->use_hi_address) { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC1_BASE; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC1_BASE; SYSREG->APBBUS_CR &= ~MSS_MAC_GEM1_ABP_BIT; } else { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC1_BASE_HI; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC1_BASE_HI; SYSREG->APBBUS_CR |= MSS_MAC_GEM1_ABP_BIT; } if(0U != this_mac->use_local_ints) { PLIC_DisableIRQ(MAC1_INT_PLIC); PLIC_DisableIRQ(MAC1_QUEUE1_PLIC); PLIC_DisableIRQ(MAC1_QUEUE2_PLIC); PLIC_DisableIRQ(MAC1_QUEUE3_PLIC); PLIC_DisableIRQ(MAC1_MMSL_PLIC); this_mac->mac_q_int[0] = MAC1_INT_U54_INT; this_mac->mac_q_int[1] = MAC1_QUEUE1_U54_INT; this_mac->mac_q_int[2] = MAC1_QUEUE2_U54_INT; this_mac->mac_q_int[3] = MAC1_QUEUE3_U54_INT; this_mac->mmsl_int = MAC1_MMSL_U54_INT; } else { __disable_local_irq(MAC1_INT_U54_INT); __disable_local_irq(MAC1_QUEUE1_U54_INT); __disable_local_irq(MAC1_QUEUE2_U54_INT); __disable_local_irq(MAC1_QUEUE3_U54_INT); __disable_local_irq(MAC1_MMSL_U54_INT); this_mac->mac_q_int[0] = MAC1_INT_PLIC; this_mac->mac_q_int[1] = MAC1_QUEUE1_PLIC; this_mac->mac_q_int[2] = MAC1_QUEUE2_PLIC; this_mac->mac_q_int[3] = MAC1_QUEUE3_PLIC; this_mac->mmsl_int = MAC1_MMSL_PLIC; } } else if(&g_emac0 == this_mac) { this_mac->is_emac = 1; if(NULL_POINTER != g_mac0.mac_base) /* If pMAC already configured must use same */ { cfg->use_hi_address = g_mac0.use_hi_address; } if(MSS_MAC_DISABLE == cfg->use_hi_address) { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC0_BASE; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC0_BASE; SYSREG->APBBUS_CR &= ~MSS_MAC_GEM0_ABP_BIT; } else { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC0_BASE_HI; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC0_BASE_HI; } if(0U != this_mac->use_local_ints) { PLIC_DisableIRQ(MAC0_EMAC_PLIC); this_mac->mac_q_int[0] = MAC0_EMAC_U54_INT; this_mac->mac_q_int[1] = LOCAL_INT_UNUSED; this_mac->mac_q_int[2] = LOCAL_INT_UNUSED; this_mac->mac_q_int[3] = LOCAL_INT_UNUSED; this_mac->mmsl_int = LOCAL_INT_UNUSED; } else { __disable_local_irq(MAC0_EMAC_U54_INT); this_mac->mac_q_int[0] = MAC0_EMAC_PLIC; this_mac->mac_q_int[1] = INVALID_IRQn; this_mac->mac_q_int[2] = INVALID_IRQn; this_mac->mac_q_int[3] = INVALID_IRQn; this_mac->mmsl_int = INVALID_IRQn; } } else { if(&g_emac1 == this_mac) { this_mac->is_emac = 1U; if(MSS_MAC_DISABLE == cfg->use_hi_address) { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC1_BASE; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC1_BASE; SYSREG->APBBUS_CR &= ~MSS_MAC_GEM1_ABP_BIT; } else { this_mac->mac_base = (MAC_TypeDef *)MSS_MAC1_BASE_HI; this_mac->emac_base = (eMAC_TypeDef *)MSS_EMAC1_BASE_HI; SYSREG->APBBUS_CR |= MSS_MAC_GEM1_ABP_BIT; } if(0U != this_mac->use_local_ints) { PLIC_DisableIRQ(MAC1_EMAC_PLIC); this_mac->mac_q_int[0] = MAC1_EMAC_U54_INT; this_mac->mac_q_int[1] = LOCAL_INT_UNUSED; this_mac->mac_q_int[2] = LOCAL_INT_UNUSED; this_mac->mac_q_int[3] = LOCAL_INT_UNUSED; this_mac->mmsl_int = LOCAL_INT_UNUSED; } else { __disable_local_irq(MAC1_EMAC_U54_INT); this_mac->mac_q_int[0] = MAC1_EMAC_PLIC; this_mac->mac_q_int[1] = INVALID_IRQn; this_mac->mac_q_int[2] = INVALID_IRQn; this_mac->mac_q_int[3] = INVALID_IRQn; this_mac->mmsl_int = INVALID_IRQn; } } } if(0U == this_mac->is_emac) { this_mac->queue[0].int_status = &this_mac->mac_base->INT_STATUS; this_mac->queue[1].int_status = &this_mac->mac_base->INT_Q1_STATUS; this_mac->queue[2].int_status = &this_mac->mac_base->INT_Q2_STATUS; this_mac->queue[3].int_status = &this_mac->mac_base->INT_Q3_STATUS; this_mac->queue[0].int_mask = &this_mac->mac_base->INT_MASK; this_mac->queue[1].int_mask = &this_mac->mac_base->INT_Q1_MASK; this_mac->queue[2].int_mask = &this_mac->mac_base->INT_Q2_MASK; this_mac->queue[3].int_mask = &this_mac->mac_base->INT_Q3_MASK; this_mac->queue[0].int_enable = &this_mac->mac_base->INT_ENABLE; this_mac->queue[1].int_enable = &this_mac->mac_base->INT_Q1_ENABLE; this_mac->queue[2].int_enable = &this_mac->mac_base->INT_Q2_ENABLE; this_mac->queue[3].int_enable = &this_mac->mac_base->INT_Q3_ENABLE; this_mac->queue[0].int_disable = &this_mac->mac_base->INT_DISABLE; this_mac->queue[1].int_disable = &this_mac->mac_base->INT_Q1_DISABLE; this_mac->queue[2].int_disable = &this_mac->mac_base->INT_Q2_DISABLE; this_mac->queue[3].int_disable = &this_mac->mac_base->INT_Q3_DISABLE; this_mac->queue[0].receive_q_ptr = &this_mac->mac_base->RECEIVE_Q_PTR; this_mac->queue[1].receive_q_ptr = &this_mac->mac_base->RECEIVE_Q1_PTR; this_mac->queue[2].receive_q_ptr = &this_mac->mac_base->RECEIVE_Q2_PTR; this_mac->queue[3].receive_q_ptr = &this_mac->mac_base->RECEIVE_Q3_PTR; this_mac->queue[0].transmit_q_ptr = &this_mac->mac_base->TRANSMIT_Q_PTR; this_mac->queue[1].transmit_q_ptr = &this_mac->mac_base->TRANSMIT_Q1_PTR; this_mac->queue[2].transmit_q_ptr = &this_mac->mac_base->TRANSMIT_Q2_PTR; this_mac->queue[3].transmit_q_ptr = &this_mac->mac_base->TRANSMIT_Q3_PTR; this_mac->queue[0].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q1; /* Not really true as this is done differently for queue 0 */ this_mac->queue[1].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q1; this_mac->queue[2].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q2; this_mac->queue[3].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q3; } else { this_mac->queue[0].int_status = &this_mac->emac_base->INT_STATUS; this_mac->queue[1].int_status = &this_mac->emac_base->INT_STATUS; /* Not Really correct but don't want 0 here... */ this_mac->queue[2].int_status = &this_mac->emac_base->INT_STATUS; this_mac->queue[3].int_status = &this_mac->emac_base->INT_STATUS; this_mac->queue[0].int_mask = &this_mac->emac_base->INT_MASK; this_mac->queue[1].int_mask = &this_mac->emac_base->INT_MASK; this_mac->queue[2].int_mask = &this_mac->emac_base->INT_MASK; this_mac->queue[3].int_mask = &this_mac->emac_base->INT_MASK; this_mac->queue[0].int_enable = &this_mac->emac_base->INT_ENABLE; this_mac->queue[1].int_enable = &this_mac->emac_base->INT_ENABLE; this_mac->queue[2].int_enable = &this_mac->emac_base->INT_ENABLE; this_mac->queue[3].int_enable = &this_mac->emac_base->INT_ENABLE; this_mac->queue[0].int_disable = &this_mac->emac_base->INT_DISABLE; this_mac->queue[1].int_disable = &this_mac->emac_base->INT_DISABLE; this_mac->queue[2].int_disable = &this_mac->emac_base->INT_DISABLE; this_mac->queue[3].int_disable = &this_mac->emac_base->INT_DISABLE; this_mac->queue[0].receive_q_ptr = &this_mac->emac_base->RECEIVE_Q_PTR; this_mac->queue[1].receive_q_ptr = &this_mac->emac_base->RECEIVE_Q_PTR; this_mac->queue[2].receive_q_ptr = &this_mac->emac_base->RECEIVE_Q_PTR; this_mac->queue[3].receive_q_ptr = &this_mac->emac_base->RECEIVE_Q_PTR; this_mac->queue[0].transmit_q_ptr = &this_mac->emac_base->TRANSMIT_Q_PTR; this_mac->queue[1].transmit_q_ptr = &this_mac->emac_base->TRANSMIT_Q_PTR; this_mac->queue[2].transmit_q_ptr = &this_mac->emac_base->TRANSMIT_Q_PTR; this_mac->queue[3].transmit_q_ptr = &this_mac->emac_base->TRANSMIT_Q_PTR; this_mac->queue[0].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q1; /* Not really true as this is done differently for queue 0 */ this_mac->queue[1].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q1; /* Not Really correct but don't want 0 here... */ this_mac->queue[2].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q2; this_mac->queue[3].dma_rxbuf_size = &this_mac->mac_base->DMA_RXBUF_SIZE_Q3; } #endif /* defined(TARGET_G5_SOC) */ } #ifdef __cplusplus } #endif /******************************** END OF FILE ******************************/ mss_ethernet_mac.h000066400000000000000000003540541432224323300422770ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC Microcontroller Subsystem 10/100/1000 Mbps Ethernet MAC bare * metal software driver public API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS Ethernet MAC Bare Metal Driver. @section intro_sec Introduction The PolarFire SoC Microcontroller Subsystem (MSS) includes two 10/100/1000 Mbps Ethernet MAC (GEM) hardware peripherals with a number of advanced features including: IEEE 1588 Time stamping support for PTPv1 and PTPv2. IEEE 802.1Qci Receive traffic policing. IEEE 802.1Qbb Priority based flow control. IEEE 802.1Q VLAN tagging. IEEE 802.1Qav Credit based traffic shaping. IEEE 802.1Qaz Bandwidth based transmit queueing. IEEE 802.1Qbv Time based priority queueing. IEEE 802.1CB Frame Redundancy and Elimination. IEEE 802.1AS Time stamping. IEEE 802.3br Frame pre-emption. TCP/UDP/IP Checksum offload. TCP/IP Large Send Offload. Advanced DMA system to provide high performance operation. The driver provides basic support for some of the features but more advanced use of the features will require application level support and/or modifications to the driver. The MSS Ethernet MACs supports GMII/MII and SGMII interfaces to the physical layer devices (PHY). The driver allows run time selection of interfaces and PHYs. This software driver provides a set of functions for controlling the MSS Ethernet MAC as part of a bare metal system where no operating system is available. The drivers can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of the driver. Unlike MSS MAC Ethernet device drivers from previous generations of Microsemi devices, the PolarFire SoC MSS Ethernet MAC device driver supports up to 4 MACs. Each GEM device has 1 x pMAC and 1 x eMAC, and so most driver functions now have a parameter which identifies the specific GEM device and MAC that the function should act upon. @section hw_dependencies Hardware Flow Dependencies The configuration of all features of the MSS Ethernet MAC is covered by this driver. The base address, register addresses and interrupt number assignment for the MSS Ethernet MAC are defined as constants in the PolarFire SoC HAL. You must ensure that the latest PolarFire SoC HAL is included in the project settings of the software tool chain used to build your project and that it is generated into your project. The MSS MAC supports the following selections for the PHY interface: Table 1 PHY Interface ----------------------------------------------------------------------------- | PHY | | | | InterFace | Value | Explanation | |------------|-------|------------------------------------------------------| | NULL_PHY | 1 | There is no PHY device connected. This configuration | | | | is used for testing where the GEM devices are cross | | | | connected through the fabric or via direct external | | | | links. | | | | | | MII | 2 | MSS MAC operates in MII mode and Interfaces with MII | | | | PHY directly. Maximum network speed is 100Mb. | | | | | | GMII | 4 | MSS MAC operates in GMII mode and Interfaces with | | | | GMII PHY directly. Maximum network speed is 1Gb. | | | | | | TBI | 8 | MSS MAC operates in TBI mode using the PCS interface.| | | | Maximum network speed is 1Gb. | | | | | | GMII_SGMII | 16 | MSS MAC operates in GMII mode but the interface to | | | | the PHY is through a SGMII to GMII converter. This | | | | facilitates designs based on the G5 SoC Emulation | | | | Platform. | | | | | | 1000BaseX | 32 | TBD | | | | | | SGMII | 64 | TBD | | | | | ----------------------------------------------------------------------------- @section theory_op Theory of Operation The MSS Ethernet MAC driver functions are grouped into the following categories: - Initialization and configuration - Transmit operations - Receive operations - Reading link status and statistics - Feature support Initialization and Configuration The MSS Ethernet MAC driver is initialized and configured by calling the MSS_MAC_init()function. The MSS_MAC_init() function takes as one of its parameters a pointer to a configuration data structure. This data structure contains all the configuration information required to initialize and configure the Ethernet MAC. The MSS Ethernet MAC driver provides the MSS_MAC_cfg_struct_def_init() function to initialize the configuration data structure entries to default values. It is recommended to use this function to retrieve the default configuration and then overwrite the defaults with the application specific settings such as PHY address, PHY type, interface type, allowed link speeds, link duplex mode and MAC address etc. The following functions are used as part of the initialization and configuration process: - MSS_MAC_cfg_struct_def_init() - MSS_MAC_init() Transmit Operations The MSS Ethernet MAC driver transmit operations are interrupt driven. The application must register a transmit call-back function with the driver using the MSS_MAC_set_tx_callback() function. This call-back function will be called by the MSS Ethernet MAC driver every time a packet has been sent. The application must call the MSS_MAC_send_pkt() function every time it wants to transmit a packet. The application must pass a pointer to the buffer containing the packet to send. It is the application's responsibility to manage the memory allocated to store the transmit packets. The MSS Ethernet MAC driver only requires a pointer to the instance structure for the desired MAC, a pointer to the buffer containing the packet, the queue number and the packet size. The MSS Ethernet MAC driver will call the transmit call-back function registered using the MSS_MAC_set_tx_callback() function once a packet is sent. The transmit call-back function is supplied by the application and can be used to release the memory used to store the packet that was sent. The following functions are used as part of transmit and receive operations: - MSS_MAC_send_pkt() - MSS_MAC_set_tx_callback() Receive Operations The MSS Ethernet MAC driver receive operations are interrupt driven. The application must first register a receive call-back function using the MSS_MAC_set_rx_callback() function. The application can then allocate receive buffers to the MSS Ethernet MAC driver by calling the MSS_MAC_receive_pkt() function. This function can be called multiple times to allocate more than one receive buffer. The MSS Ethernet MAC driver will then call the receive call-back whenever a packet is received into one of the receive buffers. It will hand back the receive buffer to the application for packet processing. This buffer will not be reused by the MSS Ethernet MAC driver unless it is re-allocated to the driver by a call to MSS_MAC_receive_pkt(). The following functions are used as part of transmit and receive operations: - MSS_MAC_receive_pkt() - MSS_MAC_set_rx_callback() Reading Status and Statistics The MSS Ethernet MAC driver provides the following functions to retrieve the current link status and statistics. - MSS_MAC_get_link_status() - MSS_MAC_read_stat() Feature Support The MSS Ethernet MAC driver provides the following functions to support on the fly configuration and control of various features of the MSS Ethernet MAC devices. - MSS_MAC_read_TSU() - MSS_MAC_init_TSU() - MSS_MAC_set_TSU_rx_mode() - MSS_MAC_set_TSU_tx_mode() - MSS_MAC_get_TSU_rx_mode() - MSS_MAC_get_TSU_tx_mode() - MSS_MAC_set_TSU_oss_mode() - MSS_MAC_get_TSU_oss_mode() - MSS_MAC_set_TSU_unicast_addr() - MSS_MAC_get_TSU_unicast_addr() - MSS_MAC_set_VLAN_only_mode() - MSS_MAC_get_VLAN_only_mode() - MSS_MAC_set_stacked_VLAN() - MSS_MAC_get_stacked_VLAN() - MSS_MAC_set_hash() - MSS_MAC_get_hash() - MSS_MAC_set_hash_mode() - MSS_MAC_get_hash_mode() - MSS_MAC_set_type_filter() - MSS_MAC_get_type_filter() - MSS_MAC_set_sa_filter() - MSS_MAC_get_sa_filter() - MSS_MAC_set_type_1_filter() - MSS_MAC_get_type_1_filter() - MSS_MAC_set_type_2_filter() - MSS_MAC_get_type_2_filter() - MSS_MAC_set_type_2_ethertype() - MSS_MAC_get_type_2_ethertype() - MSS_MAC_set_type_2_compare() - MSS_MAC_get_type_2_compare() - MSS_MAC_set_mmsl_mode() - MSS_MAC_get_mmsl_mode() - MSS_MAC_start_preemption_verify() - MSS_MAC_get_mmsl_status() - MSS_MAC_get_mmsl_stats() - MSS_MAC_set_tx_cutthru() - MSS_MAC_set_rx_cutthru() - MSS_MAC_get_tx_cutthru() - MSS_MAC_get_rx_cutthru() - MSS_MAC_tx_enable() - MSS_MAC_set_jumbo_frames_mode() - MSS_MAC_get_jumbo_frames_mode() - MSS_MAC_set_jumbo_frame_length() - MSS_MAC_get_jumbo_frame_length() - MSS_MAC_set_pause_frame_copy_to_mem() - MSS_MAC_get_pause_frame_copy_to_mem() *//*=========================================================================*/ #ifndef MSS_ETHERNET_MAC_H_ #define MSS_ETHERNET_MAC_H_ #include #include "drivers/mss/mss_mac/mss_ethernet_mac_types.h" #ifdef __cplusplus extern "C" { #endif /******************************************************************************* * * Length of a MAC address */ #define MSS_MAC_MAC_LEN (6) /******************************************************************************* * * State definitions */ #define MSS_MAC_DISABLE (0U) #define MSS_MAC_ENABLE (1U) /******************************************************************************* * API Function return value definitions */ #define MSS_MAC_SUCCESS MSS_MAC_ENABLE #define MSS_MAC_FAILED MSS_MAC_DISABLE /******************************************************************************** The following definitions are used with function MSS_MAC_get_link_status() to report the links status. */ #define MSS_MAC_LINK_DOWN (0U) #define MSS_MAC_LINK_UP (1U) #define MSS_MAC_HALF_DUPLEX (0U) #define MSS_MAC_FULL_DUPLEX (1U) /******************************************************************************* * Broadcast MAC address */ #define MSS_MAC_BROADCAST_MAC_ADDRESS 0xFFU,0xFFU,0xFFU,0xFFU,0xFFU,0xFFU /******************************************************************************* * Maximum MAC frame size (packet size) * * This value should be defined based on the type of packets you intend to * support. * For normal packets a value of 1518 is appropriate. * * If the receive_1536_byte_frames bit of the Network Config register is set * then the value 1536 is appropriate. This will be required if VLAN support is * used. * * If Jumbo frame support is enabled by setting the jumbo_frames bit of the * Network Config register, then a value up to 10240 bytes can be set. * * #define MSS_MAC_MAX_PACKET_SIZE 1518U * #define MSS_MAC_MAX_PACKET_SIZE 1536U * #define MSS_MAC_MAX_PACKET_SIZE 10240U * * Size bumped up to support maximum jumbo packet size of 10,240 bytes. The * value chosen should match that of the jumbo_max_length register if Jumbo * frame support is enabled. * */ #define MSS_MAC_JUMBO_MAX (10240U) /* Maximum the hardware supports */ #if defined(MSS_MAC_USE_DDR) #if MSS_MAC_USE_DDR == MSS_MAC_MEM_DDR #define MSS_MAC_MAX_PACKET_SIZE MSS_MAC_JUMBO_MAX /* Smaller for Crypto and FIC tests */ #else #define MSS_MAC_MAX_PACKET_SIZE (80U) #endif #else #if (MSS_MAC_QUEUE_COUNT >= 2) #define MSS_MAC_MAX_PACKET_SIZE MSS_MAC_JUMBO_MAX #else #define MSS_MAC_MAX_PACKET_SIZE MSS_MAC_JUMBO_MAX #endif #endif /* * Calculate the RX Buffer size field value automatically by rounding up to * nearest 64 bytes and dividing by 64. */ #define MSS_MAC_RX_BUF_VALUE ((MSS_MAC_MAX_PACKET_SIZE + 63U) / 64U) /***************************************************************************//** The definition below is provided to specify that the MSS_MAC_init() function should attempt to discover the address of the PHY connected to the MACs management interface.It can be used with mss_mac_cfg_t configuration parameter phy_addr and mss_mac_cfg_t as a parameter to a call to the MSS_MAC_init() function. Note: To auto detect the PHY address, this drivers scans the valid MDIO addresses starting from 0 looking for valid data. This should not be done if more than 1 device is connected to the MDIO interface. */ #define MSS_MAC_AUTO_DETECT_PHY_ADDRESS ((uint8_t)255U) /******************************************************************************* * Transmit and receive packet buffer sizes. * * The odd addition/division/multiplication sequence is to ensure the size is * a multiple of 64 bits so that sequential buffers are 64 bit word aligned * in case we are using time stamp support... * */ #define MSS_MAC_MAX_TX_BUF_SIZE (((MSS_MAC_MAX_PACKET_SIZE + 7U) / 8U) * 8U) #define MSS_MAC_MAX_RX_BUF_SIZE (((MSS_MAC_MAX_PACKET_SIZE + 7U) / 8U) * 8U) /******************************************************************************* * Defines for configuration parameters */ /* Queue enable / disable - Queue 0 is always enabled */ #define MSS_MAC_QUEUE_ENABLE MSS_MAC_ENABLE #define MSS_MAC_QUEUE_DISABLE MSS_MAC_DISABLE /* FIFO error detection & correction enable / disable */ #define MSS_MAC_ERR_DET_CORR_ENABLE MSS_MAC_ENABLE #define MSS_MAC_ERR_DET_CORR_DISABLE MSS_MAC_DISABLE /* Jumbo frame support enable / disable * Note: this enables support for the feature but the reception of jumbo frames * still needs to be explicitly enabled via MSS_MAC_set_jumbo_frames_mode() */ #define MSS_MAC_JUMBO_FRAME_ENABLE MSS_MAC_ENABLE #define MSS_MAC_JUMBO_FRAME_DISABLE MSS_MAC_DISABLE /* Length field checking enable / disable */ #define MSS_MAC_LENGTH_FIELD_CHECK_ENABLE MSS_MAC_ENABLE #define MSS_MAC_LENGTH_FIELD_CHECK_DISABLE MSS_MAC_DISABLE /* Append CRC enable / disable */ #define MSS_MAC_CRC_ENABLE MSS_MAC_ENABLE #define MSS_MAC_CRC_DISABLE MSS_MAC_DISABLE /* Fullduplex mode enable / disable */ #define MSS_MAC_FULLDUPLEX_ENABLE MSS_MAC_ENABLE #define MSS_MAC_FULLDUPLEX_DISABLE MSS_MAC_DISABLE /* Loopback mode enable / disable */ #define MSS_MAC_LOOPBACK_ENABLE MSS_MAC_ENABLE #define MSS_MAC_LOOPBACK_DISABLE MSS_MAC_DISABLE /* Receiver flow control enable / disable */ #define MSS_MAC_RX_FLOW_CTRL_ENABLE MSS_MAC_ENABLE #define MSS_MAC_RX_FLOW_CTRL_DISABLE MSS_MAC_DISABLE /* Transmission flow control enable / disable */ #define MSS_MAC_TX_FLOW_CTRL_ENABLE MSS_MAC_ENABLE #define MSS_MAC_TX_FLOW_CTRL_DISABLE MSS_MAC_DISABLE /* IPG/IFG values */ #define MSS_MAC_IPG_DEFVAL (0x00U) /* PHY clock divider values */ #define MSS_MAC_BY8_PHY_CLK (0U) #define MSS_MAC_BY16_PHY_CLK (1U) #define MSS_MAC_BY32_PHY_CLK (2U) #define MSS_MAC_BY48_PHY_CLK (3U) #define MSS_MAC_BY64_PHY_CLK (4U) #define MSS_MAC_BY96_PHY_CLK (5U) #define MSS_MAC_BY128_PHY_CLK (6U) #define MSS_MAC_BY224_PHY_CLK (7U) #if defined(TARGET_ALOE) #define MSS_MAC_DEF_PHY_CLK MSS_MAC_BY224_PHY_CLK /* Good for up to 540MHz */ #else #define MSS_MAC_DEF_PHY_CLK MSS_MAC_BY32_PHY_CLK /* Good for up to 80MHz */ #endif /* Default & Maximum PHY addresses */ #define MSS_MAC_DEFAULT_PHY ( DP83848 ) #define MSS_MAC_PHYADDR_MAXVAL ( (uint8_t)(0x1FU) ) #define MSS_MAC_PHYREGADDR_MAXVAL ( (uint8_t)(0x1FU) ) #define MSS_MAC_PHY_ADDR_DEFVAL ( (uint8_t)(0x00U) ) #define MSS_MAC_PHYREGADDR_DEFVAL ( (uint8_t)(0x00U) ) /* Maximum frame length default & maximum values */ #define MSS_MAC_MAXFRAMELEN_DEFVAL ( (uint16_t)(0x0600U) ) #define MSS_MAC_MAXFRAMELEN_MAXVAL ( (uint16_t)(0x0600U) ) /* * Options for speed configuration. */ #define MSS_MAC_ANEG_10M_FD (0x00000001U) #define MSS_MAC_ANEG_10M_HD (0x00000002U) #define MSS_MAC_ANEG_100M_FD (0x00000004U) #define MSS_MAC_ANEG_100M_HD (0x00000008U) #define MSS_MAC_ANEG_1000M_FD (0x00000010U) #define MSS_MAC_ANEG_1000M_HD (0x00000020U) #define MSS_MAC_ANEG_ALL_SPEEDS (MSS_MAC_ANEG_10M_FD | MSS_MAC_ANEG_10M_HD | \ MSS_MAC_ANEG_100M_FD | MSS_MAC_ANEG_100M_HD | \ MSS_MAC_ANEG_1000M_FD | MSS_MAC_ANEG_1000M_HD) #if defined(TARGET_G5_SOC) extern mss_mac_instance_t g_mac0; extern mss_mac_instance_t g_mac1; extern mss_mac_instance_t g_emac0; extern mss_mac_instance_t g_emac1; #endif #if defined(TARGET_ALOE) extern mss_mac_instance_t g_mac0; #endif /* Support for testing access to different memory areas */ #if defined(MSS_MAC_USE_DDR) extern uint8_t *g_mss_mac_ddr_ptr; #endif /* * Specific Address Filter support definitions. * * These may be or'ed together to construct the control value for the * MSS_MAC_set_sa_filter() function. */ #define MSS_MAC_SA_FILTER_SOURCE (0x0001U) #define MSS_MAC_SA_FILTER_BYTE0 (0x0100U) #define MSS_MAC_SA_FILTER_BYTE1 (0x0200U) #define MSS_MAC_SA_FILTER_BYTE2 (0x0400U) #define MSS_MAC_SA_FILTER_BYTE3 (0x0800U) #define MSS_MAC_SA_FILTER_BYTE4 (0x1000U) #define MSS_MAC_SA_FILTER_BYTE5 (0x2000U) #define MSS_MAC_SA_FILTER_DISABLE (0xFFFFU) /* Use this to signal we should disable filter */ /* * Type 2 Filter support definitions. */ #define MSS_MAC_T2_OFFSET_FRAME (0U) #define MSS_MAC_T2_OFFSET_ETHERTYPE (1U) #define MSS_MAC_T2_OFFSET_IP (2U) #define MSS_MAC_T2_OFFSET_TCP_UDP (3U) /**************************************************************************/ /* Public Function declarations */ /**************************************************************************/ /***************************************************************************//** The MSS_MAC_cfg_struct_def_init() function initializes a mss_mac_cfg_t configuration data structure to default values. The default configuration uses the NULL_PHY interface connected to a PHY at address 0x00 which is set to auto-negotiate at all available speeds up to 1000Mbps. This default configuration can then be used as parameter to MSS_MAC_init(). Typically, the default configuration would be modified to suit the application before being passed to MSS_MAC_init(). @param cfg This parameter is a pointer to an mss_mac_cfg_t data structure that will be used as parameter to function MSS_MAC_init(). @return This function does not return a value. Example: The example below demonstrates the use of the MSS_MAC_cfg_struct_def_init() function. It retrieves the default MAC configuration and modifies it to connect through a VSC8757 SGMII Ethernet PHY at MII management interface address 0x01. This example also demonstrates how to assign the device's MAC address and force a 100Mbps full duplex link. @code mss_mac_cfg_t mac_config; MSS_MAC_cfg_struct_def_init(&mac_config); mac_config.interface_type = TBI; config.phy_type = MSS_MAC_DEV_PHY_VSC8575; config.phy_get_link_status = MSS_MAC_VSC8575_phy_get_link_status; config.phy_init = MSS_MAC_VSC8575_phy_init; config.phy_set_link_speed = MSS_MAC_VSC8575_phy_set_link_speed; config.phy_extended_read = NULL_ti_read_extended_regs; config.phy_extended_write = NULL_ti_write_extended_regs; mac_config.phy_addr = 0x01; mac_config.speed_duplex_select = MSS_MAC_ANEG_100M_FD; mac_config.mac_addr[0] = 0xC0u; mac_config.mac_addr[1] = 0xB1u; mac_config.mac_addr[2] = 0x3Cu; mac_config.mac_addr[3] = 0x88u; mac_config.mac_addr[4] = 0x88u; mac_config.mac_addr[5] = 0x88u; MSS_MAC_init(&g_mac0, &mac_config); @endcode */ void MSS_MAC_cfg_struct_def_init ( mss_mac_cfg_t * cfg ); /***************************************************************************//** The MSS_MAC_init() function initializes the Ethernet MAC hardware and driver internal data structures. In addition to the MAC identifier, the MSS_MAC_init() function takes a pointer to a configuration data structure of type mss_mac_cfg_t as parameter. This configuration data structure contains all the information required to configure the Ethernet MAC. The MSS_MAC_init() function initializes the descriptor rings and their pointers to initial values. The MSS_MAC_init() function enables DMA Rx packet received and Tx packet sent interrupts. The configuration passed to the MSS_MAC_init() function specifies the type of interface used to connect the Ethernet MAC and Ethernet PHY as well as the PHY type and PHY MII management interface address. It also specifies the allowed link speed and duplex mode. It is at this point that the application chooses if the link speed and duplex mode will be auto-negotiated with the link partner or forced to a specific speed and duplex mode. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param cfg This parameter is a pointer to a data structure of type mss_mac_cfg_t containing the Ethernet MAC's requested configuration. You must initialize this data structure by first calling the MSS_MAC_cfg_struct_def_init() function to fill the configuration data structure with default values. You can then overwrite some of the default settings with the ones specific to your application before passing this data structure as parameter to the call to the MSS_MAC_init() function. You must at a minimum overwrite the mac_addr[6] array of the configuration data structure to contain a unique value used as the device's MAC address. @return This function does not return a value. Example: @code mss_mac_cfg_t cfg; MSS_MAC_cfg_struct_def_init(&cfg); cfg.mac_addr[0] = 0xC0u; cfg.mac_addr[1] = 0xB1u; cfg.mac_addr[2] = 0x3Cu; cfg.mac_addr[3] = 0x88u; cfg.mac_addr[4] = 0x88u; cfg.mac_addr[5] = 0x88u; MSS_MAC_init(&g_mac0, &cfg); @endcode */ void MSS_MAC_init ( mss_mac_instance_t *this_mac, mss_mac_cfg_t * cfg ); /***************************************************************************//** The MSS_MAC_update_hw_address() function updates the MAC address for the Ethernet MAC. In addition to the MAC identifier, the MSS_MAC_update_hw_address() function takes a pointer to a configuration data structure of type mss_mac_cfg_t as parameter. This configuration data structure contains all the information required to configure the Ethernet MAC including the required MAC address. The MSS_MAC_update_hw_address() function reconfigures the Ethernet MAC using the MAC address contained in the structure pointed to by cfg. This function should only be called after the MSS MAC has been initialized as it does not perform any other initialization/configuration. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param cfg This parameter is a pointer to a data structure of type mss_mac_cfg_t containing the Ethernet MAC's requested configuration. For this function, the only field of importance is the mac_addr array - all other fields are ignored. @return This function does not return a value. Example: @code mss_mac_cfg_t cfg; MSS_MAC_cfg_struct_def_init(&cfg); cfg.mac_addr[0] = 0xC0u; cfg.mac_addr[1] = 0xB1u; cfg.mac_addr[2] = 0x3Cu; cfg.mac_addr[3] = 0x88u; cfg.mac_addr[4] = 0x88u; cfg.mac_addr[5] = 0x88u; MSS_MAC_init(&g_mac_0, &cfg); .... cfg.mac_addr[0] = 0xC0u; cfg.mac_addr[1] = 0xB1u; cfg.mac_addr[2] = 0x3Cu; cfg.mac_addr[3] = 0x88u; cfg.mac_addr[4] = 0x88u; cfg.mac_addr[5] = 0x89u; MSS_MAC_update_hw_address(&g_mac0, &cfg); @endcode */ void MSS_MAC_update_hw_address ( mss_mac_instance_t *this_mac, const mss_mac_cfg_t * cfg ); /***************************************************************************//** The MSS_MAC_set_tx_callback() function registers the function that will be called by the Ethernet MAC driver when a packet has been sent on the specified queue. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param queue_no This parameter identifies the queue which this callback function will service. For single queue devices, this should be set to 0 for compatibility purposes. @param tx_complete_handler This parameter is a pointer to the function that will be called when a packet is sent by the Ethernet MAC on the selected queue. @return This function does not return a value. */ void MSS_MAC_set_tx_callback ( mss_mac_instance_t *this_mac, uint32_t queue_no, mss_mac_transmit_callback_t tx_complete_handler ); /***************************************************************************//** The MSS_MAC_set_rx_callback() function registers the function that will be called by the Ethernet MAC driver when a packet is received. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param queue_no This parameter identifies the queue which this callback function will service. For single queue devices this should be set to 0 for compatibility purposes. @param rx_callback This parameter is a pointer to the function that will be called when the a packet is received by Ethernet MAC on the selected queue. Example: The example below demonstrates the use of the MSS_MAC_set_rx_callback() function. The init() function calls the MSS_MAC_set_rx_callback() function to register the rx_callback() receive callback function with the Ethernet MAC driver. The MSS_MAC_receive_pkt() function is then called to assign the rx_buffer to an Ethernet MAC descriptor for packet reception. The rx_callback function will be called by the Ethernet MAC driver once a packet has been received into rx_buffer. The rx_callback() function calls the process_rx_packet() application function to process the received packet then calls MSS_MAC_receive_pkt() to reallocate rx_buffer to receive another packet. The rx_callback() function will be called again every time a packet is received to process the received packet and reallocate rx_buffer for packet reception. @code uint8_t rx_buffer[MSS_MAC_MAX_RX_BUF_SIZE]; void rx_callback ( void *this_mac, uint32_t queue_no, uint8_t * p_rx_packet, uint32_t pckt_length, mss_mac_rx_desc_t *cdesc, void * caller_info ) { process_rx_packet(p_rx_packet, pckt_length); MSS_MAC_receive_pkt((mss_mac_instance_t *)this_mac, queue_no, p_rx_packet, caller_info, MSS_MAC_INT_ENABLE); } void init(void) { MSS_MAC_set_rx_callback(rx_callback); MSS_MAC_receive_pkt(&g_mac0, 0, rx_buffer, (void *)0, MSS_MAC_INT_ARM); } @endcode */ void MSS_MAC_set_rx_callback ( mss_mac_instance_t *this_mac, uint32_t queue_no, mss_mac_receive_callback_t rx_callback ); /***************************************************************************//** The MSS_MAC_send_pkt() function initiates the transmission of a packet. It places the buffer containing the packet to send into one of the Ethernet MAC's transmit descriptors. This function is non-blocking. It will return immediately without waiting for the packet to be sent. The Ethernet MAC driver indicates that the packet is sent by calling the transmit completion handler registered by a call to MSS_MAC_set_tx_callback(). @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param queue_no This parameter identifies the queue to which this transmit operation applies. For single queue devices this should be set to 0 for compatibility purposes. @param tx_buffer This parameter is a pointer to the buffer containing the packet to send. @param tx_length This parameter specifies the length in bytes of the packet to send. @param p_user_data This parameter is a pointer to an optional application defined data structure. Its usage is left to the application. It is intended to help the application manage memory allocated to store packets. The Ethernet MAC driver does not make use of this pointer. The Ethernet MAC driver will pass back this pointer to the application as part of the call to the transmit completion handler registered by the application. @return This function returns 1 on successfully assigning the packet to a transmit descriptor. It returns 0 otherwise. Example: This example demonstrates the use of the MSS_MAC_send_pkt() function. The application registers the tx_complete_callback() transmit completion callback function with the Ethernet MAC driver by a call to MSS_MAC_set_tx_callback(). The application dynamically allocates memory for an application defined packet_t data structure, builds a packet and calls send_packet(). The send_packet() function extracts the pointer to the buffer containing the data to transmit and its length from the tx_packet data structure and passes these to MSS_MAC_send_pkt(). It also passes the pointer to tx_packet as the p_user_data parameter. The Ethernet MAC driver calls tx_complete_callback() once the packet is sent. The tx_complete_callback() function uses p_user_data, which points to tx_packet, to release memory allocated by the application to store the transmit packet. @code void tx_complete_handler(void *this_mac, uint32_t queue_no, mss_mac_tx_desc_t *cdesc, void * caller_info); void init(void) { MSS_MAC_set_tx_callback(tx_complete_handler); } void tx_complete_handler(void *this_mac, uint32_t queue_no, mss_mac_tx_desc_t *cdesc, void * caller_info) { release_packet_memory(caller_info); } void send_packet(app_packet_t * packet) { MSS_MAC_send_pkt(packet->buffer, packet->length, packet); } @endcode */ uint8_t MSS_MAC_send_pkt ( mss_mac_instance_t *this_mac, uint32_t queue_no, uint8_t const * tx_buffer, uint32_t tx_length, void * p_user_data ); /***************************************************************************//** The MSS_MAC_receive_pkt() function assigns a buffer to one of the Ethernet MAC's receive descriptors. The receive buffer specified as parameter will be used to receive one single packet. The receive buffer will be handed back to the application via a call to the receive callback function assigned through a call to MSS_MAC_set_rx_callback(). The MSS_MAC_receive_pkt() function will need to be called again pointing to the same buffer if more packets are to be received into this same buffer after the packet has been processed by the application. The MSS_MAC_receive_pkt() function is non-blocking. It will return immediately and does not wait for a packet to be received. The application needs to implement a receive callback function to be notified that a packet has been received. The p_user_data parameter can be optionally used to point to a memory management data structure managed by the application. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param queue_no This parameter identifies the queue to which this transmit operation applies. For single queue devices this should be set to 0 for compatibility purposes. @param rx_pkt_buffer This parameter is a pointer to a memory buffer. It points to the memory that will be assigned to one of the Ethernet MAC's receive descriptors. It must point to a buffer large enough to contain the largest possible packet. @param p_user_data This parameter is intended to help the application manage memory. Its usage is left to the application. The Ethernet MAC driver does not make use of this pointer. The Ethernet MAC driver will pass this pointer back to the application as part of the call to the application's receive callback function to help the application associate the received packet with the memory it allocated prior to the call to MSS_MAC_receive_pkt(). @param enable This parameter controls the enabling of the Ethernet MAC interrupt. If set to MSS_MAC_INT_DISABLE, the interrupt is left disabled by this function. If set to MSS_MAC_INT_ENABLE, the interrupt is enabled on return from this function. This allows a series of packet buffers to be assigned without there being any modifications to the internal packet buffer tables. To achieve this, enable should be MSS_MAC_INT_DISABLE for all but the last call to the function. When allocating a chain of buffers, the last call to MSS_MAC_send_pkt() should use a value of MSS_MAC_INT_ARM to set up the RX interrupt for the first time. @return This function returns 1 on successfully assigning the buffer to a receive descriptor. It returns 0 otherwise. Example: The example below demonstrates the use of the MSS_MAC_receive_pkt() function to handle packet reception using two receive buffers. The init() function calls the MSS_MAC_set_rx_callback() function to register the rx_callback() receive callback function with the Ethernet MAC driver. The MSS_MAC_receive_pkt() function is then called twice to assign rx_buffer_1 and rx_buffer_2 to Ethernet MAC descriptors for packet reception. The rx_callback function will be called by the Ethernet MAC driver once a packet has been received into one of the receive buffers. The rx_callback() function calls the process_rx_packet() application function to process the received packet then calls MSS_MAC_receive_pkt() to reallocate the receive buffer to receive another packet. The rx_callback() function will be called again every time a packet is received to process the received packet and reallocate rx_buffer for packet reception. Please note the use of the p_user_data parameter to handle the buffer reassignment to the Ethernet MAC as part of the rx_callback() function. This is a simplistic use of p_user_data. It is more likely that p_user_data would be useful to keep track of a pointer to a TCP/IP stack packet container data structure dynamically allocated. In this more complex use case, the first parameter of MSS_MAC_receive_pkt() would point to the actual receive buffer and the second parameter would point to a data structure used to free the receive buffer memory once the packet has been consumed by the TCP/IP stack. @code uint8_t rx_buffer_1[MSS_MAC_MAX_RX_BUF_SIZE]; uint8_t rx_buffer_2[MSS_MAC_MAX_RX_BUF_SIZE]; void rx_callback ( void *this_mac, uint32_t queue_no, uint8_t * p_rx_packet, uint32_t pckt_length, mss_mac_rx_desc_t *cdesc, void * caller_info ) { process_rx_packet(p_rx_packet, pckt_length); MSS_MAC_receive_pkt((mss_mac_instance_t *)this_mac, queue_no, p_rx_packet, caller_info, MSS_MAC_INT_ENABLE); } void init(void) { MSS_MAC_set_rx_callback(&g_mac_0, 0, rx_callback); MSS_MAC_receive_pkt(&g_mac_0, 0, rx_buffer_1, (void *)rx_buffer_1, MSS_MAC_INT_DISABLE); MSS_MAC_receive_pkt(&g_mac_0, 0, rx_buffer_2, (void *)rx_buffer_2, MSS_MAC_INT_ARM); } @endcode */ uint8_t MSS_MAC_receive_pkt ( mss_mac_instance_t *this_mac, uint32_t queue_no, uint8_t * rx_pkt_buffer, void * p_user_data, mss_mac_rx_int_ctrl_t enable ); /***************************************************************************//** The MSS_MAC_get_link_status () function retrieves the status of the link from the Ethernet PHY. It returns the current state of the Ethernet link. The speed and duplex mode of the link is also returned via the two pointers passed as parameter if the link is up. This function also adjusts the Ethernet MAC's internal configuration if some of the link characteristics have changed since the previous call to this function. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param speed This parameter is a pointer to variable of type mss_mac_speed_t where the current link speed will be stored if the link is up. This variable is not updated if the link is down. This parameter can be set to zero if the caller does not need to find out the link speed. @param fullduplex This parameter is a pointer to an unsigned character where the current link duplex mode will be stored if the link is up. This variable is not updated if the link is down. @return This function returns 1 if the link is up. It returns 0 if the link is down. Example: @code uint8_t link_up; mss_mac_speed_t speed; uint8_t full_duplex link_up = MSS_MAC_get_link_status(&gmac_0, &speed, &full_duplex); @endcode */ uint8_t MSS_MAC_get_link_status ( const mss_mac_instance_t *this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ); /***************************************************************************//** The MSS_MAC_read_stat() function reads the transmit and receive statistics of the selected Ethernet MAC. This function can be used to read one of 26 receive statistics and 20 transmitter statistics as defined in the mss_mac_stat_t enumeration. Reading a statistics value automatically zeroes the associated statistics count register. If a statistics counter reaches its maximum value, it will not roll over to 0 so it is important to collect the statistics regularly if you wish to keep an accurate account of the statistics. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param stat This parameter of type mss_mac_stat_t identifies the statistic that will be read. @return This function returns the value of the requested statistic. Example: @code uint32_t tx_pkts_cnt = MSS_MAC_read_stat(FRAMES_TXED_OK); @endcode */ uint32_t MSS_MAC_read_stat ( const mss_mac_instance_t *this_mac, mss_mac_stat_t stat ); /***************************************************************************//** @brief MSS_MAC_clear_statistics() The MSS_MAC_clear_statistics() function clears all the statistics counter registers for the selected MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function does not return a value. */ void MSS_MAC_clear_statistics ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_read_phy_reg() function reads the Ethernet PHY register specified as parameter. It uses the MII management interface to communicate with the Ethernet PHY. This function is used by the Ethernet PHY drivers provided alongside the Ethernet MAC driver. You only need to use this function if writing your own Ethernet PHY driver. This function always accesses the pMAC registers as the same PHY is shared by both eMAC and pMAC and only has an MDIO connection to the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param phyaddr This parameter is the 5-bit address of the Ethernet PHY on the MII management interface. This address is typically defined through Ethernet PHY hardware configuration signals. Please refer to the Ethernet PHY's datasheet for details of how this address is assigned. @param regaddr This parameter is the address of the Ethernet PHY register to be read. This address is the offset of the register within the Ethernet PHY's register map. @return This function returns the 16-bit value of the requested register. Example: @code #include "phy.h" uint16_t read_phy_status(uint8_t phy_addr) { uint16_t phy_status = MSS_MAC_read_phy_reg(&g_mac0, phy_addr, MII_BMSR); return phy_status; } @endcode */ uint16_t MSS_MAC_read_phy_reg ( const mss_mac_instance_t *this_mac, uint8_t phyaddr, uint8_t regaddr ); /***************************************************************************//** The MSS_MAC_write_phy_reg() function writes a 16-bit value to the specified Ethernet PHY register. It uses the MII management interface to communicate with the Ethernet PHY. This function is used by the Ethernet PHY drivers provided alongside the Ethernet MAC driver. You only need to use this function if writing your own Ethernet PHY driver. This function always accesses the pMAC registers as the same PHY is shared by both eMAC and pMAC and only has an MDIO connection to the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param phyaddr This parameter is the 5-bit address of the Ethernet PHY on the MII management interface. This address is typically defined through Ethernet PHY hardware configuration signals. Please refer to the Ethernet PHY's datasheet for details of how this address is assigned. @param regaddr This parameter is the address of the Ethernet register that will be written to. This address is the offset of the register within the Ethernet PHY's register map. @param regval The parameter is the 16-bit value that will be written into the specified PHY register. @return This function does not return a value. Example: @code #include "mss_ethernet_sgmii_phy.h" #include "phy.h" void reset_sgmii_phy(void) { MSS_MAC_write_phy_reg(&g_mac0, SGMII_PHY_ADDR, MII_BMCR, 0x8000); } @endcode */ void MSS_MAC_write_phy_reg ( const mss_mac_instance_t *this_mac, uint8_t phyaddr, uint8_t regaddr, uint16_t regval ); /***************************************************************************//** The MSS_MAC_init_TSU() function configures the Time Stamp Unit (TSU) for operation and sets the initial count value. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param tsu_cfg this parameter is a pointer to an mss_mac_tsu_config_t structure which the application uses to set the initial timer value and the nanosecond and sub-nanosecond increment values to ensure the counter increments at the desired rate. @return This function does not return a value. Example: This example illustrates configuring the TSU for operation with a 125MHz clock (8nS increment). It also configures the time stamping operation for the Ethernet MAC to collect the times tamps for received and transmitted PTP packets without modifying outgoing PTP packets. The ingress and egress unicast PTP addresses to recognize are set to 10.1.1.2 and 10.1.1.3 respectively and at a later stage the current TSU count is retrieved and displayed. @code #include "mss_ethernet_mac.h" void init_ts(void) { mss_mac_tsu_config_t tsu_cfg; tsu_cfg.nanoseconds = 0; tsu_cfg.secs_lsb = 0; tsu_cfg.secs_msb = 0; tsu_cfg.ns_inc = 8; tsu_cfg.sub_ns_inc = 0; MSS_MAC_init_TSU(&g_mac0, &tsu_cfg); MSS_MAC_set_TSU_rx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_tx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_oss_mode(&g_mac0, MSS_MAC_OSS_MODE_DISABLED); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_RX, 0x0A010102); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_TX, 0x0A010103); ... MSS_MAC_read_TSU(&g_mac0, &tsu_val); printf("TSU = %u, %u, %u\n\r", tsu_val.secs_msb, tsu_val.secs_lsb, tsu_val.nanoseconds); } @endcode */ void MSS_MAC_init_TSU ( const mss_mac_instance_t *this_mac, const mss_mac_tsu_config_t *tsu_cfg ); /***************************************************************************//** The MSS_MAC_MSS_MAC_read_TSU() function reads the current timer value from the TSU. A strict order of reading and a check for nanoseconds overflow is used to ensure the time is read correctly. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param tsu_time This parameter is a pointer to an mss_mac_tsu_time_t structure which the driver populates with the current counter value from the TSU. @return This function does not return a value. Example: This example illustrates configuring the TSU for operation with a 125MHz clock (8nS increment). It also configures the time stamping operation for the Ethernet MAC to collect the time stamps for received and transmitted PTP packets without modifying outgoing PTP packets. The ingress and egress unicast PTP addresses to recognize are set to 10.1.1.2 and 10.1.1.3 respectively and at a later stage the current TSU count is retrieved and displayed. @code #include "mss_ethernet_mac.h" void init_ts(void) { mss_mac_tsu_config_t tsu_cfg; tsu_cfg.nanoseconds = 0; tsu_cfg.secs_lsb = 0; tsu_cfg.secs_msb = 0; tsu_cfg.ns_inc = 8; tsu_cfg.sub_ns_inc = 0; MSS_MAC_init_TSU(&g_mac0, &tsu_cfg); MSS_MAC_set_TSU_rx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_tx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_oss_mode(&g_mac0, MSS_MAC_OSS_MODE_DISABLED); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_RX, 0x0A010102); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_TX, 0x0A010103); ... MSS_MAC_read_TSU(&g_mac0, &tsu_val); printf("TSU = %u, %u, %u\n\r", tsu_val.secs_msb, tsu_val.secs_lsb, tsu_val.nanoseconds); } @endcode */ void MSS_MAC_read_TSU ( const mss_mac_instance_t *this_mac, mss_mac_tsu_time_t *tsu_time ); /***************************************************************************//** The MSS_MAC_set_TSU_rx_mode() function configures time stamp recording for received packets. This allows recording the TSU value for received packets in the DMA descriptor for different types of packet. The receive packet callback function can retrieve the packet time stamp from the DMA descriptor for processing by the application. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param tsu_mode This parameter selects which types of packet have their time stamp recorded. The available options allow for none, PTP event packets, all PTP packets and all packets. @return This function does not return a value. Example: This example illustrates configuring the TSU for operation with a 125MHz clock (8nS increment). It also configures the time stamping operation for the Ethernet MAC to collect the time stamps for received and transmitted PTP packets without modifying outgoing PTP packets. The ingress and egress unicast PTP addresses to recognize are set to 10.1.1.2 and 10.1.1.3 respectively and at a later stage the current TSU count is retrieved and displayed. @code #include "mss_ethernet_mac.h" void init_ts(void) { mss_mac_tsu_config_t tsu_cfg; tsu_cfg.nanoseconds = 0; tsu_cfg.secs_lsb = 0; tsu_cfg.secs_msb = 0; tsu_cfg.ns_inc = 8; tsu_cfg.sub_ns_inc = 0; MSS_MAC_init_TSU(&g_mac0, &tsu_cfg); MSS_MAC_set_TSU_rx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_tx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_oss_mode(&g_mac0, MSS_MAC_OSS_MODE_DISABLED); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_RX, 0x0A010102); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_TX, 0x0A010103); ... MSS_MAC_read_TSU(&g_mac0, &tsu_val); printf("TSU = %u, %u, %u\n\r", tsu_val.secs_msb, tsu_val.secs_lsb, tsu_val.nanoseconds); } @endcode */ void MSS_MAC_set_TSU_rx_mode ( const mss_mac_instance_t *this_mac, mss_mac_tsu_mode_t tsu_mode ); /***************************************************************************//** The MSS_MAC_set_TSU_tx_mode() function configures time stamp recording for transmitted packets. This allows recording the TSU value for transmitted packets in the DMA descriptor for different types of packet. The transmit packet callback function can retrieve the packet time stamp from the DMA descriptor for processing by the application. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param tsu_mode This parameter selects which types of packet have their time stamp recorded. The available options allow for none, PTP event packets, all PTP packets and all packets. @return This function does not return a value. Example: This example illustrates configuring the TSU for operation with a 125MHz clock (8nS increment). It also configures the time stamping operation for the Ethernet MAC to collect the time stamps for received and transmitted PTP packets without modifying outgoing PTP packets. The ingress and egress unicast PTP addresses to recognize are set to 10.1.1.2 and 10.1.1.3 respectively and at a later stage the current TSU count is retrieved and displayed. @code #include "mss_ethernet_mac.h" void init_ts(void) { mss_mac_tsu_config_t tsu_cfg; tsu_cfg.nanoseconds = 0; tsu_cfg.secs_lsb = 0; tsu_cfg.secs_msb = 0; tsu_cfg.ns_inc = 8; tsu_cfg.sub_ns_inc = 0; MSS_MAC_init_TSU(&g_mac0, &tsu_cfg); MSS_MAC_set_TSU_rx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_tx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_oss_mode(&g_mac0, MSS_MAC_OSS_MODE_DISABLED); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_RX, 0x0A010102); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_TX, 0x0A010103); ... MSS_MAC_read_TSU(&g_mac0, &tsu_val); printf("TSU = %u, %u, %u\n\r", tsu_val.secs_msb, tsu_val.secs_lsb, tsu_val.nanoseconds); } @endcode */ void MSS_MAC_set_TSU_tx_mode ( const mss_mac_instance_t *this_mac, mss_mac_tsu_mode_t tsu_mode ); /***************************************************************************//** The MSS_MAC_get_TSU_rx_mode() function allows the application determine the current TSU receive time stamping mode. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns the current TSU receive time stamping mode setting. */ mss_mac_tsu_mode_t MSS_MAC_get_TSU_rx_mode ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_get_TSU_tx_mode() function allows the application determine the current TSU tranmit time stamping mode. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns the current TSU transmit time stamping mode setting. */ mss_mac_tsu_mode_t MSS_MAC_get_TSU_tx_mode ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_TSU_oss_mode() function configures one step sync (OSS) operation for the Ethernet MAC. The three options allow for disabling OSS, enabling OSS time stamp replacement mode and enabling OSS correction field adjustment mode. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param oss_mode This parameter selects which OSS mode to use. @return This function does not return a value. Example: @code #include "mss_ethernet_mac.h" void init_ts(void) { mss_mac_tsu_config_t tsu_cfg; tsu_cfg.nanoseconds = 0; tsu_cfg.secs_lsb = 0; tsu_cfg.secs_msb = 0; tsu_cfg.ns_inc = 8; tsu_cfg.sub_ns_inc = 0; MSS_MAC_init_TSU(&g_mac0, &tsu_cfg); MSS_MAC_set_TSU_rx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_tx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_oss_mode(&g_mac0, MSS_MAC_OSS_MODE_DISABLED); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_RX, 0x0A010102); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_TX, 0x0A010103); ... MSS_MAC_read_TSU(&g_mac0, &tsu_val); printf("TSU = %u, %u, %u\n\r", tsu_val.secs_msb, tsu_val.secs_lsb, tsu_val.nanoseconds); } @endcode */ void MSS_MAC_set_TSU_oss_mode ( const mss_mac_instance_t *this_mac, mss_mac_oss_mode_t oss_mode ); /***************************************************************************//** The MSS_MAC_get_TSU_oss_mode() function returns the currently configured one step sync (OSS) mode for the MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns an mss_mac_oss_mode_t value which indicates the current OSS mode in operation. */ mss_mac_oss_mode_t MSS_MAC_get_TSU_oss_mode ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_TSU_unicast_addr() function configures IP addresses that the MAC will use to identify unicast PTP frames. The receive IPv4 address and transmit IPv4 address can be set separately. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param select This parameter of type mss_mac_tsu_addr_t, selects whether the RX or TX address is being set. @param ip_address This unsigned 32 bit int holds the IP address with the 8 msb holding the leftmost octet i.e. 10.2.2.1 is represented as 0x0A020201. @return This function does not return a value. Example: @code #include "mss_ethernet_mac.h" void init_ts(void) { mss_mac_tsu_config_t tsu_cfg; tsu_cfg.nanoseconds = 0; tsu_cfg.secs_lsb = 0; tsu_cfg.secs_msb = 0; tsu_cfg.ns_inc = 8; tsu_cfg.sub_ns_inc = 0; MSS_MAC_init_TSU(&g_mac0, &tsu_cfg); MSS_MAC_set_TSU_rx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_tx_mode(&g_mac0, MSS_MAC_TSU_MODE_PTP_EVENT); MSS_MAC_set_TSU_oss_mode(&g_mac0, MSS_MAC_OSS_MODE_DISABLED); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_RX, 0x0A010102); MSS_MAC_set_TSU_unicast_addr(&g_mac0, MSS_MAC_TSU_UNICAST_TX, 0x0A010103); ... MSS_MAC_read_TSU(&g_mac0, &tsu_val); printf("TSU = %u, %u, %u\n\r", tsu_val.secs_msb, tsu_val.secs_lsb, tsu_val.nanoseconds); } @endcode */ void MSS_MAC_set_TSU_unicast_addr ( const mss_mac_instance_t *this_mac, mss_mac_tsu_addr_t select, uint32_t ip_address ); /***************************************************************************//** The MSS_MAC_get_TSU_unicast_addr() function retrieves the IP addresses that the Ethernet MAC uses to identify unicast PTP frames. The receive IPv4 address and transmit IPv4 address can retrieved separately. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param select This parameter of type mss_mac_tsu_addr_t, selects whether the RX or TX address is being retrieved. @return This function returns an unsigned 32 bit int which holds the IP address with the 8 msb holding the leftmost octet i.e. 10.2.2.1 is represented as 0x0A020201. */ uint32_t MSS_MAC_get_TSU_unicast_addr ( const mss_mac_instance_t *this_mac, mss_mac_tsu_addr_t select ); /***************************************************************************//** The MSS_MAC_set_VLAN_only_mode() function allows the application enable or disable VLAN only mode. When VALN only mode is enabled, non VLAN tagged packets will be discarded. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param enable This parameter of type bool, is set to true to enable VLAN only mode and false to disable it. @return This function does not return a value. */ void MSS_MAC_set_VLAN_only_mode ( const mss_mac_instance_t *this_mac, bool enable ); /***************************************************************************//** The MSS_MAC_get_VLAN_only_mode() function retrieves the current VLAN only mode status. When VALN only mode is enabled, non VLAN tagged packets will be discarded. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a value of type bool, which is true to indicate VLAN only mode is currently enabled and false otherwise. */ bool MSS_MAC_get_VLAN_only_mode ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_stacked_VLAN() function sets the stacked VLAN tag register in the MAC. This can be used to enable and disable stacked VLAN operation. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param tag This parameter of type uint16_t, holds the stacked VLAN tag to write to the Ethernet MAC. A value <= GEM_VLAN_ETHERTYPE_MIN disables stacked VLAN mode and sets the stacked VLAN tag to 0. @return This function does not return a value. */ void MSS_MAC_set_stacked_VLAN ( const mss_mac_instance_t *this_mac, uint16_t tag ); /***************************************************************************//** The MSS_MAC_get_stacked_VLAN() function retrieves the current stacked VLAN tag register from the Ethernet MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a value of type uint16_t, which is the current stacked VLAN tag from the Ethernet MAC. A value of 0 indicates stacked VLAN mode is disabled. */ uint16_t MSS_MAC_get_stacked_VLAN ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_hash() function sets the 64 bit addressing hash field in the Ethernet MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param hash This parameter of type uint64_t, holds the hash bitmap for the MAC which is used to enable matching against blocks of addresses based on a 6 bit hashing function. As a short cut, setting value of 0 also disables hash address matching. @return This function does not return a value. Example: This example sets the hash bit for the multicast MAC address 01:80:C2:00:00:0E and also configures the Ethernet MAC to only use hashing to match multicast addresses. The calc_gem_hash_index() function calculates the bit index in the 64 bit hash value associated with a given MAC address. @code uint32_t calc_gem_hash_index(uint8_t *p_address) { uint64_t address; uint32_t index; uint32_t count; p_address += 5; address = 0; for(count = 0; count != 6; count++) { address <<= 8; address |= (uint64_t)*p_address; p_address--; } index = (int32_t)address & 0x0000003Fl; for(count = 0; count != 7; count++) { address >>= 6; index ^= (uint32_t)(address & 0x0000003Fl); } return(index); } void set_gem_hash(void) { uint8_t mac_address[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}; int32_t index; uint64_t temp_hash; uint64_t current_hash; index = calc_gem_hash_index(mac_address); temp_hash = (uint64_t)(1ll << index); current_hash = MSS_MAC_get_hash(g_mac0); current_hash = current_hash | temp_hash; MSS_MAC_set_hash_mode(g_mac0, MSS_MAC_HASH_MULTICAST); MSS_MAC_set_hash(g_mac0, current_hash); } @endcode */ void MSS_MAC_set_hash ( const mss_mac_instance_t *this_mac, uint64_t hash ); /***************************************************************************//** The MSS_MAC_get_hash() function retrieves the current 64 bit addressing hash field from the Ethernet MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a value of type uint64_t, representing the hash bitmap for the Ethernet MAC. Example: This example sets the hash bit for the multicast MAC address 01:80:C2:00:00:0E and also configures the Ethernet MAC to only use hashing to match multicast addresses. The calc_gem_hash_index() function calculates the bit index in the 64 bit hash value associated with a given MAC address. @code uint32_t calc_gem_hash_index(uint8_t *p_address) { uint64_t address; uint32_t index; uint32_t count; p_address += 5; address = 0; for(count = 0; count != 6; count++) { address <<= 8; address |= (uint64_t)*p_address; p_address--; } index = (int32_t)address & 0x0000003Fl; for(count = 0; count != 7; count++) { address >>= 6; index ^= (uint32_t)(address & 0x0000003Fl); } return(index); } void set_gem_hash(void) { uint8_t mac_address[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}; int32_t index; uint64_t temp_hash; uint64_t current_hash; index = calc_gem_hash_index(mac_address); temp_hash = (uint64_t)(1ll << index); current_hash = MSS_MAC_get_hash(g_mac0); current_hash = current_hash | temp_hash; MSS_MAC_set_hash_mode(g_mac0, MSS_MAC_HASH_MULTICAST); MSS_MAC_set_hash(g_mac0, current_hash); } @endcode */ uint64_t MSS_MAC_get_hash ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_hash_mode() function sets the operational mode for the hash based address matching. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param mode This parameter of type mss_mac_hash_mode_t, selects the mode of operation of the hash based address filter. The options allow for disabling hash based filtering, matching unicast packets only, matching multicast packets only and matching both packet types. @return This function does not return a value. Example: This example sets the hash bit for the multicast MAC address 01:80:C2:00:00:0E and also configures the Ethernet MAC to only use hashing to match multicast addresses. The calc_gem_hash_index() function calculates the bit index in the 64 bit hash value associated with a given MAC address. @code uint32_t calc_gem_hash_index(uint8_t *p_address) { uint64_t address; uint32_t index; uint32_t count; p_address += 5; address = 0; for(count = 0; count != 6; count++) { address <<= 8; address |= (uint64_t)*p_address; p_address--; } index = (int32_t)address & 0x0000003Fl; for(count = 0; count != 7; count++) { address >>= 6; index ^= (uint32_t)(address & 0x0000003Fl); } return(index); } void set_gem_hash(void) { uint8_t mac_address[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}; int32_t index; uint64_t temp_hash; uint64_t current_hash; index = calc_gem_hash_index(mac_address); temp_hash = (uint64_t)(1ll << index); current_hash = MSS_MAC_get_hash(g_mac0); current_hash = current_hash | temp_hash; MSS_MAC_set_hash_mode(g_mac0, MSS_MAC_HASH_MULTICAST); MSS_MAC_set_hash(g_mac0, current_hash); } @endcode */ void MSS_MAC_set_hash_mode ( const mss_mac_instance_t *this_mac, mss_mac_hash_mode_t mode ); /***************************************************************************//** The MSS_MAC_get_hash_mode() function retrieves the current operational mode for the hash based address matching. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a value of type mss_mac_hash_mode_t, which indicates the mode of operation of the hash based address filter. */ mss_mac_hash_mode_t MSS_MAC_get_hash_mode ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_type_filter() function is used to configure the specific type filters in the Ethernet MAC. These filters allow selective reception of packets based on matching the type ID/length field in the packet. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter This parameter of type uint16_t, selects which filter to configure. The valid range is 1 to 4 to match the numbering in the GEM documentation. @param value This parameter of type uint16_t, is the value to match against. Typical values for matching purposes will be greater than 0x600 (1536) as the field is used for packet length in some circumstances and as the Ethertype value in others. Setting the value to 0 indicates disabling the filter. @return This function does not return a value. Example: This example enables Specific Type filters 1 and 2 for IPv4 and IPv6 packets respectively. @code #include "mss_ethernet_mac.h" void init_st_filters(void) { MSS_MAC_set_type_filter(&g_mac0, 1, 0x0800); MSS_MAC_set_type_filter(&g_mac0, 2, 0x86DD); MSS_MAC_set_type_filter(&g_mac0, 3, 0x0000); MSS_MAC_set_type_filter(&g_mac0, 4, 0x0000); } @endcode */ void MSS_MAC_set_type_filter ( const mss_mac_instance_t *this_mac, uint32_t filter, uint16_t value ); /***************************************************************************//** The MSS_MAC_get_type_filter() function is used to retrieve the current settings of the specific type filters in the Ethernet MAC. These filters allow selective reception of packets based on matching the type ID/length field in the packet. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter This parameter of type uint16_t, selects which filter to read. The valid range is 1 to 4 to match the numbering in the GEM documentation. @return This function returns a value of type uint16_t, which is the current filter match value. A value of 0 indicates the filter is disabled. . */ uint16_t MSS_MAC_get_type_filter ( const mss_mac_instance_t *this_mac, uint32_t filter ); /***************************************************************************//** The MSS_MAC_set_sa_filter() function is used to configure the specific address filters in the Ethernet MAC. These filters allow selective reception of packets based on matching the destination or source MAC address field in the packet. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter This parameter of type uint16_t, selects which filter to configure. The valid range is 2 to 4 to match the numbering in the GEM documentation. Filter 1 is reserved for the MAC address of the device and cannot be modified using this function. @param control This parameter of type uint16_t, is used to select between source and destination matching and selective masking of individual bytes, see the MSS_MAC_SA_FILTER_* macros for allowed values. In addition, the MSS_MAC_SA_FILTER_DISABLE value is used to disable a filter. @param mac_addr This parameter of type pointer to uint8_t, points to the 6 byte MAC address to be used for this filter operation. @return This function does not return a value. Example: This example assumes MAC0 is connected on the same network as MAC1 and configures source address filters to detect traffic from MAC0 and MAC1 on the opposing MAC. This uses filter number two on each Ethernet MAC. @code #include "mss_ethernet_mac.h" void init_sa_filters(void) { MSS_MAC_set_sa_filter(&g_mac0, 2, MSS_MAC_SA_FILTER_SOURCE, g_mac1.mac_addr); MSS_MAC_set_sa_filter(&g_mac1, 2, MSS_MAC_SA_FILTER_SOURCE, g_mac0.mac_addr); } @endcode */ void MSS_MAC_set_sa_filter ( const mss_mac_instance_t *this_mac, uint32_t filter, uint16_t control, const uint8_t *mac_addr ); /***************************************************************************//** The MSS_MAC_get_sa_filter() function retrieves the current specific address filter settings from the Ethernet MAC. These filters allow selective reception of packets based on matching the destination or source MAC address field in the packet. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter This parameter of type uint16_t, selects which filter to retrieve from. The valid range is 2 to 4 to match the numbering in the GEM documentation. Filter 1 is reserved for the MAC address of the device and cannot be read using this function. @param mac_addr This parameter of type pointer to uint8_t, points to a storage location where the 6 byte MAC address from the filter will be stored. @return This function returns a value of type uint16_t, which has the same format as the control parameter for the MSS_MAC_set_sa_filter() function. Example: This example reads the filter settings for filter 2 on the pMAC of GEM 0. @code #include "mss_ethernet_mac.h" void read_sa_filter_2(void) { uint16_t control; uint8_t mac_addr[6]; control = MSS_MAC_get_sa_filter(&g_mac0, 2, mac_addr); } @endcode */ uint16_t MSS_MAC_get_sa_filter ( const mss_mac_instance_t *this_mac, uint32_t filter, uint8_t *mac_addr ); /***************************************************************************//** The MSS_MAC_set_type_1_filter() function is used to configure the Type 1 filters in the Ethernet MAC. These filters allow selective routing of packets to specific queues based on combinations of UDP port number and/or differentiated service/traffic class values. Packets can also be flagged for dropping based on the same criteria. Packets that do not match a Type 1 or Type 2 filter are automatically routed to queue 0. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter_no This parameter of type uint32_t, selects which filter to configure. The valid range is 0 to 3. @param filter This parameter of type pointer to mss_mac_type_1_filter_t, points to the filter configuration structure which defines the filter setup required. @return This function does not return a value. Example: This example configures 3 type 1 filters which route UDP port 320 packets to queue 1, packets with a DS or TC value of 15 to queue 2 and drops packets with a UDP port of 1534. The example also checks to see if filter 3 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t1_filters(void) { mss_mac_type_1_filter_t filter1; MSS_MAC_get_type_1_filter(&g_mac0, 3, &filter1); if(0 == filter1.udp_port) { memset(&filter1, 0, sizeof(filter1)); filter1.udp_port = 320; filter1.udp_port_enable = 1; filter1.queue_no = 1; MSS_MAC_set_type_1_filter(&g_mac0, 3, &filter1); memset(&filter1, 0, sizeof(filter1)); filter1.dstc = 0x0F; filter1.dstc_enable = 1; filter1.queue_no = 2; MSS_MAC_set_type_1_filter(&g_mac0, 2, &filter1); memset(&filter1, 0, sizeof(filter1)); filter1.udp_port = 1534; filter1.udp_port_enable = 1; filter1.drop_on_match = 1; filter1.queue_no = 3; MSS_MAC_set_type_1_filter(&g_mac0, 1, &filter1); } } @endcode */ void MSS_MAC_set_type_1_filter ( const mss_mac_instance_t *this_mac, uint32_t filter_no, const mss_mac_type_1_filter_t *filter ); /***************************************************************************//** The MSS_MAC_get_type_1_filter() function is used to retrieve the current Type 1 filter configurations from the Ethernet MAC. These filters allow selective routing of packets to specific queues based on combinations of UDP port number and/or differentiated service/traffic class values. Packets can also be flagged for dropping based on the same criteria. Packets that do not match a Type 1 or Type 2 filter are automatically routed to queue 0. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter_no This parameter of type uint32_t, selects which filter to retrieve. The valid range is 0 to 3. @param filter This parameter of type pointer to mss_mac_type_1_filter_t, points to the filter configuration structure which receives the setup information for the selected filter. @return This function does not return a value. Example: This example configures 3 type 1 filters which route UDP port 320 packets to queue 1, packets with a DS or TC value of 15 to queue 2 and drops packets with a UDP port of 1534. The example also checks to see if filter 3 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t1_filters(void) { mss_mac_type_1_filter_t filter1; MSS_MAC_get_type_1_filter(&g_mac0, 3, &filter1); if(0 == filter1.udp_port) { memset(&filter1, 0, sizeof(filter1)); filter1.udp_port = 320; filter1.udp_port_enable = 1; filter1.queue_no = 1; MSS_MAC_set_type_1_filter(&g_mac0, 3, &filter1); memset(&filter1, 0, sizeof(filter1)); filter1.dstc = 0x0F; filter1.dstc_enable = 1; filter1.queue_no = 2; MSS_MAC_set_type_1_filter(&g_mac0, 2, &filter1); memset(&filter1, 0, sizeof(filter1)); filter1.udp_port = 1534; filter1.udp_port_enable = 1; filter1.drop_on_match = 1; filter1.queue_no = 3; MSS_MAC_set_type_1_filter(&g_mac0, 1, &filter1); } } @endcode */ void MSS_MAC_get_type_1_filter ( const mss_mac_instance_t *this_mac, uint32_t filter_no, mss_mac_type_1_filter_t *filter ); /***************************************************************************//** The MSS_MAC_set_type_2_filter() function is used to configure the Type 2 filters in the Ethernet MAC. These filters allow selective routing of packets to specific queues based on combinations of Ethertype field values, general data patterns and VLAN priority values. Packets can also be flagged for dropping based on the same criteria. For consistent operation, the application should always use the MSS_MAC_set_type_2_compare() and MSS_MAC_set_type_2_ethertype() functions to set up the filter match values before calling MSS_MAC_set_type_2_filter(). Packets that do not match a Type 1 or Type 2 filter are automatically routed to queue 0. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter_no This parameter of type uint32_t, selects which filter to configure. The valid range is 0 to 3 for pMACs and 0 to 1 for eMACs. @param filter This parameter of type pointer to mss_mac_type_2_filter_t, points to the filter configuration structure which defines the filter setup required. @return This function does not return a value. Example: This example configures 2 filters which route IP packets with 0x9E, 0x48, 0x05, 0x0F at offset 0x48 to queue 3 and ARP packets with 12 x 0xFF at offset 0x30 to queue 2. The example also checks to see if Ethertype block 0 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t2_filters(void) { mss_mac_type_2_filter_t filter; mss_mac_type_2_compare_t compare; if(0 == MSS_MAC_get_type_2_ethertype(&g_mac0, 0)) { MSS_MAC_set_type_2_ethertype(&g_mac0, 0, 0x0800); compare.disable_mask = 1; compare.data = 0x0F05489EUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x48; MSS_MAC_set_type_2_compare(&g_mac0, 0, &compare); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 0; filter.ethertype_enable = 1; filter.ethertype_index = 0; filter.queue_no = 3; MSS_MAC_set_type_2_filter(&g_mac0, 0, &filter); compare.disable_mask = 1; compare.data = 0xFFFFFFFFUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x30; MSS_MAC_set_type_2_compare(&g_mac0, 1, &compare); compare.offset_value = 0x34; MSS_MAC_set_type_2_compare(&g_mac0, 2, &compare); compare.offset_value = 0x38; MSS_MAC_set_type_2_compare(&g_mac0, 3, &compare); MSS_MAC_set_type_2_ethertype(&g_mac0, 1, 0x0806); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 1; filter.compare_b_enable = 1; filter.compare_b_index = 2; filter.compare_c_enable = 1; filter.compare_c_index = 3; filter.ethertype_enable = 1; filter.ethertype_index = 1; filter.queue_no = 2; MSS_MAC_set_type_2_filter(&g_mac0, 1, &filter); } } @endcode */ void MSS_MAC_set_type_2_filter ( const mss_mac_instance_t *this_mac, uint32_t filter_no, const mss_mac_type_2_filter_t *filter ); /***************************************************************************//** The MSS_MAC_get_type_2_filter() function is used to retrieve the current Type 2 filter configuration from the Ethernet MAC. These filters allow selective routing of packets to specific queues based on combinations of Ethertype field values, general data patterns and VLAN priority values. Packets can also be flagged for dropping based on the same criteria. Packets that do not match a Type 1 or Type 2 filter are automatically routed to queue 0. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param filter_no This parameter of type uint32_t, selects which filter to retrieve. The valid range is 0 to 3 for pMACs and 0 to 1 for eMACs. @param filter This parameter of type pointer to mss_mac_type_2_filter_t, points to the filter configuration structure which will receive a copy of the current filter setup. @return This function does not return a value. Example: This example configures 2 filters which route IP packets with 0x9E, 0x48, 0x05, 0x0F at offset 0x48 to queue 3 and ARP packets with 12 x 0xFF at offset 0x30 to queue 2. The example also checks to see if Ethertype block 0 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t2_filters(void) { mss_mac_type_2_filter_t filter; mss_mac_type_2_compare_t compare; if(0 == MSS_MAC_get_type_2_ethertype(&g_mac0, 0)) { MSS_MAC_set_type_2_ethertype(&g_mac0, 0, 0x0800); compare.disable_mask = 1; compare.data = 0x0F05489EUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x48; MSS_MAC_set_type_2_compare(&g_mac0, 0, &compare); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 0; filter.ethertype_enable = 1; filter.ethertype_index = 0; filter.queue_no = 3; MSS_MAC_set_type_2_filter(&g_mac0, 0, &filter); compare.disable_mask = 1; compare.data = 0xFFFFFFFFUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x30; MSS_MAC_set_type_2_compare(&g_mac0, 1, &compare); compare.offset_value = 0x34; MSS_MAC_set_type_2_compare(&g_mac0, 2, &compare); compare.offset_value = 0x38; MSS_MAC_set_type_2_compare(&g_mac0, 3, &compare); MSS_MAC_set_type_2_ethertype(&g_mac0, 1, 0x0806); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 1; filter.compare_b_enable = 1; filter.compare_b_index = 2; filter.compare_c_enable = 1; filter.compare_c_index = 3; filter.ethertype_enable = 1; filter.ethertype_index = 1; filter.queue_no = 2; MSS_MAC_set_type_2_filter(&g_mac0, 1, &filter); } } @endcode */ void MSS_MAC_get_type_2_filter ( const mss_mac_instance_t *this_mac, uint32_t filter_no, mss_mac_type_2_filter_t *filter ); /***************************************************************************//** The MSS_MAC_set_type_2_ethertype() function is used to configure the Type 2 Ethertype matching blocks in the Ethernet MAC. These are used by Type 2 filters to allow selection of packet types. For consistent operation, the application should always use the MSS_MAC_set_type_2_compare() and MSS_MAC_set_type_2_ethertype() functions to set up the filter match values before calling MSS_MAC_set_type_2_filter(). @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param ethertype_no This parameter of type uint32_t, selects which Ethertype block to configure. The valid range is 0 to 3 for pMACs, eMACs do not support Ethertype filters. @param ethertype This parameter of type uint16_t, is the Ethertype value to match against. A value of 0 indicates the Ethertype matching block is not configured. @return This function does not return a value. Example: This example configures 2 filters which route IP packets with 0x9E, 0x48, 0x05, 0x0F at offset 0x48 to queue 3 and ARP packets with 12 x 0xFF at offset 0x30 to queue 2. The example also checks to see if Ethertype block 0 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t2_filters(void) { mss_mac_type_2_filter_t filter; mss_mac_type_2_compare_t compare; if(0 == MSS_MAC_get_type_2_ethertype(&g_mac0, 0)) { MSS_MAC_set_type_2_ethertype(&g_mac0, 0, 0x0800); compare.disable_mask = 1; compare.data = 0x0F05489EUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x48; MSS_MAC_set_type_2_compare(&g_mac0, 0, &compare); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 0; filter.ethertype_enable = 1; filter.ethertype_index = 0; filter.queue_no = 3; MSS_MAC_set_type_2_filter(&g_mac0, 0, &filter); compare.disable_mask = 1; compare.data = 0xFFFFFFFFUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x30; MSS_MAC_set_type_2_compare(&g_mac0, 1, &compare); compare.offset_value = 0x34; MSS_MAC_set_type_2_compare(&g_mac0, 2, &compare); compare.offset_value = 0x38; MSS_MAC_set_type_2_compare(&g_mac0, 3, &compare); MSS_MAC_set_type_2_ethertype(&g_mac0, 1, 0x0806); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 1; filter.compare_b_enable = 1; filter.compare_b_index = 2; filter.compare_c_enable = 1; filter.compare_c_index = 3; filter.ethertype_enable = 1; filter.ethertype_index = 1; filter.queue_no = 2; MSS_MAC_set_type_2_filter(&g_mac0, 1, &filter); } } @endcode */ void MSS_MAC_set_type_2_ethertype ( const mss_mac_instance_t *this_mac, uint32_t ethertype_no, uint16_t ethertype ); /***************************************************************************//** The MSS_MAC_get_type_2_ethertype() function is used to retrieve the current settings for Type 2 Ethertype matching blocks in the Ethernet MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param ethertype_no This parameter of type uint32_t, selects which Ethertype block to retrieve. The valid range is 0 to 3 for pMACs, eMACs do not support Ethertype filters. @return This function returns a value of type uint16_t which is the Ethertype value to match against. A value of 0 indicates the Ethertype matching block is not configured. Example: This example configures 2 filters which route IP packets with 0x9E, 0x48, 0x05, 0x0F at offset 0x48 to queue 3 and ARP packets with 12 x 0xFF at offset 0x30 to queue 2. The example also checks to see if Ethertype block 0 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t2_filters(void) { mss_mac_type_2_filter_t filter; mss_mac_type_2_compare_t compare; if(0 == MSS_MAC_get_type_2_ethertype(&g_mac0, 0)) { MSS_MAC_set_type_2_ethertype(&g_mac0, 0, 0x0800); compare.disable_mask = 1; compare.data = 0x0F05489EUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x48; MSS_MAC_set_type_2_compare(&g_mac0, 0, &compare); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 0; filter.ethertype_enable = 1; filter.ethertype_index = 0; filter.queue_no = 3; MSS_MAC_set_type_2_filter(&g_mac0, 0, &filter); compare.disable_mask = 1; compare.data = 0xFFFFFFFFUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x30; MSS_MAC_set_type_2_compare(&g_mac0, 1, &compare); compare.offset_value = 0x34; MSS_MAC_set_type_2_compare(&g_mac0, 2, &compare); compare.offset_value = 0x38; MSS_MAC_set_type_2_compare(&g_mac0, 3, &compare); MSS_MAC_set_type_2_ethertype(&g_mac0, 1, 0x0806); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 1; filter.compare_b_enable = 1; filter.compare_b_index = 2; filter.compare_c_enable = 1; filter.compare_c_index = 3; filter.ethertype_enable = 1; filter.ethertype_index = 1; filter.queue_no = 2; MSS_MAC_set_type_2_filter(&g_mac0, 1, &filter); } } @endcode */ uint16_t MSS_MAC_get_type_2_ethertype ( const mss_mac_instance_t *this_mac, uint32_t ethertype_no ); /***************************************************************************//** The MSS_MAC_set_type_2_compare() function is used to configure the Type 2 data matching blocks in the Ethernet MAC. These are used by Type 2 filters to allow comparing up to 4 bytes of data at different locations in the packet. They also allow for matching against VLAN IDs. The data matching can be performed against 4 consecutive bytes or against up to 2 consecutive bytes with an associated bit mask. For consistent operation, the application should always use the MSS_MAC_set_type_2_compare() and MSS_MAC_set_type_2_ethertype() functions to set up the filter match values before calling MSS_MAC_set_type_2_filter(). @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param comparer_no_in This parameter of type uint32_t, selects which compare block to configure. The valid range is 0 to 11 for pMACs and 0 to 5 for eMACs. @param comparer This parameter of type pointer to mss_mac_type_2_compare_t, is the address of the compare block structure to use for the configuration. @return This function does not return a value. Example: This example configures 2 filters which route IP packets with 0x9E, 0x48, 0x05, 0x0F at offset 0x48 to queue 3 and ARP packets with 12 x 0xFF at offset 0x30 to queue 2. The example also checks to see if Ethertype block 0 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t2_filters(void) { mss_mac_type_2_filter_t filter; mss_mac_type_2_compare_t compare; if(0 == MSS_MAC_get_type_2_ethertype(&g_mac0, 0)) { MSS_MAC_set_type_2_ethertype(&g_mac0, 0, 0x0800); compare.disable_mask = 1; compare.data = 0x0F05489EUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x48; MSS_MAC_set_type_2_compare(&g_mac0, 0, &compare); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 0; filter.ethertype_enable = 1; filter.ethertype_index = 0; filter.queue_no = 3; MSS_MAC_set_type_2_filter(&g_mac0, 0, &filter); compare.disable_mask = 1; compare.data = 0xFFFFFFFFUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x30; MSS_MAC_set_type_2_compare(&g_mac0, 1, &compare); compare.offset_value = 0x34; MSS_MAC_set_type_2_compare(&g_mac0, 2, &compare); compare.offset_value = 0x38; MSS_MAC_set_type_2_compare(&g_mac0, 3, &compare); MSS_MAC_set_type_2_ethertype(&g_mac0, 1, 0x0806); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 1; filter.compare_b_enable = 1; filter.compare_b_index = 2; filter.compare_c_enable = 1; filter.compare_c_index = 3; filter.ethertype_enable = 1; filter.ethertype_index = 1; filter.queue_no = 2; MSS_MAC_set_type_2_filter(&g_mac0, 1, &filter); } } @endcode */ void MSS_MAC_set_type_2_compare ( const mss_mac_instance_t *this_mac, uint32_t comparer_no_in, const mss_mac_type_2_compare_t *comparer ); /***************************************************************************//** The MSS_MAC_get_type_2_compare() function is used to retrieve the current Type 2 data matching blocks configuration from the Ethernet MAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param comparer_no_in This parameter of type uint32_t, selects which compare block to retrieve. The valid range is 0 to 11 for pMACs and 0 to 5 for eMACs. @param comparer This parameter of type pointer to mss_mac_type_2_compare_t, is the address of the configuration structure which will receive a copy of the current comparer block setup. @return This function does not return a value. Example: This example configures 2 filters which route IP packets with 0x9E, 0x48, 0x05, 0x0F at offset 0x48 to queue 3 and ARP packets with 12 x 0xFF at offset 0x30 to queue 2. The example also checks to see if Ethertype block 0 has already been configured and only proceeds if it is not configured. @code #include "mss_ethernet_mac.h" void init_t2_filters(void) { mss_mac_type_2_filter_t filter; mss_mac_type_2_compare_t compare; if(0 == MSS_MAC_get_type_2_ethertype(&g_mac0, 0)) { MSS_MAC_set_type_2_ethertype(&g_mac0, 0, 0x0800); compare.disable_mask = 1; compare.data = 0x0F05489EUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x48; MSS_MAC_set_type_2_compare(&g_mac0, 0, &compare); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 0; filter.ethertype_enable = 1; filter.ethertype_index = 0; filter.queue_no = 3; MSS_MAC_set_type_2_filter(&g_mac0, 0, &filter); compare.disable_mask = 1; compare.data = 0xFFFFFFFFUL; compare.compare_offset = MSS_MAC_T2_OFFSET_FRAME; compare.offset_value = 0x30; MSS_MAC_set_type_2_compare(&g_mac0, 1, &compare); compare.offset_value = 0x34; MSS_MAC_set_type_2_compare(&g_mac0, 2, &compare); compare.offset_value = 0x38; MSS_MAC_set_type_2_compare(&g_mac0, 3, &compare); MSS_MAC_set_type_2_ethertype(&g_mac0, 1, 0x0806); memset(&filter, 0, sizeof(filter)); filter.compare_a_enable = 1; filter.compare_a_index = 1; filter.compare_b_enable = 1; filter.compare_b_index = 2; filter.compare_c_enable = 1; filter.compare_c_index = 3; filter.ethertype_enable = 1; filter.ethertype_index = 1; filter.queue_no = 2; MSS_MAC_set_type_2_filter(&g_mac0, 1, &filter); } } @endcode */ void MSS_MAC_get_type_2_compare ( const mss_mac_instance_t *this_mac, uint32_t comparer_no_in, mss_mac_type_2_compare_t *comparer ); /***************************************************************************//** The MSS_MAC_set_mmsl_mode() function is used to configure the operation of the MAC Merge Sublayer component of the GEM. This function is used to enable and disable preemption and to determine which MAC (eMAC or pMAC) is used for reception in non preemption modes. The function also allows control of the preemption verification functionality. The function only operates on the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param mmsl_cfg This parameter of type pointer to mss_mac_mmsl_config_t, points to the configuration structure used to set the MMSL operation mode. @return This function does not return a value. */ void MSS_MAC_set_mmsl_mode ( const mss_mac_instance_t *this_mac, const mss_mac_mmsl_config_t *mmsl_cfg ); /***************************************************************************//** The MSS_MAC_get_mmsl_mode() function is used to retrieve the current configuration of the MAC Merge Sublayer component of the GEM. The function only operates on the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param mmsl_cfg This parameter of type pointer to mss_mac_mmsl_config_t, points to the configuration structure which will receive a copy of the current MMSL configuration. @return This function does not return a value. */ void MSS_MAC_get_mmsl_mode ( const mss_mac_instance_t *this_mac, mss_mac_mmsl_config_t *mmsl_cfg ); /***************************************************************************//** The MSS_MAC_start_preemption_verify() function is used to initiate a link preemption verification operation by the MAC Merge Sublayer component of the GEM. The progress and completion status of the operation can be monitored by calling the MSS_MAC_get_mmsl_status() function until the operation completes. The function only operates on the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function does not return a value. */ void MSS_MAC_start_preemption_verify ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_get_mmsl_status() function is used to monitor the current state of the MAC Merge Sublayer component of the GEM. The function returns the raw 32 bit value from the MMSL Status register and the definitions in mss_ethernet_mac_regs.h can be used to examine the status. The function only operates on the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a 32 bit value which is a copy of the MMSL Status register. The register bit defines for the MMSL Status register can be used to examine the return value including the GEM_VERIFY_* defines which enumerate the verification state machine. */ uint32_t MSS_MAC_get_mmsl_status ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_get_mmsl_stats() function is used to retrieve the statistics counts from the MAC Merge Sublayer component of the GEM. The function only operates on the pMAC. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param stats This parameter is a pointer to an mss_mac_mmsl_stats_t structure which will be populated with the current MMSL statistics counts. @return This function does not return a value. */ void MSS_MAC_get_mmsl_stats ( const mss_mac_instance_t *this_mac, mss_mac_mmsl_stats_t *stats ); /***************************************************************************//** The MSS_MAC_set_tx_cutthru() function is used to set the transmit cutthru level for the GEM DMA engine. The useful ranges are different for the eMAC and pMAC and will also differ based on the allocation of DMA buffer space to active queues. This setting should be used with caution and the correct values will depend on the overall bus speed amongst other things. This value may need to be configured to allow sending Jumbo frames of more than approximately 3,880 bytes depending on system configuration. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param level This 32 bit parameter indicates the minimum data to be read into the DMA buffer before cutthru operation begins. @return This function does not return a value. */ void MSS_MAC_set_tx_cutthru ( const mss_mac_instance_t *this_mac, uint32_t level ); /***************************************************************************//** The MSS_MAC_set_rx_cutthru() function is used to set the receive cutthru level for the GEM DMA engine. The useful ranges are different for the eMAC and pMAC. This setting should be used with caution and the correct values will depend on the overall bus speed amongst other things. This value may need to be configured to allow receiving Jumbo frames of more than approximately 3,880 bytes depending on system configuration. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param level This 32 bit parameter indicates the minimum data to be written from the FIFO into the DMA buffer before cutthru operation begins. @return This function does not return a value. */ void MSS_MAC_set_rx_cutthru ( const mss_mac_instance_t *this_mac, uint32_t level ); /***************************************************************************//** The MSS_MAC_get_tx_cutthru() function is used to retrieve the current transmit cutthru level for the GEM DMA engine. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns an unsigned 32 bit value representing the current minimum amount of data to be read into the DMA buffer before cutthru operation begins. */ uint32_t MSS_MAC_get_tx_cutthru ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_get_rx_cutthru() function is used to retrieve the current receive cutthru level for the GEM DMA engine. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns an unsigned 32 bit value representing the current minimum amount of data to be read to be written from the FIFO into the DMA buffer before cutthru operation begins. */ uint32_t MSS_MAC_get_rx_cutthru ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_tx_enable() function is used to start or restart transmit operations. It can be used as part of recovery from errors which may have resulted in transmission being stopped. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function does not return a value. */ void MSS_MAC_tx_enable ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_jumbo_frames_mode() function is used to enable and disable reception of Jumbo frames. For this function to work correctly, the jumbo_frame_enable value in the mss_mac_cfg_t structure used to configure the Ethernet MAC will have to have been set to true. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param state This boolean parameter is set to true to enable Jumbo frame support and false to disable Jumbo frame support. @return This function does not return a value. */ void MSS_MAC_set_jumbo_frames_mode ( const mss_mac_instance_t *this_mac, bool state ); /***************************************************************************//** The MSS_MAC_get_jumbo_frames_mode() function is used to retrieve the current setting of Jumbo frame support. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a boolean value which is true if Jumbo frame support is enabled and false otherwise. */ bool MSS_MAC_get_jumbo_frames_mode ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_jumbo_frame_length() function is used to set the maximum length of Jumbo frames that can be received. The maximum allowed is MSS_MAC_JUMBO_MAX. For this function to work correctly, the jumbo_frame_enable value in the mss_mac_cfg_t structure used to configure the Ethernet MAC will have to have been set to true. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param length This unsigned 32 bit int parameter sets the maximum Jumbo frame length that the MAC will accept. @return This function does not return a value. */ void MSS_MAC_set_jumbo_frame_length ( const mss_mac_instance_t *this_mac, uint32_t length ); /***************************************************************************//** The MSS_MAC_get_jumbo_frame_length() function is used to retrieve the current maximum length of Jumbo frames that can be received. For this function to work correctly, the jumbo_frame_enable value in the mss_mac_cfg_t structure used to configure the Ethernet MAC will have to have been set to true. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns an unsigned 32 bit int indicating the current maximum Jumbo frame length that the MAC will accept. */ uint32_t MSS_MAC_get_jumbo_frame_length ( const mss_mac_instance_t *this_mac ); /***************************************************************************//** The MSS_MAC_set_pause_frame_copy_to_mem() function is used to control the writing of pause frames into memory. The default operation is not to copy pause frames into memory. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @param state This boolean value is true to enable copying of pause frames to memory and false to disable. @return This function does not return a value. */ void MSS_MAC_set_pause_frame_copy_to_mem ( const mss_mac_instance_t *this_mac, bool state ); /***************************************************************************//** The MSS_MAC_get_pause_frame_copy_to_mem() function is used to determine whether the GEM is currently configured to copy pause frames to memory. @param this_mac This parameter is a pointer to one of the global mss_mac_instance_t structures which identifies the MAC that the function is to operate on. There are between 1 and 4 such structures identifying pMAC0, eMAC0, pMAC1 and eMAC1. @return This function returns a boolean value which is true if copying of pause frames to memory is enabled and false otherwise. */ bool MSS_MAC_get_pause_frame_copy_to_mem ( const mss_mac_instance_t *this_mac ); #ifdef __cplusplus } #endif #endif /* MSS_ETHERNET_MAC_H_ */ mss_ethernet_mac_regs.h000066400000000000000000001435201432224323300433110ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC MSS MAC. * * SVN $Revision$ * SVN $Date$ */ #ifndef MSS_ETHERNET_MAC_REGS_H_ #define MSS_ETHERNET_MAC_REGS_H_ #ifdef __cplusplus extern "C" { #endif #define BIT_31 ((uint32_t)(0x80000000UL)) #define BIT_30 ((uint32_t)(0x40000000UL)) #define BIT_29 ((uint32_t)(0x20000000UL)) #define BIT_28 ((uint32_t)(0x10000000UL)) #define BIT_27 ((uint32_t)(0x08000000UL)) #define BIT_26 ((uint32_t)(0x04000000UL)) #define BIT_25 ((uint32_t)(0x02000000UL)) #define BIT_24 ((uint32_t)(0x01000000UL)) #define BIT_23 ((uint32_t)(0x00800000UL)) #define BIT_22 ((uint32_t)(0x00400000UL)) #define BIT_21 ((uint32_t)(0x00200000UL)) #define BIT_20 ((uint32_t)(0x00100000UL)) #define BIT_19 ((uint32_t)(0x00080000UL)) #define BIT_18 ((uint32_t)(0x00040000UL)) #define BIT_17 ((uint32_t)(0x00020000UL)) #define BIT_16 ((uint32_t)(0x00010000UL)) #define BIT_15 ((uint32_t)(0x00008000UL)) #define BIT_14 ((uint32_t)(0x00004000UL)) #define BIT_13 ((uint32_t)(0x00002000UL)) #define BIT_12 ((uint32_t)(0x00001000UL)) #define BIT_11 ((uint32_t)(0x00000800UL)) #define BIT_10 ((uint32_t)(0x00000400UL)) #define BIT_09 ((uint32_t)(0x00000200UL)) #define BIT_08 ((uint32_t)(0x00000100UL)) #define BIT_07 ((uint32_t)(0x00000080UL)) #define BIT_06 ((uint32_t)(0x00000040UL)) #define BIT_05 ((uint32_t)(0x00000020UL)) #define BIT_04 ((uint32_t)(0x00000010UL)) #define BIT_03 ((uint32_t)(0x00000008UL)) #define BIT_02 ((uint32_t)(0x00000004UL)) #define BIT_01 ((uint32_t)(0x00000002UL)) #define BIT_00 ((uint32_t)(0x00000001UL)) #define BITS_30 ((uint32_t)(0x3FFFFFFFUL)) #define BITS_24 ((uint32_t)(0x00FFFFFFUL)) #define BITS_22 ((uint32_t)(0x003FFFFFUL)) #define BITS_18 ((uint32_t)(0x0003FFFFUL)) #define BITS_16 ((uint32_t)(0x0000FFFFUL)) #define BITS_15 ((uint32_t)(0x00007FFFUL)) #define BITS_14 ((uint32_t)(0x00003FFFUL)) #define BITS_13 ((uint32_t)(0x00001FFFUL)) #define BITS_12 ((uint32_t)(0x00000FFFUL)) #define BITS_11 ((uint32_t)(0x000007FFUL)) #define BITS_10 ((uint32_t)(0x000003FFUL)) #define BITS_09 ((uint32_t)(0x000001FFUL)) #define BITS_08 ((uint32_t)(0x000000FFUL)) #define BITS_07 ((uint32_t)(0x0000007FUL)) #define BITS_06 ((uint32_t)(0x0000003FUL)) #define BITS_05 ((uint32_t)(0x0000001FUL)) #define BITS_04 ((uint32_t)(0x0000000FUL)) #define BITS_03 ((uint32_t)(0x00000007UL)) #define BITS_02 ((uint32_t)(0x00000003UL)) /******************************************************************************* Register Bit definitions */ /* General MAC Network Control register bit definitions */ /* eMAC Network Control register bit definitions */ #define GEM_IFG_EATS_QAV_CREDIT BIT_30 #define GEM_TWO_PT_FIVE_GIG BIT_29 #define GEM_SEL_MII_ON_RGMII BIT_28 #define GEM_OSS_CORRECTION_FIELD BIT_27 #define GEM_EXT_RXQ_SEL_EN BIT_26 #define GEM_PFC_CTRL BIT_25 #define GEM_ONE_STEP_SYNC_MODE BIT_24 #define GEM_EXT_TSU_PORT_ENABLE BIT_23 #define GEM_STORE_UDP_OFFSET BIT_22 #define GEM_ALT_SGMII_MODE BIT_21 #define GEM_PTP_UNICAST_ENA BIT_20 #define GEM_TX_LPI_EN BIT_19 #define GEM_FLUSH_RX_PKT_PCLK BIT_18 #define GEM_TRANSMIT_PFC_PRIORITY_BASED_PAUSE_FRAME BIT_17 #define GEM_PFC_ENABLE BIT_16 #define GEM_STORE_RX_TS BIT_15 #define GEM_TX_PAUSE_FRAME_ZERO BIT_12 #define GEM_TX_PAUSE_FRAME_REQ BIT_11 #define GEM_TRANSMIT_HALT BIT_10 #define GEM_TRANSMIT_START BIT_09 #define GEM_BACK_PRESSURE BIT_08 #define GEM_STATS_WRITE_EN BIT_07 #define GEM_INC_ALL_STATS_REGS BIT_06 #define GEM_CLEAR_ALL_STATS_REGS BIT_05 #define GEM_MAN_PORT_EN BIT_04 #define GEM_ENABLE_TRANSMIT BIT_03 #define GEM_ENABLE_RECEIVE BIT_02 #define GEM_LOOPBACK_LOCAL BIT_01 #define GEM_LOOPBACK BIT_00 /* General MAC Network Configuration register bit definitions */ /* eMAC Network Configuration register bit definitions */ #define GEM_UNI_DIRECTION_ENABLE BIT_31 #define GEM_IGNORE_IPG_RX_ER BIT_30 #define GEM_NSP_CHANGE BIT_29 #define GEM_IPG_STRETCH_ENABLE BIT_28 #define GEM_SGMII_MODE_ENABLE BIT_27 #define GEM_IGNORE_RX_FCS BIT_26 #define GEM_EN_HALF_DUPLEX_RX BIT_25 #define GEM_RECEIVE_CHECKSUM_OFFLOAD_ENABLE BIT_24 #define GEM_DISABLE_COPY_OF_PAUSE_FRAMES BIT_23 #define GEM_DATA_BUS_WIDTH (BIT_21 | BIT_22) #define GEM_MDC_CLOCK_DIVISOR (BIT_18 | BIT_19 | BIT_20) #define GEM_FCS_REMOVE BIT_17 #define GEM_LENGTH_FIELD_ERROR_FRAME_DISCARD BIT_16 #define GEM_RECEIVE_BUFFER_OFFSET (BIT_14 | BIT_15) #define GEM_PAUSE_ENABLE BIT_13 #define GEM_RETRY_TEST BIT_12 #define GEM_PCS_SELECT BIT_11 #define GEM_GIGABIT_MODE_ENABLE BIT_10 #define GEM_EXTERNAL_ADDRESS_MATCH_ENABLE BIT_09 #define GEM_RECEIVE_1536_BYTE_FRAMES BIT_08 #define GEM_UNICAST_HASH_ENABLE BIT_07 #define GEM_MULTICAST_HASH_ENABLE BIT_06 #define GEM_NO_BROADCAST BIT_05 #define GEM_COPY_ALL_FRAMES BIT_04 #define GEM_JUMBO_FRAMES BIT_03 #define GEM_DISCARD_NON_VLAN_FRAMES BIT_02 #define GEM_FULL_DUPLEX BIT_01 #define GEM_SPEED BIT_00 #define GEM_DATA_BUS_WIDTH_SHIFT 21 #define GEM_MDC_CLOCK_DIVISOR_SHIFT 18 #define GEM_MDC_CLOCK_DIVISOR_MASK BITS_03 #define GEM_RECEIVE_BUFFER_OFFSET_SHIFT 14 /* General MAC Network Status register bit definitions */ /* eMAC Network Status register bit definitions */ #define GEM_LPI_INDICATE_PCLK BIT_07 #define GEM_PFC_NEGOTIATE_PCLK BIT_06 #define GEM_MAC_PAUSE_TX_EN BIT_05 #define GEM_MAC_PAUSE_RX_EN BIT_04 #define GEM_MAC_FULL_DUPLEX BIT_03 #define GEM_MAN_DONE BIT_02 #define GEM_MDIO_IN BIT_01 #define GEM_PCS_LINK_STATE BIT_00 /* General MAC User IO register bit definitions */ #define GEM_CODEGROUP_BYPASS BIT_05 #define GEM_COMMA_BYPASS BIT_04 #define GEM_TSU_CLK_SOURCE BIT_00 /* General MAC DMA Config register bit definitions */ /* eMAC DMA Config register bit definitions */ #define GEM_DMA_ADDR_BUS_WIDTH_1 BIT_30 #define GEM_TX_BD_EXTENDED_MODE_EN BIT_29 #define GEM_RX_BD_EXTENDED_MODE_EN BIT_28 #define GEM_FORCE_MAX_AMBA_BURST_TX BIT_26 #define GEM_FORCE_MAX_AMBA_BURST_RX BIT_25 #define GEM_FORCE_DISCARD_ON_ERR BIT_24 #define GEM_RX_BUF_SIZE (BITS_08 << 16) #define GEM_CRC_ERROR_REPORT BIT_13 #define GEM_INFINITE_LAST_DBUF_SIZE_EN BIT_12 #define GEM_TX_PBUF_TCP_EN BIT_11 #define GEM_TX_PBUF_SIZE BIT_10 #define GEM_RX_PBUF_SIZE (BIT_08 | BIT_09) #define GEM_ENDIAN_SWAP_PACKET BIT_07 #define GEM_ENDIAN_SWAP_MANAGEMENT BIT_06 #define GEM_HDR_DATA_SPLITTING_EN BIT_05 #define GEM_AMBA_BURST_LENGTH BITS_05 #define GEM_RX_BUF_SIZE_SHIFT 16 #define GEM_RX_PBUF_SIZE_SHIFT 8 /* General MAC Transmit Status register bit definitions */ /* eMAC Transmit Status register bit definitions */ #define GEM_TX_DMA_LOCKUP_DETECTED BIT_10 #define GEM_TX_MAC_LOCKUP_DETECTED BIT_09 #define GEM_TX_RESP_NOT_OK BIT_08 #define GEM_LATE_COLLISION_OCCURRED BIT_07 #define GEM_STAT_TRANSMIT_UNDER_RUN BIT_06 #define GEM_STAT_TRANSMIT_COMPLETE BIT_05 #define GEM_STAT_AMBA_ERROR BIT_04 #define GEM_TRANSMIT_GO BIT_03 #define GEM_RETRY_LIMIT_EXCEEDED BIT_02 #define GEM_COLLISION_OCCURRED BIT_01 #define GEM_USED_BIT_READ BIT_00 /* General MAC Receive Queue Pointer register bit definitions */ /* General MAC Receive Queue 1 Pointer register bit definitions */ /* General MAC Receive Queue 2 Pointer register bit definitions */ /* General MAC Receive Queue 3 Pointer register bit definitions */ /* eMAC Receive Queue Pointer register bit definitions */ #define GEM_DMA_RX_Q_PTR (~(BIT_00 | BIT_01)) #define GEM_DMA_RX_DIS_Q BIT_00 /* General MAC Transmit Queue Pointer register bit definitions */ /* General MAC Transmit Queue 1 Pointer register bit definitions */ /* General MAC Transmit Queue 2 Pointer register bit definitions */ /* General MAC Transmit Queue 3 Pointer register bit definitions */ /* eMAC Transmit Queue Pointer register bit definitions */ #define GEM_DMA_TX_Q_PTR (~(BIT_00 | BIT_01)) #define GEM_DMA_TX_DIS_Q BIT_00 /* General MAC Receive Status register bit definitions */ /* eMAC Receive Status register bit definitions */ #define GEM_RX_DMA_LOCKUP_DETECTED BIT_05 #define GEM_RX_MAC_LOCKUP_DETECTED BIT_04 #define GEM_RX_RESP_NOT_OK BIT_03 #define GEM_RECEIVE_OVERRUN BIT_02 #define GEM_FRAME_RECEIVED BIT_01 #define GEM_BUFFER_NOT_AVAILABLE BIT_00 /* General MAC Interrupt Status register bit definitions */ /* General MAC Interrupt Enable register bit definitions */ /* General MAC Interrupt Disable register bit definitions */ /* General MAC Interrupt Mask register bit definitions */ /* General MAC Priority Queue 1 Interrupt Status register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 2 Interrupt Status register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 3 Interrupt Status register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 1 Interrupt Enable register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 2 Interrupt Enable register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 3 Interrupt Enable register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 1 Interrupt Disable register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 2 Interrupt Disable register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 3 Interrupt Disable register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 1 Interrupt Mask register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 2 Interrupt Mask register bit definitions - b01 to b11 only */ /* General MAC Priority Queue 3 Interrupt Mask register bit definitions - b01 to b11 only */ /* eMAC Interrupt Status register bit definitions */ /* eMAC Interrupt Enable register bit definitions */ /* eMAC Interrupt Disable register bit definitions */ /* eMAC Interrupt Mask register bit definitions */ #define GEM_TX_LOCKUP_DETECTED BIT_31 #define GEM_RX_LOCKUP_DETECTED BIT_30 #define GEM_TSU_TIMER_COMPARISON_INTERRUPT BIT_29 #define GEM_WOL_INTERRUPT BIT_28 #define GEM_RX_LPI_INDICATION_STATUS_BIT_CHANGE BIT_27 #define GEM_TSU_SECONDS_REGISTER_INCREMENT BIT_26 #define GEM_PTP_PDELAY_RESP_FRAME_TRANSMITTED BIT_25 #define GEM_PTP_PDELAY_REQ_FRAME_TRANSMITTED BIT_24 #define GEM_PTP_PDELAY_RESP_FRAME_RECEIVED BIT_23 #define GEM_PTP_PDELAY_REQ_FRAME_RECEIVED BIT_22 #define GEM_PTP_SYNC_FRAME_TRANSMITTED BIT_21 #define GEM_PTP_DELAY_REQ_FRAME_TRANSMITTED BIT_20 #define GEM_PTP_SYNC_FRAME_RECEIVED BIT_19 #define GEM_PTP_DELAY_REQ_FRAME_RECEIVED BIT_18 #define GEM_PCS_LINK_PARTNER_PAGE_RECEIVED BIT_17 #define GEM_PCS_AUTO_NEGOTIATION_COMPLETE BIT_16 #define GEM_EXTERNAL_INTERRUPT BIT_15 #define GEM_PAUSE_FRAME_TRANSMITTED BIT_14 #define GEM_PAUSE_TIME_ELAPSED BIT_13 #define GEM_PAUSE_FRAME_WITH_NON_0_PAUSE_QUANTUM_RX BIT_12 #define GEM_RESP_NOT_OK_INT BIT_11 #define GEM_RECEIVE_OVERRUN_INT BIT_10 #define GEM_LINK_CHANGE BIT_09 #define GEM_TRANSMIT_COMPLETE BIT_07 #define GEM_AMBA_ERROR BIT_06 #define GEM_RETRY_LIMIT_EXCEEDED_OR_LATE_COLLISION BIT_05 #define GEM_TRANSMIT_UNDER_RUN BIT_04 #define GEM_TX_USED_BIT_READ BIT_03 #define GEM_RX_USED_BIT_READ BIT_02 #define GEM_RECEIVE_COMPLETE BIT_01 #define GEM_MANAGEMENT_FRAME_SENT BIT_00 /* * General MAC Fatal or Non Fatal Interrupt register bit definitions * Note bits 0 to 15 are as per interrupt mask etc registers above. */ #define GEM_LOCKUP_DETECTED_INT_TYPE BIT_22 #define GEM_TSU_TIMER_COMPARISON_INTERRUPT_INT_TYPE BIT_21 #define GEM_WOL_INTERRUPT_INT_TYPE BIT_20 #define GEM_RECEIVE_LPI_INT_TYPE BIT_19 #define GEM_TSU_SECONDS_REGISTER_INCREMENT_INT_TYPE BIT_18 #define GEM_PTP_FRAME_RECEIVED_INT_TYPE BIT_17 #define GEM_PCS_INT_TYPE BIT_16 /* General MAC Phy Management register bit definitions */ /* eMAC Phy Management register bit definitions */ #define GEM_WRITE0 BIT_31 #define GEM_WRITE1 BIT_30 #define GEM_OPERATION (BIT_28 | BIT_29) #define GEM_PHY_ADDRESS (BITS_05 << 23) #define GEM_REGISTER_ADDRESS (BITS_05 << 18) #define GEM_WRITE10 (BIT_16 | BIT_17) #define GEM_PHY_WRITE_READ_DATA BITS_16 #define GEM_PHY_OP_CL22_WRITE ((uint32_t)(1UL)) #define GEM_PHY_OP_CL22_READ ((uint32_t)(2UL)) #define GEM_PHY_OP_CL45_ADDRESS ((uint32_t)(0UL)) #define GEM_PHY_OP_CL45_WRITE ((uint32_t)(1UL)) #define GEM_PHY_OP_CL45_POST_READ_INC ((uint32_t)(2UL)) #define GEM_PHY_OP_CL45_READ ((uint32_t)(3UL)) #define GEM_OPERATION_SHIFT 28 #define GEM_PHY_ADDRESS_SHIFT 23 #define GEM_REGISTER_ADDRESS_SHIFT 18 #define GEM_WRITE10_SHIFT 16 /* General MAC Pause Time register bit definitions */ /* General MAC Transmit Pause Time register bit definitions */ /* eMAC Pause Time register bit definitions */ /* eMAC Transmit Pause Time register bit definitions */ #define GEM_QUANTUM BITS_16 /* General MAC PBuff TX Cutthru register bit definitions */ /* General MAC PBuff RX Cutthru register bit definitions */ /* eMAC PBuff TX Cutthru register bit definitions */ /* eMAC PBuff RX Cutthru register bit definitions */ #define GEM_DMA_CUTTHRU BIT_31 #define GEM_DMA_TX_CUTTHRU_THRESHOLD BITS_11 #define GEM_DMA_RX_CUTTHRU_THRESHOLD BITS_10 #define GEM_DMA_EMAC_CUTTHRU_THRESHOLD BITS_09 /* General MAC Jumbo Max Length register bit definitions */ /* eMAC Jumbo Max Length register bit definitions */ #define GEM_JUMBO_MAX_LENGTH BITS_14 /* General MAC AXI Max Pipeline register bit definitions */ /* eMAC AXI Max Pipeline register bit definitions */ #define GEM_USE_AW2B_FILL BIT_16 #define GEM_AW2W_MAX_PIPELINE (BITS_08 << 8) #define GEM_AR2R_MAX_PIPELINE BITS_08 /* General MAC Int Moderation register bit definitions */ /* eMAC Int Moderation register bit definitions */ #define GEM_TX_INT_MODERATION (BITS_08 << 16) #define GEM_RX_INT_MODERATION BITS_08 /* General MAC Sys Wake Time register bit definitions */ /* eMAC Sys Wake Time register bit definitions */ #define GEM_SYS_WAKE_TIME BITS_16 /* General MAC Lockup Config register bit definitions */ /* General RX MAC Lockup Time register bit definitions */ /* eMAC Lockup Config register bit definitions */ /* RX eMAC Lockup Time register bit definitions */ #define GEM_TX_DMA_LOCKUP_MON_EN BIT_31 #define GEM_TX_MAC_LOCKUP_MON_EN BIT_30 #define GEM_RX_DMA_LOCKUP_MON_EN BIT_29 #define GEM_RX_MAC_LOCKUP_MON_EN BIT_28 #define GEM_LOCKUP_RECOVERY_EN BIT_27 #define GEM_LOCKUP_TIME BITS_16 /* General MAC Specific Address 1 Top register bit definitions */ /* General MAC Specific Address 2 Top register bit definitions */ /* General MAC Specific Address 3 Top register bit definitions */ /* General MAC Specific Address 4 Top register bit definitions */ /* eMAC Specific Address 1 Top register bit definitions */ /* eMAC Specific Address 2 Top register bit definitions */ /* eMAC Specific Address 3 Top register bit definitions */ /* eMAC Specific Address 4 Top register bit definitions */ #define GEM_FILTER_BYTE_MASK (BITS_06 << 24) #define GEM_FILTER_TYPE BIT_16 #define GEM_SPEC_ADDRESS BITS_16 /* General MAC Specific Address Type 1 register bit definitions */ /* General MAC Specific Address Type 2 register bit definitions */ /* General MAC Specific Address Type 3 register bit definitions */ /* General MAC Specific Address Type 4 register bit definitions */ /* eMAC Specific Address Type 1 register bit definitions */ /* eMAC Specific Address Type 2 register bit definitions */ /* eMAC Specific Address Type 3 register bit definitions */ /* eMAC Specific Address Type 4 register bit definitions */ #define GEM_ENABLE_COPY BIT_31 #define GEM_SPEC_ADDR_MATCH BITS_16 /* General MAC Wake On LAN register bit definitions */ /* eMAC Wake On LAN register bit definitions */ #define GEM_WOL_MULTICAST_HASH BIT_19 #define GEM_WOL_SPEC_ADDRESS_1 BIT_18 #define GEM_WOL_ARP_REQUEST BIT_17 #define GEM_WOL_MAGIC_PACKET BIT_16 #define GEM_WOL_ADDRESS BITS_16 /* General MAC Stretch Ratio register bit definitions */ /* eMAC Stretch Ratio register bit definitions */ #define GEM_IPG_STRETCH BITS_16 #define GEM_IPG_STRETCH_DIV (BITS_8 << 8) #define GEM_IPG_STRETCH_MUL BITS_08 #define GEM_IPG_STRETCH_DIV_MASK BITS_08 #define GEM_IPG_STRETCH_DIV_SHIFT 8 #define GEM_IPG_STRETCH_MUL_MASK BITS_08 /* General MAC Stacked VLAN register bit definitions */ /* eMAC Stacked VLAN register bit definitions */ #define GEM_ENABLE_PROCESSING BIT_31 #define GEM_VLAN_MATCH BITS_16 #define GEM_VLAN_C_TAG (0x8100U) #define GEM_VLAN_S_TAG (0x88A8U) /* Valid EtherTypes including VLAN tags must be bigger than this */ #define GEM_VLAN_ETHERTYPE_MIN (1536U) #define GEM_VLAN_NO_STACK (0U) /* General MAC Transmit PFC Pause register bit definitions */ /* eMAC Transmit PFC Pause register bit definitions */ #define GEM_VECTOR (BITS_08 << 8) #define GEM_VECTOR_ENABLE BITS_08 /* General MAC Specific Address Type 1 Mask register bit definitions */ /* eMAC Specific Address Type 1 Mask register bit definitions */ #define GEM_SPEC_ADDR_MASK BITS_16 /* General MAC Receive DMA Data Buffer Address Mask register bit definitions */ /* eMAC Receive DMA Data Buffer Address Mask register bit definitions */ #define GEM_DMA_DBUF_ADDR_MASK_VALUE (BITS_04 << 28) #define GEM_DMA_DBUF_ADDR_MASK_ENABLE BITS_04 /* General MAC TSU timer comparison value nanosecond register bit definitions */ /* eMAC TSU timer comparison value nanosecond register bit definitions */ #define GEM_NSEC_COMPARISON_VALUE BITS_22 /* General MAC TSU timer comparison value seconds 47:32 register bit definitions */ /* General MAC PTP Event Frame Transmitted Seconds Register 47:32 register bit definitions */ /* General MAC PTP Event Frame Received Seconds Register 47:32 register bit definitions */ /* General MAC PTP Peer Event Frame Transmitted Seconds Register 47:32 register bit definitions */ /* General MAC PTP Peer Event Frame Received Seconds Register 47:32 register bit definitions */ /* eMAC TSU timer comparison value seconds 47:32 register bit definitions */ /* eMAC PTP Event Frame Transmitted Seconds Register 47:32 register bit definitions */ /* eMAC PTP Event Frame Received Seconds Register 47:32 register bit definitions */ /* eMAC PTP Peer Event Frame Transmitted Seconds Register 47:32 register bit definitions */ /* eMAC PTP Peer Event Frame Received Seconds Register 47:32 register bit definitions */ #define GEM_SEC_VALUE_UPPER BITS_16 /* General MAC DP RAM Fill Debug register bit definitions */ /* eMAC DP RAM Fill Debug register bit definitions */ #define GEM_DMA_TX_RX_FILL_LEVEL (BITS_16 << 16) #define GEM_DMA_TX_Q_FILL_LEVEL_SELECT (BITS_04 << 4) #define GEM_DMA_TX_RX_FILL_LEVEL_SELECT BIT_00 /* General MAC Revision register bit definitions */ /* eMAC Revision register bit definitions */ #define GEM_FIX_NUMBER (BITS_04 << 24) #define GEM_MODULE_IDENTIFICATION_NUMBER (BITS_12 << 16) #define GEM_MODULE_REVISION BITS_16 /* General MAC Octets Transmitted Top register bit definitions */ /* General MAC Octets Received Top register bit definitions */ /* eMAC Octets Transmitted Top register bit definitions */ /* eMAC Octets Received Top register bit definitions */ #define GEM_UPPER_BITS_OF_48 BITS_16 /* General MAC Pause Frames Transmitted register bit definitions */ /* General MAC Pause Frames Received register bit definitions */ /* eMAC Pause Frames Transmitted register bit definitions */ /* eMAC Pause Frames Received register bit definitions */ #define GEM_FRAME_COUNT BITS_16 /* General MAC Transmit Underruns register bit definitions */ /* eMAC Transmit Underruns register bit definitions */ #define GEM_UNDERRUN_COUNT BITS_10 /* General MAC Single Collision register bit definitions */ /* General MAC Multiple Collisions register bit definitions */ /* eMAC Single Collision register bit definitions */ /* eMAC Multiple Collisions register bit definitions */ #define GEM_SM_COLLISION_COUNT BITS_18 /* General MAC Late Collisions register bit definitions */ /* eMAC Late Collisions register bit definitions */ #define GEM_LATE_COLLISION_COUNT BITS_10 /* General MAC Deferred Frames register bit definitions */ /* eMAC Deferred Frames register bit definitions */ #define GEM_DEFERRED_FRAMES_COUNT BITS_18 /* General MAC CRS Errors register bit definitions */ /* eMAC CRS Errors register bit definitions */ #define GEM_CRS_ERROR_COUNT BITS_10 /* General MAC Undersize Frames Received register bit definitions */ /* eMAC Undersize Frames Received register bit definitions */ #define GEM_RUNT_FRAME_COUNT BITS_10 /* General MAC Oversize Frames Received register bit definitions */ /* eMAC Oversize Frames Received register bit definitions */ #define GEM_OVERSIZE_FRAME_COUNT BITS_10 /* General MAC Jabbers Received register bit definitions */ /* eMAC Jabbers Received register bit definitions */ #define GEM_JABBER_COUNT BITS_10 /* General MAC FCS Error register bit definitions */ /* eMAC FCS Error register bit definitions */ #define GEM_FCS_ERROR_COUNT BITS_10 /* General MAC Length Field Frame Errors register bit definitions */ /* eMAC Length Field Frame Errors register bit definitions */ #define GEM_LENGTH_ERROR_COUNT BITS_10 /* General MAC Receive Symbol Errors register bit definitions */ /* eMAC Receive Symbol Errors register bit definitions */ #define GEM_SYMBOL_ERROR_COUNT BITS_10 /* General MAC Receive Alignment Errors register bit definitions */ /* eMAC Receive Alignment Errors register bit definitions */ #define GEM_ALIGNMENT_ERROR_COUNT BITS_10 /* General MAC Receive Resource Error register bit definitions */ /* eMAC Receive Resource Error register bit definitions */ #define GEM_RESOURCE_ERROR_COUNT BITS_10 /* General MAC Receive Overrun register bit definitions */ /* eMAC Receive Overrun register bit definitions */ #define GEM_OVERRUN_COUNT BITS_10 /* General MAC IP Checksum Error register bit definitions */ /* General MAC TCP Checksum Error register bit definitions */ /* General MAC UDP Checksum Error register bit definitions */ /* eMAC IP Checksum Error register bit definitions */ /* eMAC TCP Checksum Error register bit definitions */ /* eMAC UDP Checksum Error register bit definitions */ #define GEM_IP_CHECKSUM_ERROR_COUNT BITS_08 /* General MAC Auto Flushed Packets register bit definitions */ /* eMAC Auto Flushed Packets register bit definitions */ #define GEM_AUTO_FLUSHED_COUNT BITS_16 /* General MAC TSU Timer Increment Sub Nanoseconds register bit definitions */ /* eMAC TSU Timer Increment Sub Nanoseconds register bit definitions */ #define GEM_SUB_NS_INCR_LSB (BITS_08 << 24) #define GEM_SUB_NS_INCR BITS_16 /* General MAC TSU Timer Seconds MSB register bit definitions */ /* General MAC TSU Strobe Seconds MSB register bit definitions */ #define GEM_TSU_SECONDS_MSB BITS_16 /* General MAC TSU Timer Sync Strobe Nanoseconds register bit definitions */ /* General MAC TSU Timer Nanoseconds register bit definitions */ /* General MAC TSU Timer Adjust register bit definitions */ /* General MAC PTP Event Frame Transmitted Nanoseconds register bit definitions */ /* General MAC PTP Event Frame Received Nanoseconds register bit definitions */ /* General MAC PTP Peer Event Frame Transmitted Nanoseconds register bit definitions */ /* General MAC PTP Peer Event Frame Received Nanoseconds register bit definitions */ /* eMAC TSU Timer Sync Strobe Nanoseconds register bit definitions */ /* eMAC TSU Timer Nanoseconds register bit definitions */ /* eMAC TSU Timer Adjust register bit definitions */ /* eMAC PTP Event Frame Transmitted Nanoseconds register bit definitions */ /* eMAC PTP Event Frame Received Nanoseconds register bit definitions */ /* eMAC PTP Peer Event Frame Transmitted Nanoseconds register bit definitions */ /* eMAC PTP Peer Event Frame Received Nanoseconds register bit definitions */ #define GEM_ADD_SUBTRACT BIT_31 /* Adjust register only... */ #define GEM_TSU_NANOSECONDS BITS_30 /* General MAC TSU Timer Adjust register bit definitions */ /* eMAC TSU Timer Adjust register bit definitions */ #define GEM_NUM_INCS (BITS_08 << 16) #define GEM_ALT_NS_INC (BITS_08 << 8) #define GEM_NS_INCREMENT BITS_08 /* General MAC PCS Control register bit definitions */ #define GEM_PCS_SOFTWARE_RESET BIT_15 #define GEM_LOOPBACK_MODE BIT_14 #define GEM_SPEED_SELECT_BIT_1 BIT_13 #define GEM_ENABLE_AUTO_NEG BIT_12 #define GEM_RESTART_AUTO_NEG BIT_09 #define GEM_MAC_DUPLEX_STATE BIT_08 #define GEM_COLLISION_TEST BIT_07 #define GEM_SPEED_SELECT_BIT_0 BIT_06 /* General MAC PCS Status register bit definitions */ #define GEM_BASE_100_T4 BIT_15 #define GEM_BASE_100_X_FULL_DUPLEX BIT_14 #define GEM_BASE_100_X_HALF_DUPLEX BIT_13 #define GEM_MBPS_10_FULL_DUPLEX BIT_12 #define GEM_MBPS_10_HALF_DUPLEX BIT_11 #define GEM_BASE_100_T2_FULL_DUPLEX BIT_10 #define GEM_BASE_100_T2_HALF_DUPLEX BIT_09 #define GEM_EXTENDED_STATUS BIT_08 #define GEM_AUTO_NEG_COMPLETE BIT_05 #define GEM_REMOTE_FAULT BIT_04 #define GEM_AUTO_NEG_ABILITY BIT_03 #define GEM_LINK_STATUS BIT_02 #define GEM_EXTENDED_CAPABILITIES BIT_00 /* General MAC PCS PHY Top ID register bit definitions */ /* General MAC PCS PHY Bottom ID register bit definitions */ #define GEM_ID_CODE BITS_16 /* General MAC PCS Autonegotiation Advertisment register bit definitions */ #define GEM_AN_AV_NEXT_PAGE BIT_15 #define GEM_AN_AV_REMOTE_FAULT (BIT_12 | BIT_13) #define GEM_AN_AV_PAUSE (BIT_08 | BIT_07) #define GEM_AN_AV_HALF_DUPLEX BIT_06 #define GEM_AN_AV_FULL_DUPLEX BIT_05 /* General MAC PCS Autonegotiation Link Partner Base register bit definitions */ #define GEM_LINK_PARTNER_NEXT_PAGE_STATUS BIT_15 #define GEM_LINK_PARTNER_ACKNOWLEDGE BIT_14 #define GEM_LINK_PARTNER_REMOTE_FAULT_DUPLEX_MODE (BIT_12 | BIT_13) #define GEM_LINK_PARTNER_SPEED (BIT_10 | BIT_11) #define GEM_LINK_PARTNER_PAUSE (BIT_07 | BIT_08) #define GEM_LINK_PARTNER_HALF_DUPLEX BIT_06 #define GEM_LINK_PARTNER_FULL_DUPLEX BIT_05 /* General MAC PCS Autonegotiation Next Page Ability register bit definitions */ #define GEM_NEXT_PAGE_CAPABILITY BIT_02 #define GEM_PAGE_RECEIVED BIT_01 /* General MAC PCS Autonegotiation Next Page Transmit register bit definitions */ /* General MAC PCS Autonegotiation Next Page Receive register bit definitions */ #define GEM_NEXT_PAGE_TO_TRANSMIT BIT_15 #define GEM_NEXT_PAGE_TO_RECEIVE BIT_15 #define GEM_ACKNOWLEDGE BIT_14 #define GEM_MESSAGE_PAGE_INDICATOR BIT_13 #define GEM_ACKNOWLEDGE_2 BIT_12 #define GEM_TOGGLE BIT_11 #define GEM_AN_MESSAGE BITS_11 /* General MAC PCS Autonegotiation Extended Status register bit definitions */ #define GEM_FULL_DUPLEX_1000BASE_X BIT_15 #define GEM_HALF_DUPLEX_1000BASE_X BIT_14 #define GEM_FULL_DUPLEX_1000BASE_T BIT_13 #define GEM_HALF_DUPLEX_1000BASE_T BIT_12 /* General MAC Received LPI Transitions register bit definitions */ /* General MAC Transmitted LPI Transitions register bit definitions */ /* eMAC Received LPI Transitions register bit definitions */ /* eMAC Transmitted LPI Transitions register bit definitions */ #define GEM_LPI_COUNT BITS_16 /* General MAC Received LPI Time register bit definitions */ /* General MAC Transmitted LPI Time register bit definitions */ /* eMAC Received LPI Time register bit definitions */ /* eMAC Transmitted LPI Time register bit definitions */ #define GEM_LPI_TIME BITS_24 /* General MAC Design Configuration Debug 1 register bit definitions */ /* eMAC Design Configuration Debug 1 register bit definitions */ #define GEM_AXI_CACHE_VALUE (BITS_04 << 28) #define GEM_DMA_BUS_WIDTH (BIT_25 | BIT_26 | BIT 27) #define GEM_EXCLUDE_CBS BIT_24 #define GEM_IRQ_READ_CLEAR BIT_23 #define GEM_NO_SNAPSHOT BIT_22 #define GEM_NO_STATS BIT_21 #define GEM_USER_IN_WIDTH (BITS_05 << 15) #define GEM_USER_OUT_WIDTH (BITS_05 << 10) #define GEM_USER_IO BIT_09 #define GEM_EXT_FIFO_INTERFACE BIT_06 #define GEM_INT_LOOPBACK BIT_04 #define GEM_EXCLUDE_QBV BIT_01 #define GEM_NO_PCS BIT_00 /* General MAC Design Configuration Debug 2 register bit definitions */ /* eMAC Design Configuration Debug 2 register bit definitions */ #define GEM_SPRAM BIT_31 #define GEM_AXI BIT_30 #define GEM_TX_PBUF_ADDR (BITS_04 << 26) #define GEM_RX_PBUF_ADDR (BITS_04 << 22) #define GEM_TX_PKT_BUFFER BIT_21 #define GEM_RX_PKT_BUFFER BIT_20 #define GEM_HPROT_VALUE (BITS_04 << 16) #define GEM_JUMBO_MAX_LENGTH BITS_14 /* General MAC Design Configuration Debug 3 register bit definitions */ /* eMAC Design Configuration Debug 3 register bit definitions */ #define GEM_NUM_SPEC_ADD_FILTERS (BITS_06 << 24) /* General MAC Design Configuration Debug 5 register bit definitions */ /* eMAC Design Configuration Debug 5 register bit definitions */ #define GEM_AXI_PROT_VALUE (BIT_29 | BIT_30 | BIT_31) #define GEM_TSU_CLK BIT_28 #define GEM_RX_BUFFER_LENGTH_DEF (BITS_08 << 20) #define GEM_TX_PBUF_SIZE_DEF BIT_19 #define GEM_RX_PBUF_SIZE_DEF (BIT_17 | BIT_18) #define GEM_ENDIAN_SWAP_DEF (BIT_15 | BIT_16) #define GEM_MDC_CLOCK_DIV (BIT_12 | BIT_13 | BIT_14) #define GEM_DMA_BUS_WIDTH_DEF (BIT_10 | BIT_11) #define GEM_PHY_IDENT BIT_09 #define GEM_TSU BIT_08 #define GEM_TX_FIFO_CNT_WIDTH (BITS_04 << 4) #define GEM_RX_FIFO_CNT_WIDTH BITS_04 /* General MAC Design Configuration Debug 6 register bit definitions */ /* eMAC Design Configuration Debug 6 register bit definitions */ #define GEM_PBUF_LSO BIT_27 #define GEM_PBUF_RSC BIT_26 #define GEM_PBUF_CUTTHRU BIT_25 #define GEM_PFC_MULTI_QUANTUM BIT_24 #define GEM_DMA_ADDR_WIDTH_IS_64B BIT_23 #define GEM_HOST_IF_SOFT_SEL BIT_22 #define GEM_TX_ADD_FIFO_IF BIT_21 #define GEM_EXT_TSU_TIMER BIT_20 #define GEM_TX_PBUF_QUEUE_SEGMENT_SIZE (BITS_04 << 16) #define GEM_DMA_PRIORITY_QUEUE15 BIT_15 #define GEM_DMA_PRIORITY_QUEUE14 BIT_14 #define GEM_DMA_PRIORITY_QUEUE13 BIT_13 #define GEM_DMA_PRIORITY_QUEUE12 BIT_12 #define GEM_DMA_PRIORITY_QUEUE11 BIT_11 #define GEM_DMA_PRIORITY_QUEUE10 BIT_10 #define GEM_DMA_PRIORITY_QUEUE9 BIT_09 #define GEM_DMA_PRIORITY_QUEUE8 BIT_08 #define GEM_DMA_PRIORITY_QUEUE7 BIT_07 #define GEM_DMA_PRIORITY_QUEUE6 BIT_06 #define GEM_DMA_PRIORITY_QUEUE5 BIT_05 #define GEM_DMA_PRIORITY_QUEUE4 BIT_04 #define GEM_DMA_PRIORITY_QUEUE3 BIT_03 #define GEM_DMA_PRIORITY_QUEUE2 BIT_02 #define GEM_DMA_PRIORITY_QUEUE1 BIT_01 /* General MAC Design Configuration Debug 7 register bit definitions */ /* eMAC Design Configuration Debug 7 register bit definitions */ #define GEM_TX_PBUF_NUM_SEGMENTS_Q7 (BITS_04 << 28) #define GEM_TX_PBUF_NUM_SEGMENTS_Q6 (BITS_04 << 24) #define GEM_TX_PBUF_NUM_SEGMENTS_Q5 (BITS_04 << 20) #define GEM_TX_PBUF_NUM_SEGMENTS_Q4 (BITS_04 << 16) #define GEM_TX_PBUF_NUM_SEGMENTS_Q3 (BITS_04 << 12) #define GEM_TX_PBUF_NUM_SEGMENTS_Q2 (BITS_04 << 8) #define GEM_TX_PBUF_NUM_SEGMENTS_Q1 (BITS_04 << 4) #define GEM_TX_PBUF_NUM_SEGMENTS_Q0 BITS_04 /* General MAC Design Configuration Debug 8 register bit definitions */ /* eMAC Design Configuration Debug 8 register bit definitions */ #define GEM_NUM_TYPE1_SCREENERS (BITS_08 << 24) #define GEM_NUM_TYPE2_SCREENERS (BITS_08 << 16) #define GEM_NUM_SCR2_ETHTYPE_REGS (BITS_08 << 8) #define GEM_NUM_SCR2_COMPARE_REGS BITS_08 /* General MAC Design Configuration Debug 9 register bit definitions */ /* eMAC Design Configuration Debug 9 register bit definitions */ #define GEM_TX_PBUF_NUM_SEGMENTS_Q15 (BITS_04 << 28) #define GEM_TX_PBUF_NUM_SEGMENTS_Q14 (BITS_04 << 24) #define GEM_TX_PBUF_NUM_SEGMENTS_Q13 (BITS_04 << 20) #define GEM_TX_PBUF_NUM_SEGMENTS_Q12 (BITS_04 << 16) #define GEM_TX_PBUF_NUM_SEGMENTS_Q11 (BITS_04 << 12) #define GEM_TX_PBUF_NUM_SEGMENTS_Q10 (BITS_04 << 8) #define GEM_TX_PBUF_NUM_SEGMENTS_Q9 (BITS_04 << 4) #define GEM_TX_PBUF_NUM_SEGMENTS_Q8 BITS_04 /* General MAC Design Configuration Debug 10 register bit definitions */ /* eMAC Design Configuration Debug 10 register bit definitions */ #define GEM_EMAC_BUS_WIDTH (BITS_04 << 28) #define GEM_TX_PBUF_DATA (BITS_04 << 24) #define GEM_RX_PBUF_DATA (BITS_04 << 20) #define GEM_AXI_ACCESS_PIPELINE_BITS (BITS_04 << 16) #define GEM_AXI_TX_DESCR_RD_BUFF_BITS (BITS_04 << 12) #define GEM_AXI_RX_DESCR_RD_BUFF_BITS (BITS_04 << 8) #define GEM_AXI_TX_DESCR_WR_BUFF_BITS (BITS_04 << 4) #define GEM_AXI_RX_DESCR_WR_BUFF_BITS BITS_04 /* General MAC Design Configuration Debug 11 register bit definitions */ /* eMAC Design Configuration Debug 11 register bit definitions */ #define GEM_PROTECT_DESCR_ADDR BIT_04 #define GEM_PROTECT_TSU BIT_03 #define GEM_ADD_CSR_PARITY BIT_02 #define GEM_ADD_DP_PARITY BIT_01 #define GEM_ADD_ECC_DPRAM BIT_00 /* General MAC Design Configuration Debug 12 register bit definitions */ /* eMAC Design Configuration Debug 12 register bit definitions */ #define GEM_GEM_HAS_802P3_BR BIT_25 #define GEM_EMAC_TX_PBUF_ADDR (BITS_04 << 21) #define GEM_EMAC_RX_PBUF_ADDR (BITS_04 << 17) #define GEM_GEM_HAS_CB BIT_16 #define GEM_GEM_CB_HISTORY_LEN (BITS_08 << 8) #define GEM_GEM_NUM_CB_STREAMS BITS_08 /* General MAC Queue 1 DMA Receive Buffer Size register bit definitions */ /* General MAC Queue 2 DMA Receive Buffer Size register bit definitions */ /* General MAC Queue 3 DMA Receive Buffer Size register bit definitions */ #define GEM_DMA_RX_Q_BUF_SIZE BITS_08 /* General MAC CBS Control register bit definitions */ /* eMAC CBS Control register bit definitions */ #define GEM_CBS_ENABLE_QUEUE_B BIT_01 #define GEM_CBS_ENABLE_QUEUE_A BIT_00 /* General MAC TX BD Control register bit definitions */ /* General MAC RX BD Control register bit definitions */ /* eMAC TX BD Control register bit definitions */ /* eMAC RX BD Control register bit definitions */ #define GEM_BD_TS_MODE (BIT_04 | BIT_05) #define GEM_BD_TS_MODE_SHIFT 4 /* General MAC WD Counter register bit definitions */ #define GEM_RX_BD_REREAD_TIMER BITS_04 /* General MAC AXI TX Full Threshold 0 register bit definitions */ #define GEM_AXI_TX_FULL_ADJ_0 (BITS_11 << 16) #define GEM_AXI_TX_FULL_ADJ_1 BITS_11 /* General MAC AXI TX Full Threshold 1 register bit definitions */ #define GEM_AXI_TX_FULL_ADJ_2 (BITS_11 << 16) #define GEM_AXI_TX_FULL_ADJ_3 BITS_11 /* General Screening Type 1 Register register bit definitions */ #define GEM_DROP_ON_MATCH BIT_30 #define GEM_UDP_PORT_MATCH_ENABLE BIT_29 #define GEM_DSTC_ENABLE BIT_28 #define GEM_UDP_PORT_MATCH (BITS_16 << 12) #define GEM_DSTC_MATCH (BITS_08 << 4) #define GEM_QUEUE_NUMBER BITS_04 #define GEM_UDP_PORT_MATCH_SHIFT 12 #define GEM_DSTC_MATCH_SHIFT 4 /* General Screening Type 2 Register register bit definitions */ #define GEM_T2_DROP_ON_MATCH BIT_31 #define GEM_COMPARE_C_ENABLE BIT_30 #define GEM_COMPARE_C (BITS_05 << 25) #define GEM_COMPARE_B_ENABLE BIT_24 #define GEM_COMPARE_B (BITS_05 << 19) #define GEM_COMPARE_A_ENABLE BIT_18 #define GEM_COMPARE_A (BITS_05 << 13) #define GEM_ETHERTYPE_ENABLE BIT_12 #define GEM_ETHERTYPE_REG_INDEX (BITS_03 << 9) #define GEM_VLAN_ENABLE BIT_08 #define GEM_VLAN_PRIORITY (BITS_03 << 4) #define GEM_COMPARE_C_SHIFT 25 #define GEM_COMPARE_B_SHIFT 19 #define GEM_COMPARE_A_SHIFT 13 #define GEM_ETHERTYPE_REG_INDEX_SHIFT 9 #define GEM_VLAN_PRIORITY_SHIFT 4 /* General MAC TX Schedule Control register bit definitions */ #define GEM_TX_SCHED_Q3 (BIT_06 | BIT_07) #define GEM_TX_SCHED_Q2 (BIT_04 | BIT_05) #define GEM_TX_SCHED_Q1 (BIT_02 | BIT_03) #define GEM_TX_SCHED_Q0 (BIT_00 | BIT_01) /* General MAC TX Bandwidth Rate Limit Queue 0 to 3 register bit definitions */ #define GEM_DWRR_ETS_WEIGHT_Q3 (BITS_08 << 24) #define GEM_DWRR_ETS_WEIGHT_Q2 (BITS_08 << 16) #define GEM_DWRR_ETS_WEIGHT_Q1 (BITS_08 << 8) #define GEM_DWRR_ETS_WEIGHT_Q0 BITS_08 /* General MAC TX Queue Segment Alloc Queue 0 to 3 register bit definitions */ #define GEM_SEGMENT_ALLOC_Q3 (BIT_12 | BIT_13 | BIT_14) #define GEM_SEGMENT_ALLOC_Q2 (BIT_08 | BIT_09 | BIT_10) #define GEM_SEGMENT_ALLOC_Q1 (BIT_04 | BIT_05 | BIT_06) #define GEM_SEGMENT_ALLOC_Q0 (BIT_00 | BIT_01 | BIT_02) /* General MAC Screening Type 2 Ethertype Reg 0 register bit definitions */ #define GEM_COMPARE_VALUE BITS_16 /* General MAC Type 2 Compare 0 Word 0 register bit definitions */ /* eMAC Type 2 Compare 0 Word 0 register bit definitions */ /* eMAC Type 2 Compare 1 Word 0 register bit definitions */ /* eMAC Type 2 Compare 2 Word 0 register bit definitions */ /* eMAC Type 2 Compare 3 Word 0 register bit definitions */ /* eMAC Type 2 Compare 4 Word 0 register bit definitions */ /* eMAC Type 2 Compare 5 Word 0 register bit definitions */ #define GEM_W0_COMPARE_VALUE (BITS_16 << 16) #define GEM_W0_MASK_VALUE BITS_16 /* General MAC Type 2 Compare 0 Word 1 register bit definitions */ /* eMAC Type 2 Compare 0 Word 1 register bit definitions */ /* eMAC Type 2 Compare 1 Word 1 register bit definitions */ /* eMAC Type 2 Compare 2 Word 1 register bit definitions */ /* eMAC Type 2 Compare 3 Word 1 register bit definitions */ /* eMAC Type 2 Compare 4 Word 1 register bit definitions */ /* eMAC Type 2 Compare 5 Word 1 register bit definitions */ #define GEM_COMPARE_VLAN_ID BIT_10 #define GEM_DISABLE_MASK BIT_09 #define GEM_COMPARE_OFFSET (BIT_07 | BIT_08) #define GEM_COMPARE_S_TAG BIT_07 #define GEM_OFFSET_VALUE BITS_07 #define GEM_COMPARE_OFFSET_SHIFT 7 /* General MAC Enst Start Time Queue 0 register bit definitions */ /* General MAC Enst Start Time Queue 1 register bit definitions */ /* General MAC Enst Start Time Queue 2 register bit definitions */ /* General MAC Enst Start Time Queue 3 register bit definitions */ /* eMAC Enst Start Time register bit definitions */ #define GEM_START_TIME_SEC (BIT_30 | BIT_31) #define GEM_START_TIME_NSEC BITS_30 /* General MAC Enst Start Time Queue 0 register bit definitions */ /* General MAC Enst Start Time Queue 1 register bit definitions */ /* General MAC Enst Start Time Queue 2 register bit definitions */ /* General MAC Enst Start Time Queue 3 register bit definitions */ /* General MAC Enst Off Time Queue 0 register bit definitions */ /* General MAC Enst Off Time Queue 1 register bit definitions */ /* General MAC Enst Off Time Queue 2 register bit definitions */ /* General MAC Enst Off Time Queue 3 register bit definitions */ /* eMAC Enst Start Time register bit definitions */ /* eMAC Enst Off Time register bit definitions */ #define GEM_ON_OFF_TIME BITS_17 /* General MAC Enst Control register bit definitions */ /* eMAC Enst Control register bit definitions */ #define GEM_ENST_DISABLE_Q_3 BIT_19 #define GEM_ENST_DISABLE_Q_2 BIT_18 #define GEM_ENST_DISABLE_Q_1 BIT_17 #define GEM_ENST_DISABLE_Q_0 BIT_16 #define GEM_ENST_ENABLE_Q_3 BIT_03 #define GEM_ENST_ENABLE_Q_2 BIT_02 #define GEM_ENST_ENABLE_Q_1 BIT_01 #define GEM_ENST_ENABLE_Q_0 BIT_00 /* General MAC MMSL Control register bit definitions */ #define GEM_MMSL_DEBUG_MODE BIT_06 #define GEM_ROUTE_RX_TO_PMAC BIT_05 #define GEM_RESTART_VER BIT_04 #define GEM_PRE_ENABLE BIT_03 #define GEM_VERIFY_DISABLE BIT_02 #define GEM_ADD_FRAG_SIZE (BIT_00 | BIT_01) /* General MAC MMSL Status register bit definitions */ #define GEM_SMD_ERROR BIT_10 #define GEM_FRER_COUNT_ERR BIT_09 #define GEM_SMDC_ERROR BIT_08 #define GEM_SMDS_ERROR BIT_07 #define GEM_RCV_V_ERROR BIT_06 #define GEM_RCV_R_ERROR BIT_05 #define GEM_VERIFY_STATUS (BIT_02 | BIT_03 | BIT_04) #define GEM_RESPOND_STATUS BIT_01 #define GEM_PRE_ACTIVE BIT_00 #define GEM_VERIFY_STATUS_SHIFT 2 #define GEM_VERIFY_INIT ((uint32_t)(0x00UL)) #define GEM_VERIFY_IDLE ((uint32_t)(0x01UL)) #define GEM_VERIFY_SEND ((uint32_t)(0x02UL)) #define GEM_VERIFY_WAIT ((uint32_t)(0x03UL)) #define GEM_VERIFY_DONE_OK ((uint32_t)(0x04UL)) #define GEM_VERIFY_DONE_FAIL ((uint32_t)(0x05UL)) /* General MAC MMSL Error Stats register bit definitions */ #define GEM_SMD_ERR_COUNT (BITS_08 << 16) #define GEM_ASS_ERR_COUNT BITS_08 #define GEM_SMD_ERR_COUNT_SHIFT 16 /* General MAC MMSL Ass OK Count register bit definitions */ #define GEM_ASS_OK_COUNT BITS_17 /* General MAC MMSL Frag Count RX register bit definitions */ /* General MAC MMSL Frag Count TX register bit definitions */ #define GEM_FRAG_COUNT BITS_17 /* General MAC MMSL Interrupt Status register bit definitions */ /* General MAC MMSL Interrupt Enable register bit definitions */ /* General MAC MMSL Interrupt Disable register bit definitions */ /* General MAC MMSL Interrupt Mask register bit definitions */ #define GEM_INT_SMD_ERROR BIT_05 #define GEM_INT_FRER_COUNT_ERR BIT_04 #define GEM_INT_SMDC_ERROR BIT_03 #define GEM_INT_SMDS_ERROR BIT_02 #define GEM_INT_RCV_V_ERROR BIT_01 #define GEM_INT_RCV_R_ERROR BIT_00 #ifdef __cplusplus } #endif #endif /* MSS_ETHERNET_MAC_REGS_H_ */ mss_ethernet_mac_types.h000066400000000000000000001120241432224323300435100ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * This file contains type definitions used throughout the PolarFire SoC MSS * Ethernet MAC and PHY device drivers. User need not include this file in * application source code. * Inclusion of mss_ethernet_mac.h inherits these types. * * SVN $Revision$ * SVN $Date$ */ #ifndef MSS_ETHERNET_MAC_TYPES_H_ #define MSS_ETHERNET_MAC_TYPES_H_ #include #ifdef __cplusplus extern "C" { #endif /*******************************************************************************/ /* Public type definitions */ /*******************************************************************************/ /******************************************************************************* * MAC interface speed * This enumeration specifies the various interface speeds supported by MAC * hardware. */ typedef enum { MSS_MAC_10MBPS = 0x00, MSS_MAC_100MBPS = 0x01, MSS_MAC_1000MBPS = 0x02, INVALID_SPEED = 0x03 } mss_mac_speed_t; /******************************************************************************* * MAC RX interrupt control * This enumeration indicates the action to take in relation to the RX * interrupt when configuring an RX buffer with MSS_MAC_receive_pkt(). */ typedef enum { MSS_MAC_INT_ARM = -1, /* Last buffer in chain so arm the RX interrupt */ MSS_MAC_INT_DISABLE = 0, /* Disable interrupts on exit */ MSS_MAC_INT_ENABLE = 1, /* Leave interrupts enabled on exit */ } mss_mac_rx_int_ctrl_t; /******************************************************************************* PolarFire SoC MSS Ethernet MAC Configuration Structure. The mss_mac_cfg_t type contains the initial configuration values for the MPFS Ethernet MAC. You need to create a record of this type to hold the configuration of the MAC. MSS_MAC_cfg_struct_def_init() is used to initialize the configuration record to default values. Later, the configuration elements in the record can be changed to desired values before passing them to MSS_MAC_init(). interface_type This indicates the type of interface between the MAC and the PHY. The currently supported values are: NULL_PHY - No PHY involved, usually for direct connection via the fabric. GMII - Connection via GMII routed through the fabric to external PHY device. TBI - Connection via SGMII block to external PHY device. GMII_SGMII - Emulation platform specific option using SGMII to GMII bridge. phy_type This indicates the type of PHY device connected to the MAC. The currently supported values are: MSS_MAC_DEV_PHY_NULL - No PHY device. MSS_MAC_DEV_PHY_VSC8575 - VSC8575 with full VTSS API. MSS_MAC_DEV_PHY_VSC8575_LITE - VSC8757 with Lite VTSS API. MSS_MAC_DEV_PHY_VSC8541 - VSC8541 without VTSS API. MSS_MAC_DEV_PHY_DP83867 - TI DP83867. phy_init phy_set_link_speed phy_autonegotiate phy_get_link_status phy_extended_read phy_init_extended_write These are callback functions for the PHY support within the driver. These should be set to the appropriate PHY driver functions for the attached PHY device. See mss_mac_phy_init_t, mss_mac_phy_set_speed_t, mss_mac_phy_autonegotiate_t, mss_mac_phy_get_link_status_t, mss_mac_phy_extended_read_t and mss_mac_phy_extended_write_t for details. queue_enable This array of values of length MSS_MAC_QUEUE_COUNT, indicates which queues are to be enabled. 0 in an entry indicates disabled and 1 indicates enabled. speed_duplex_select The speed_duplex_select configuration parameter specifies the allowed link speeds. It is a bit-mask of the various link speed and duplex modes. The speed_duplex_select configuration can be set to a bitmask of the following defines to specify the allowed link speed and duplex mode: MSS_MAC_ANEG_10M_FD MSS_MAC_ANEG_10M_HD MSS_MAC_ANEG_100M_FD MSS_MAC_ANEG_100M_HD MSS_MAC_ANEG_1000M_FD MSS_MAC_ANEG_1000M_HD The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_ANEG_ALL_SPEEDS indicating that a link will be setup for best available speed and duplex combination. mac_addr The mac_addr configuration parameter is a 6-byte array containing the local MAC address of the Ethernet MAC. phy_address The phy_address parameter specifies the address of the PHY device, usually set in hardware by the address pins of the PHY device. pcs_phy_address The pcs_phy_address parameter specifies the address of the control device for hidden SGMII type interfaces such as that in the G5 SoC emulation platform. tx_edc_enable The tx_edc_enable parameter specifies enable or disable error detection and correction for tx FIFOs. The allowed values for the tx_edc_enable configuration parameter are: MSS_MAC_ERR_DET_CORR_ENABLE MSS_MAC_ERR_DET_CORR_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_ERR_DET_CORR_DISABLE. rx_edc_enable The rx_edc_enable parameter specifies enable or disable error detection and correction for rx FIFOs. The allowed values for the rx_edc_enable configuration parameter are: MSS_MAC_ERR_DET_CORR_ENABLE MSS_MAC_ERR_DET_CORR_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_ERR_DET_CORR_DISABLE. jumbo_frame_enable The jumbo_frame_enable parameter allows enabling or disabling jumbo frame support. When enabled, it allows frames longer than the maximum frame length to be transmitted and received. When disabled, the MAC limits the length of frames at the maximum frame length. The allowed values for the jumbo_frame_enable configuration parameter are: MSS_MAC_JUMBO_FRAME_ENABLE MSS_MAC_JUMBO_FRAME_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_JUMBO_FRAME_DISABLE. jumbo_frame_default This parameter sets the initial maximum jumbo frame length. The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_MAX_PACKET_SIZE. length_field_check The length_field_check parameter specifies enable or disable length field check. When enabled, the MAC checks the frame length field of received frames to ensure it matches the actual data field length. The allowed values for the length_field_check configuration parameter are: MSS_MAC_LENGTH_FIELD_CHECK_ENABLE MSS_MAC_LENGTH_FIELD_CHECK_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_LENGTH_FIELD_CHECK_ENABLE append_CRC The append_CRC parameter specifies enable or disable appending a CRC to transmitted packets. When enabled, the MAC appends a CRC to all frames. When disabled, frames presented to the MAC must have a valid length and contain a valid CRC. The allowed values for the append_CRC parameter are: MSS_MAC_CRC_ENABLE MSS_MAC_CRC_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_CRC_ENABLE. fullduplex The fullduplex parameter specifies enable or disable full duplex. When enabled, the MAC operates in full duplex mode. When disabled, the MAC operates in half duplex mode. The allowed values for the fullduplex configuration parameter are: MSS_MAC_FULLDUPLEX_ENABLE MSS_MAC_FULLDUPLEX_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_FULLDUPLEX_ENABLE. loopback The loopback parameter specifies enable or disable loop back mode. When enabled, the MAC transmit outputs to be looped back to its receiving inputs. The allowed values for the loopback configuration parameter are: MSS_MAC_LOOPBACK_ENABLE MSS_MAC_LOOPBACK_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_LOOPBACK_DISABLE. rx_flow_ctrl The rx_flow_ctrl parameter specifies enable or disable receiver flow control. When enabled, the MAC detects and acts on PAUSE flow control frames. When disabled, it ignores PAUSE flow control frames. The allowed values for the rx_flow_ctrl configuration parameter are: MSS_MAC_RX_FLOW_CTRL_ENABLE MSS_MAC_RX_FLOW_CTRL_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_RX_FLOW_CTRL_ENABLE. tx_flow_ctrl The tx_flow_ctrl parameter specifies enable or disable transmitter flow control. When enabled, the transmitter sends PAUSE flow control frames when requested by the system. When disabled, prevents the transmitter from sending flow control frames. The allowed values for the tx_flow_ctrl configuration parameter are: MSS_MAC_TX_FLOW_CTRL_ENABLE MSS_MAC_TX_FLOW_CTRL_DISABLE The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_TX_FLOW_CTRL_ENABLE. ipg_multiplier ipg_divisor The ipg_multiplier and ipg_divisor parameters specify the minimum size of gap (IPG/IFG) to enforce between frames (expressed in bit times). They are both 8 bit values and are used to calculate an IPG value based on the last packet sent by multiplying the length by ipg_multiplier and dividing the result by ipg_divisor. The resulting number of bits is used if it is greater than the default 96 bits. To select standard 96 bit IPG, set ipg_multiplier to MSS_MAC_IPG_DEFVAL. The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_IPG_DEFVAL. phyclk The phyclk parameter specifies the MII management clock divider value. PCLK is the source clock. The allowed values for the phyclk configuration parameter are: MSS_MAC_DEF_PHY_CLK MSS_MAC_BY8_PHY_CLK MSS_MAC_BY16_PHY_CLK MSS_MAC_BY32_PHY_CLK MSS_MAC_BY48_PHY_CLK MSS_MAC_BY64_PHY_CLK MSS_MAC_BY96_PHY_CLK MSS_MAC_BY128_PHY_CLK MSS_MAC_BY224_PHY_CLK The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_DEF_PHY_CLK. max_frame_length The max_frame_length parameter specifies the maximum frame size in both the transmit and receive directions. The allowed values for the max_frame_length configuration parameter are: MSS_MAC_MAXFRAMELEN_DEFVAL MSS_MAC_MAXFRAMELEN_MAXVAL The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to MSS_MAC_MAXFRAMELEN_DEFVAL. use_hi_address When set to 0, use_hi_address selects the default AXI slave slot 5 address for the location of the registers of the GEM device. When set to non 0, AXI slave slot 6 is used to access the device. The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to 0. use_local_ints When set to 0, use_local_ints selects the PLIC interrupts as the source for interrupts from the GEM. When set to non 0 local interrupts are used. GEM0 is connected to the local interrupts of U54 numbers 1 and 2. GEM1 is connected to the local interrupts of U54 numbers 3 and 4. The MSS_MAC_cfg_struct_def_init() function sets this configuration parameter to 0. queue0_int_priority queue1_int_priority queue2_int_priority queue3_int_priority mmsl_int_priority These parameters indicate the interrupt priority to use for each of the interrupt sources that the GEM supports. A priority of 0 effectively disables an interrupt and a priority of 7 is the highest priority that can be assigned. queue0_int_priority is the priority for the primary queue for the pMAC and the only queue for the eMAC. The MSS_MAC_cfg_struct_def_init() function sets these configuration parameters to 7. */ /******************************************************************************* * Pointer to PHY init function * * void MSS_MAC_phy_init(mss_mac_instance_t *this_mac, uint8_t phy_addr); * * this_mac - pointer to global structure for the MAC in question. * phy_addr - address of PHY on MDIO interface. * */ typedef void (*mss_mac_phy_init_t)(/* mss_mac_instance_t*/ const void *this_mac, uint8_t phy_addr); /******************************************************************************* * Pointer to PHY set link speed function * * void MSS_MAC_phy_set_link_speed(mss_mac_instance_t *this_mac, uint32_t speed_duplex_select); * * this_mac - pointer to global structure for the MAC in question. * speed_duplex_select - Combined and duplex options mask. */ typedef void (*mss_mac_phy_set_speed_t)(/* mss_mac_instance_t*/ const void *this_mac, uint32_t speed_duplex_select); /******************************************************************************* * Pointer to PHY autonegotiate function * * void MSS_MAC_phy_autonegotiate(mss_mac_instance_t *this_mac); * * this_mac - pointer to global structure for the MAC in question. */ typedef void (*mss_mac_phy_autonegotiate_t)(/* mss_mac_instance_t*/ const void *this_mac); /******************************************************************************* * Pointer to PHY get link status function * * uint8_t MSS_MAC_phy_get_link_status * ( * mss_mac_instance_t *this_mac, * mss_mac_speed_t * speed, * uint8_t * fullduplex * ); * * this_mac - pointer to global structure for the MAC in question. * speed - pointer to where to store current speed. * full_duplex - pointer to where to store current duplex mode. */ typedef uint8_t (*mss_mac_phy_get_link_status_t) ( /* mss_mac_instance_t*/ const void *this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ); #if MSS_MAC_USE_PHY_DP83867 /******************************************************************************* * Pointer to PHY extended read function * * uint16_t ti_read_extended_regs(mss_mac_instance_t * this_mac, uint16_t reg); * * this_mac - pointer to global structure for the MAC in question. * reg - the register to read from. */ typedef uint16_t (*mss_mac_phy_extended_read_t)(/* mss_mac_instance_t*/ const void *this_mac, uint16_t reg); /******************************************************************************* * Pointer to PHY extended write function * * void ti_write_extended_regs(mss_mac_instance_t * this_mac, uint16_t reg); * * this_mac - pointer to global structure for the MAC in question. * reg - the register to write to. * data - the value to write to the register. */ typedef void (*mss_mac_phy_extended_write_t)(/* mss_mac_instance_t*/ const void *this_mac, uint16_t reg, uint16_t data); #endif /* * Note: Even though most of these values are small, we use uint32_t for most values * here as they will be used in calculations that are based on uint32_t values and * this avoids having to put casts everywhere... */ typedef struct { uint32_t interface_type; /* Type of network interface associated with this GEM */ uint32_t phy_type; /* PHY device type associated with this GEM */ /* PHY interface functions */ mss_mac_phy_init_t phy_init; mss_mac_phy_set_speed_t phy_set_link_speed; mss_mac_phy_autonegotiate_t phy_autonegotiate; mss_mac_phy_get_link_status_t phy_get_link_status; #if MSS_MAC_USE_PHY_DP83867 mss_mac_phy_extended_read_t phy_extended_read; mss_mac_phy_extended_write_t phy_extended_write; #endif uint32_t queue_enable[MSS_MAC_QUEUE_COUNT]; /* Enables for additional queues */ uint32_t speed_duplex_select; /* Link speed and duplex mode allowed to setup a link. */ uint8_t mac_addr[6]; /* Station's MAC address */ uint32_t phy_addr; /* Address of Ethernet PHY on MII management interface. */ uint32_t pcs_phy_addr; /* Address of SGMII interface controller on MII management interface. */ uint32_t tx_edc_enable; /* Enable / disable error detection and correction for tx FIFOs */ uint32_t rx_edc_enable; /* Enable / disable error detection and correction for rx FIFOs */ uint32_t jumbo_frame_enable; /* Enable / disable jumbo frame support: default is disable 0 */ uint32_t jumbo_frame_default; /* Default maximum size for jumbo frames */ uint32_t length_field_check; /* Enable / disable length field checking */ uint32_t append_CRC; /* Enable / disable appending CRC */ uint32_t fullduplex; /* Enable / disable full duplex: default is disable 0 */ uint32_t loopback; /* Enable / disable loopback mode: default is disable 0 */ uint32_t rx_flow_ctrl; /* Enable / disable receiver flow control: default is disable 0 */ uint32_t tx_flow_ctrl; /* Enable / disable transmitter flow control: default is disable 0 */ uint32_t ipg_multiplier; /* 8-bit IPG multiplication factor, if 0 we disable IPG stretching */ uint32_t ipg_divisor; /* 8-bit back to back inter-frame gap value */ uint32_t phyclk; /* 3-bit MGMT clock divider value */ uint32_t max_frame_length; /* Maximum frame length: default value is 0x0600(1536d) */ uint32_t use_hi_address; /* Non 0 means use upper address range for this device */ uint32_t use_local_ints; /* non 0 meams use local interrupts for MAC instead of PLIC */ uint32_t queue0_int_priority; /* Main MAC interrupt */ uint32_t queue1_int_priority; /* Queue 1 interrupt */ uint32_t queue2_int_priority; /* Queue 2 interrupt */ uint32_t queue3_int_priority; /* Queue 3 interrupt */ uint32_t mmsl_int_priority; /* MMSL interrupt */ } mss_mac_cfg_t; /******************************************************************************* * This enumeration is used for accessing Transmit and Receive statistics. The * statistic which is desired to be read is passed to MSS_MAC_read_stat(). The * width of the returned statistic value is indicated in the comment against the * statistic. */ typedef enum { MSS_MAC_TX_OCTETS_LOW, /* 32-bit */ MSS_MAC_TX_OCTETS_HIGH, /* 16-bit */ MSS_MAC_TX_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_BCAST_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_MCAST_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_PAUSE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_64_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_65_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_128_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_256_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_512_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_1024_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_1519_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_TX_UNDERRUNS, /* 10-bit */ MSS_MAC_TX_SINGLE_COLLISIONS, /* 18-bit */ MSS_MAC_TX_MULTIPLE_COLLISIONS, /* 18-bit */ MSS_MAC_TX_EXCESSIVE_COLLISIONS, /* 10-bit */ MSS_MAC_TX_LATE_COLLISIONS, /* 10-bit */ MSS_MAC_TX_DEFERRED_FRAMES, /* 18-bit */ MSS_MAC_TX_CRS_ERRORS, /* 10-bit */ MSS_MAC_RX_OCTETS_LOW, /* 32-bit */ MSS_MAC_RX_OCTETS_HIGH, /* 16-bit */ MSS_MAC_RX_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_BCAST_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_MCAST_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_PAUSE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_64_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_65_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_128_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_256_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_512_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_1024_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_1519_BYTE_FRAMES_OK, /* 32-bit */ MSS_MAC_RX_UNDERSIZE_FRAMES_OK, /* 10-bit */ MSS_MAC_RX_OVERSIZE_FRAMES_OK, /* 10-bit */ MSS_MAC_RX_JABBERS, /* 10-bit */ MSS_MAC_RX_FCS_ERRORS, /* 10-bit */ MSS_MAC_RX_LENGTH_ERRORS, /* 10-bit */ MSS_MAC_RX_SYMBOL_ERRORS, /* 10-bit */ MSS_MAC_RX_ALIGNMENT_ERRORS, /* 10-bit */ MSS_MAC_RX_RESOURCE_ERRORS, /* 18-bit */ MSS_MAC_RX_OVERRUNS, /* 10-bit */ MSS_MAC_RX_IP_CHECKSUM_ERRORS, /* 8-bit */ MSS_MAC_RX_TCP_CHECKSUM_ERRORS, /* 8-bit */ MSS_MAC_RX_UDP_CHECKSUM_ERRORS, /* 8-bit */ MSS_MAC_RX_AUTO_FLUSHED_PACKETS, /* 16-bit */ MSS_MAC_LAST_STAT } mss_mac_stat_t; /******************************************************************************* * This enumeration indicates which direction unicast packet is being * referenced. */ typedef enum { MSS_MAC_TSU_UNICAST_RX, MSS_MAC_TSU_UNICAST_TX } mss_mac_tsu_addr_t; /******************************************************************************* * This enumeration indicates DMA descriptor time stamp insertion modes. */ typedef enum { MSS_MAC_TSU_MODE_DISABLED, /* Time stamp insertion disabled */ MSS_MAC_TSU_MODE_PTP_EVENT, /* Time stamp insertion for PTP Event frames only */ MSS_MAC_TSU_MODE_PTP_ALL, /* Time stamp insertion all PTP frames */ MSS_MAC_TSU_MODE_ALL, /* Time stamp insertion for all frames */ MSS_MAC_TSU_MODE_END } mss_mac_tsu_mode_t; /******************************************************************************* * This enumeration indicates hash matching modes. */ typedef enum { MSS_MAC_HASH_NONE = 0x00, /* Hash matching disabnled */ MSS_MAC_HASH_MULTICAST = 0x40, /* Multicast matching enabled */ MSS_MAC_HASH_UNIICAST = 0x80, /* Unicast matching enabled */ MSS_MAC_HASH_ALL = 0xC0 /* Multicast and Unicast matching enabled */ } mss_mac_hash_mode_t; /******************************************************************************* * This enumeration indicates sync time stamp adjust modes. */ typedef enum { MSS_MAC_OSS_MODE_DISABLED, /* Sync time stamp adjust disabled */ MSS_MAC_OSS_MODE_REPLACE, /* Sync time stamp replace mode */ MSS_MAC_OSS_MODE_ADJUST, /* Sync time stamp adjust correction field mode */ MSS_MAC_OSS_MODE_INVALID, /* Only for reporting mis-configured setup, not setting things... */ MSS_MAC_OSS_MODE_END } mss_mac_oss_mode_t; /******************************************************************************* * This enumeration indicates the preemption fragment size. */ typedef enum { MSS_MAC_FRAG_SIZE_64, MSS_MAC_FRAG_SIZE_128, MSS_MAC_FRAG_SIZE_192, MSS_MAC_FRAG_SIZE_256, MSS_MAC_FRAG_SIZE_END } mss_mac_frag_size_t; /******************************************************************************* * DMA Descriptor bit field defines. * * Driver creates and manages two descriptor rings for transmission and * reception. */ #define GEM_RX_DMA_TS_PRESENT BIT_02 #define GEM_RX_DMA_WRAP BIT_01 #define GEM_RX_DMA_USED BIT_00 #define GEM_RX_DMA_BCAST BIT_31 #define GEM_RX_DMA_MULTICAST_HASH BIT_30 #define GEM_RX_DMA_UNICAST_HASH BIT_29 #define GEM_RX_DMA_EXT_ADDR_MATCH BIT_28 #define GEM_RX_DMA_SPECIFIC_ADDR BIT_27 #define GEM_RX_DMA_ADDR_REGISTER (BIT_25 | BIT_26) #define GEM_RX_DMA_TYPE_ID_MATCH BIT_24 #define GEM_RX_DMA_TYPE_ID (BIT_22 | BIT_23) #define GEM_RX_DMA_VLAN_TAG BIT_21 #define GEM_RX_DMA_PRIORITY_TAG BIT_20 #define GEM_RX_DMA_VLAN_PRIORITY (BITS_03 << 17) #define GEM_RX_DMA_FCS_ERROR BIT_16 #define GEM_RX_DMA_START_OF_FRAME BIT_15 #define GEM_RX_DMA_END_OF_FRAME BIT_14 #define GEM_RX_DMA_JUMBO_BIT_13 BIT_13 #define GEM_RX_DMA_BUFF_LEN BITS_13 #define GEM_TX_DMA_USED BIT_31 #define GEM_TX_DMA_WRAP BIT_30 #define GEM_TX_DMA_RETRY_ERROR BIT_29 #define GEM_TX_DMA_UNDERRUN BIT_28 #define GEM_TX_DMA_BUS_ERROR BIT_27 #define GEM_TX_DMA_LATE_COL_ERROR BIT_26 #define GEM_TX_DMA_TS_PRESENT BIT_23 #define GEM_TX_DMA_OFFLOAD_ERRORS (BITS_03 << 20) #define GEM_TX_DMA_NO_CRC BIT_16 #define GEM_TX_DMA_LAST BIT_15 #define GEM_TX_DMA_BUFF_LEN BITS_14 typedef struct mss_mac_tx_desc mss_mac_tx_desc_t; typedef struct mss_mac_rx_desc mss_mac_rx_desc_t; /******************************************************************************* * Note: in the following definitions we use void * for the this_mac parameter * as they are used in the definition of the mss_mac_instance_t structure and * this confuses the compiler if we try to use the proper structure pointer in * the definition of these function pointers... */ /******************************************************************************* * Transmit callback function. * * this_mac - pointer to global structure for the MAC in question. * queue_no - 0 to 3 for pMAC and always 0 for eMAC. * cdesc - pointer to the DMA descriptor associated with this packet. * p_user_data - original user data pointer associated with the packet buffer. */ typedef void (*mss_mac_transmit_callback_t)(/* mss_mac_instance_t*/ void *this_mac, uint32_t queue_no, mss_mac_tx_desc_t *cdesc, void * p_user_data); /******************************************************************************* * Receive callback function. * * this_mac - pointer to global structure for the MAC in question. * queue_no - 0 to 3 for pMAC and always 0 for eMAC. * p_rx_packet - pointer to the buffer for the packet to be processed. * pckt_length - length of packet to be processed. * cdesc - pointer to the DMA descriptor associated with this packet. * p_user_data - original user data pointer associated with the packet buffer. */ typedef void (*mss_mac_receive_callback_t)(/* mss_mac_instance_t*/ void *this_mac, uint32_t queue_no, uint8_t *p_rx_packet, uint32_t pckt_length, mss_mac_rx_desc_t *cdesc, void *p_user_data); /******************************************************************************* * Transmit DMA descriptor. */ struct mss_mac_tx_desc { uint32_t addr_low; /* Buffer address low portion */ volatile uint32_t status; /* Status and options for transmit operation */ #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) uint32_t addr_high; /* High portion of address in 64bit addressing mode */ uint32_t unused; /* Unused word in 64bit mode */ #endif #if defined(MSS_MAC_TIME_STAMPED_MODE) volatile uint32_t nano_seconds; /* Nanoseconds and LSBs of seconds for timestamp */ volatile uint32_t seconds; /* MSBs of timestamp seconds */ #endif }; /******************************************************************************* * Receive DMA descriptor. */ struct mss_mac_rx_desc { uint32_t addr_low; /* Buffer address low portion */ volatile uint32_t status; /* Status and options for transmit operation */ #if defined(MSS_MAC_64_BIT_ADDRESS_MODE) uint32_t addr_high; /* High portion of address in 64bit addressing mode */ uint32_t unused; /* Unused word in 64bit mode */ #endif #if defined(MSS_MAC_TIME_STAMPED_MODE) volatile uint32_t nano_seconds; /* Nanoseconds and LSBs of seconds for timestamp */ volatile uint32_t seconds; /* MSBs of timestamp seconds */ #endif }; /******************************************************************************* * TSU timer time value. */ typedef struct mss_mac_tsu_time mss_mac_tsu_time_t; struct mss_mac_tsu_time { uint32_t secs_msb; /* Most significant bits of seconds count */ uint32_t secs_lsb; /* Least significant bits of seconds count */ uint32_t nanoseconds; /* Nanoseconds count */ }; /******************************************************************************* * TSU configuration structure. */ typedef struct mss_mac_tsu_config mss_mac_tsu_config_t; struct mss_mac_tsu_config { /* initial values */ uint32_t secs_msb; /* Most significant bits of seconds count */ uint32_t secs_lsb; /* Least significant bits of seconds count */ uint32_t nanoseconds; /* Nanoseconds count */ /* Per TSU tick values */ uint32_t ns_inc; /* Nanoseconds TSU increment value */ uint32_t sub_ns_inc; /* Sub-nanoseconds TSU increment value */ }; /******************************************************************************* * Type 1 filter structure. */ typedef struct mss_mac_type_1_filter mss_mac_type_1_filter_t; struct mss_mac_type_1_filter { uint16_t udp_port; /* UDP port number to match */ uint8_t dstc; /* Designated Services/Traffic Class value to match */ uint8_t queue_no; /* Queue to send to on match */ uint8_t drop_on_match; /* Drop packet instead of routing to queue */ uint8_t dstc_enable; /* Enable DS/TC matching */ uint8_t udp_port_enable; /* Enable UDP port matching */ }; /******************************************************************************* * Type 2 filter structures. */ typedef struct mss_mac_type_2_filter mss_mac_type_2_filter_t; struct mss_mac_type_2_filter { uint8_t ethertype_enable; /* Enable Ethertype matching */ uint8_t ethertype_index; /* Which Ethertype compare block to use */ uint8_t vlan_priority_enable; /* Enable VLAN priority matching */ uint8_t vlan_priority; /* VLAN priority level to use. */ uint8_t drop_on_match; /* Drop packet instead of routing to queue */ uint8_t compare_a_enable; /* Enable data comparer A */ uint8_t compare_a_index; /* Index to data comparator to use for A */ uint8_t compare_b_enable; /* Enable data comparer B */ uint8_t compare_b_index; /* Index to data comparator to use for B */ uint8_t compare_c_enable; /* Enable data comparer C */ uint8_t compare_c_index; /* Index to data comparator to use for C */ uint8_t queue_no; /* The queue to route packet to on match */ }; typedef struct mss_mac_type_2_compare mss_mac_type_2_compare_t; struct mss_mac_type_2_compare { uint32_t data; /* 32 bits of data or 16 bits of data */ uint16_t mask; /* 16 bit mask if data is 16 bit */ uint8_t disable_mask; /* True to select raw 32 bit data match */ uint8_t compare_vlan_c_id; /* Compare VLAN C tag - higher precedence than S tag */ uint8_t compare_vlan_s_id; /* Compare VLAN S tag */ uint8_t compare_offset; /* Offset type - see MSS_MAC_OFFSET_* definitions */ uint8_t offset_value; /* Offset value */ }; /******************************************************************************* * Media Merge Sublayer configuration structure. */ typedef struct mss_mac_mmsl_config mss_mac_mmsl_config_t; struct mss_mac_mmsl_config { mss_mac_frag_size_t frag_size; /* See mss_mac_frag_size_t for details */ uint8_t preemption; /* Enable preemption */ uint8_t verify_disable; /* Set true to force preemption without testing link */ uint8_t use_pmac; /* Receive all to pMAC if not preempting */ }; /******************************************************************************* * Media Merge Sublayer statistics structure. */ typedef struct mss_mac_mmsl_stats mss_mac_mmsl_stats_t; /* * These values are actually a mix of 8 and 17 bits but we return them all as * 32 bits to simplify collecting the stats. */ struct mss_mac_mmsl_stats { uint32_t smd_err_count; /* Count of unknown SMD values received */ uint32_t ass_err_count; /* Count of frames with reassembly errors */ uint32_t ass_ok_count; /* Count of frames reassembled ok */ uint32_t frag_count_rx; /* Count of mPackets received */ uint32_t frag_count_tx; /* Count of mPackets sent */ }; #if defined(MSS_MAC_SIMPLE_TX_QUEUE) /* Only need two descriptors... */ #undef MSS_MAC_TX_RING_SIZE #define MSS_MAC_TX_RING_SIZE (4) /* Ok, I lied we use a couple more for testing * sometimes by stuffing the queue with extra * copies of the packet... */ #endif /******************************************************************************* * Per queue specific info for device management structure. */ struct mss_mac_queue { #if defined(MSS_MAC_USE_DDR) mss_mac_tx_desc_t *tx_desc_tab; /* Transmit descriptor table */ #else mss_mac_tx_desc_t tx_desc_tab[MSS_MAC_TX_RING_SIZE]; /* Transmit descriptor table */ #endif #if defined(MSS_MAC_USE_DDR) mss_mac_rx_desc_t *rx_desc_tab; /* Receive descriptor table */ #else mss_mac_rx_desc_t rx_desc_tab[MSS_MAC_RX_RING_SIZE]; /* Receive descriptor table */ #endif void *tx_caller_info[MSS_MAC_TX_RING_SIZE]; /* Pointer to user specific data */ void *rx_caller_info[MSS_MAC_RX_RING_SIZE]; mss_mac_transmit_callback_t pckt_tx_callback; mss_mac_receive_callback_t pckt_rx_callback; volatile uint32_t nb_available_tx_desc; volatile uint32_t nb_available_rx_desc; volatile uint32_t next_free_rx_desc_index; volatile uint32_t first_rx_desc_index; uint32_t rx_discard; uint32_t overflow_counter; volatile int32_t in_isr; /* Set when processing ISR so functions * don't call PLIC enable/disable for protection */ /* Queue specific register addresses to simplify the driver code */ volatile uint32_t *int_status; /* interrupt status */ volatile uint32_t *int_mask; /* interrupt mask */ volatile uint32_t *int_enable; /* interrupt enable */ volatile uint32_t *int_disable; /* interrupt disable */ volatile uint32_t *receive_q_ptr; /* RX queue pointer */ volatile uint32_t *transmit_q_ptr; /* TX queue pointer */ volatile uint32_t *dma_rxbuf_size; /* RX queue buffer size */ /* Statistics counters */ volatile uint64_t ingress; volatile uint64_t egress; volatile uint64_t rx_overflow; volatile uint64_t hresp_error; volatile uint64_t rx_restart; volatile uint64_t tx_amba_errors; }; typedef struct mss_mac_queue mss_mac_queue_t; /******************************************************************************* * G5SoC Ethernet MAC instance * A local record of this type "g_mac" will be created and maintained by the * driver. */ typedef struct { uint32_t is_emac; /* 0 for primary MAC and non zero for eMAC */ MAC_TypeDef *mac_base; /* Register start address - NULL if eMAC */ eMAC_TypeDef *emac_base; /* Register start address - NULL if primary MAC */ PLIC_IRQn_Type mac_q_int[MSS_MAC_QUEUE_COUNT]; #if defined(TARGET_G5_SOC) PLIC_IRQn_Type mmsl_int; #endif mss_mac_queue_t queue[MSS_MAC_QUEUE_COUNT]; volatile uint64_t tx_pause; volatile uint64_t rx_pause; volatile uint64_t pause_elapsed; uint32_t rx_discard; volatile uint32_t mac_available; /* Flag to show init is done and MAC and PHY can be used */ /* These are set from the cfg structure */ uint32_t jumbo_frame_enable; /* Enable / disable jumbo frame support: */ uint32_t append_CRC; /* Enable / disable GEM CRC calculation */ uint32_t interface_type; /* Type of network interface associated with this GEM */ uint32_t phy_type; /* PHY device type associated with this GEM */ uint32_t phy_addr; /* Address of Ethernet PHY on MII management interface. */ uint32_t pcs_phy_addr; /* Address of SGMII interface controller on MII management interface. */ uint32_t use_hi_address; /* Non 0 means use upper address range for this device */ uint32_t use_local_ints; /* non 0 meams use local interrupts for MAC instead of PLIC */ uint8_t mac_addr[6]; /* Station's MAC address */ /* PHY interface functions */ mss_mac_phy_init_t phy_init; mss_mac_phy_set_speed_t phy_set_link_speed; mss_mac_phy_autonegotiate_t phy_autonegotiate; mss_mac_phy_get_link_status_t phy_get_link_status; #if MSS_MAC_USE_PHY_DP83867 mss_mac_phy_extended_read_t phy_extended_read; mss_mac_phy_extended_write_t phy_extended_write; #endif } mss_mac_instance_t; /******************************************************************************* * Flag value to indicate this MAC has been set up and is safe to call functions */ #define MSS_MAC_AVAILABLE (0XAAF1D055U) #ifdef __cplusplus } #endif #endif /* MSS_ETHERNET_MAC_TYPES_H_ */ mss_ethernet_mac_user_config.h000066400000000000000000000143621432224323300446550ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * This file contains system specific definitions for the PolarFire SoC MSS * Ethernet MAC device driver. * * SVN $Revision$ * SVN $Date$ * */ #ifndef MICROSEMI__FIRMWARE__POLARFIRE_SOC_MSS_ETHERNET_MAC_DRIVER__1_5_101_CONFIGURATION_HEADER #define MICROSEMI__FIRMWARE__POLARFIRE_SOC_MSS_ETHERNET_MAC_DRIVER__1_5_101_CONFIGURATION_HEADER #define CORE_VENDOR "Microsemi" #define CORE_LIBRARY "Firmware" #define CORE_NAME "PolarFire_SoC_MSS_Ethernet_MAC_Driver" #define CORE_VERSION "1.5.101" /* * Defines for OS and network stack specific support * Un-comment as necessary or define in project properties etc. */ /* #define USING_FREERTOS */ /* #define USING_LWIP */ /* Allowed PHY interface types: */ #define NULL_PHY (0x0001U) /* No PHY in connection, for example GEM0 and GEM1 connected via fabric */ #define GMII (0x0002U) /* Currently only on Aloe board */ #define TBI (0x0004U) /* G5 SoC Emulation Platform designs with TBI */ #define GMII_SGMII (0x0008U) /* G5 SoC Emulation Platform designs with SGMII to GMII conversion */ #define BASEX1000 (0x0010U) /* Not currently available */ #define RGMII (0x0020U) /* Not currently available */ #define RMII (0x0040U) /* Not currently available */ #define SGMII (0x0080U) /* Not currently available */ /* Allowed PHY models: */ #define MSS_MAC_DEV_PHY_NULL (0x0001U) #define MSS_MAC_DEV_PHY_VSC8575 (0x0002U) /* Uses full VTSS API */ #define MSS_MAC_DEV_PHY_VSC8541 (0x0004U) #define MSS_MAC_DEV_PHY_DP83867 (0x0008U) #define MSS_MAC_DEV_PHY_VSC8575_LITE (0x0010U) /* Uses Lite VTSS API */ /* * Defines for the different hardware configurations on the G5 SoC Emulation * Platform etc. * * Used to allow software configure GPIO etc, to support the appropriate * hardware configuration. Not strictly part of the driver but we manage them * here to keep things tidy. */ #define MSS_MAC_DESIGN_ALOE (0) /* ALOE board from Sifive */ #define MSS_MAC_DESIGN_EMUL_GMII (1) /* G5 SoC Emulation Platform VSC8575 designs with GMII to SGMII bridge on GEM0 */ #define MSS_MAC_DESIGN_EMUL_TBI (2) /* G5 SoC Emulation Platform VSC8575 designs with TBI to SGMII bridge on GEM0 */ #define MSS_MAC_DESIGN_EMUL_DUAL_INTERNAL (3) /* G5 SoC Emulation Platform Dual GEM design with loopback in fabric */ #define MSS_MAC_DESIGN_EMUL_TI_GMII (4) /* G5 SoC Emulation Platform DP83867 design with GMII to SGMII bridge */ #define MSS_MAC_DESIGN_EMUL_DUAL_EX_TI (5) /* G5 SoC Emulation Platform Dual GEM design with external TI PHY on GEM1 (GMII) */ #define MSS_MAC_DESIGN_EMUL_DUAL_EX_VTS (6) /* G5 SoC Emulation Platform Dual GEM design with external Vitess PHY on GEM0 (GMII) */ #define MSS_MAC_DESIGN_EMUL_GMII_GEM1 (7) /* G5 SoC Emulation Platform VSC8575 designs with GMII to SGMII bridge on GEM 1 */ #define MSS_MAC_DESIGN_EMUL_DUAL_EXTERNAL (8) /* G5 SoC Emulation Platform Dual GEM design with GEM0 -> VSC, GEM1 -> TI (both GMII) */ #define MSS_MAC_DESIGN_EMUL_TBI_GEM1 (9) /* G5 SoC Emulation Platform VSC8575 designs with TBI to SGMII bridge GEM1 */ #define MSS_MAC_DESIGN_EMUL_TBI_TI (10) /* G5 SoC Emulation Platform DP83867 designs with TBI to SGMII bridge GEM0 */ #define MSS_MAC_DESIGN_EMUL_TBI_GEM1_TI (11) /* G5 SoC Emulation Platform DP83867 designs with TBI to SGMII bridge GEM1 */ #define MSS_MAC_DESIGN_EMUL_GMII_LOCAL (12) /* G5 SoC Emulation Platform VSC8575 design with GMII to SGMII bridge with local ints */ #if defined(TARGET_ALOE) #define MSS_MAC_PHY_INTERFACE GMII /* Only one option allowed here... */ #define MSS_MAC_RX_RING_SIZE (4U) #define MSS_MAC_TX_RING_SIZE (2U) #define MSS_MAC_PHYS (MSS_MAC_DEV_PHY_NULL | MSS_MAC_DEV_PHY_VSC8541) #define MSS_MAC_HW_PLATFORM MSS_MAC_DESIGN_ALOE #endif #if defined(TARGET_G5_SOC) #define MSS_MAC_PHYS (MSS_MAC_DEV_PHY_NULL | MSS_MAC_DEV_PHY_VSC8575_LITE | MSS_MAC_DEV_PHY_DP83867) #define MSS_MAC_HW_PLATFORM MSS_MAC_DESIGN_EMUL_DUAL_EXTERNAL //#define MSS_MAC_RX_RING_SIZE (16U) #define MSS_MAC_RX_RING_SIZE (9U) #define MSS_MAC_TX_RING_SIZE (4U) /* PMCS should be 2 but want to be able to force duplicate * tx to stuff multiple packets into FIFO for testing */ #endif #define MSS_MAC_USE_PHY_VSC8575 (0U != (MSS_MAC_PHYS & MSS_MAC_DEV_PHY_VSC8575)) #define MSS_MAC_USE_PHY_VSC8575_LITE (0U != (MSS_MAC_PHYS & MSS_MAC_DEV_PHY_VSC8575_LITE)) #define MSS_MAC_USE_PHY_VSC8541 (0U != (MSS_MAC_PHYS & MSS_MAC_DEV_PHY_VSC8541)) #define MSS_MAC_USE_PHY_DP83867 (0U != (MSS_MAC_PHYS & MSS_MAC_DEV_PHY_DP83867)) #define MSS_MAC_USE_PHY_NULL (0U != (MSS_MAC_PHYS & MSS_MAC_DEV_PHY_NULL)) #define MSS_MAC_TIME_STAMPED_MODE (0) /* Enable time stamp support */ */ /* * Defines for different memory areas. Set the macro MSS_MAC_USE_DDR to one of * these values to select the area of memory and buffer sizes to use when * testing for non LIM based areas of memory. */ #define MSS_MAC_MEM_DDR (0) #define MSS_MAC_MEM_FIC0 (1) #define MSS_MAC_MEM_FIC1 (2) #define MSS_MAC_MEM_CRYPTO (3) /* * Number of additional queues for PMAC. * * Note. We explicitly set the number of queues in the MAC structure as we have * to indicate the Interrupt Number so this is slightly artificial... */ #if defined(TARGET_ALOE) #define MSS_MAC_QUEUE_COUNT (1) #else #define MSS_MAC_QUEUE_COUNT (4) #endif /* * Number of Type 1 and 2 screeners */ #define MSS_MAC_TYPE_1_SCREENERS (4U) #define MSS_MAC_TYPE_2_SCREENERS (4U) #define MSS_MAC_TYPE_2_ETHERTYPES (4U) #define MSS_MAC_TYPE_2_COMPARERS (4U) /* These are hard coded and not user selectable */ #define MSS_MAC_EMAC_TYPE_2_SCREENERS (2U) #define MSS_MAC_EMAC_TYPE_2_COMPARERS (6U) #endif /* MICROSEMI__FIRMWARE__POLARFIRE_SOC_MSS_ETHERNET_MAC_DRIVER__1_5_101_CONFIGURATION_HEADER */ mss_ethernet_registers.h000066400000000000000000000743151432224323300435450ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * This file contains the type definitions for the GEM Ethernet MAC as * implemented for the PolarFire SoC. This also covers the subset implemented for * the FU540 on the Aloe board with the provisio that many of the registers will * not be present on that device. * * We use separate MAC and eMAC definitions even though the eMAC is a subset * of the MAC as it helps to catch errors if we try to program registers not * present on the eMAC. * * SVN $Revision$ * SVN $Date$ */ #ifndef MSS_ETHERNET_MAC_REGISTERS_H_ #define MSS_ETHERNET_MAC_REGISTERS_H_ #ifdef __cplusplus extern "C" { #endif /*----------------------------------------------------------------------------*/ /*----------------------------------- MAC -----------------------------------*/ /*----------------------------------------------------------------------------*/ #define __I const volatile #define __O volatile #define __IO volatile typedef struct { __IO uint32_t NETWORK_CONTROL; /* 0x0000 */ __IO uint32_t NETWORK_CONFIG; /* 0x0004 */ __I uint32_t NETWORK_STATUS; /* 0x0008 */ __IO uint32_t USER_IO; /* 0x000C */ __IO uint32_t DMA_CONFIG; /* 0x0010 */ __IO uint32_t TRANSMIT_STATUS; /* 0x0014 */ __IO uint32_t RECEIVE_Q_PTR; /* 0x0018 */ __IO uint32_t TRANSMIT_Q_PTR; /* 0x001C */ __IO uint32_t RECEIVE_STATUS; /* 0x0020 */ __IO uint32_t INT_STATUS; /* 0x0024 */ __IO uint32_t INT_ENABLE; /* 0x0028 */ __IO uint32_t INT_DISABLE; /* 0x002C */ __IO uint32_t INT_MASK; /* 0x0030 */ __IO uint32_t PHY_MANAGEMENT; /* 0x0034 */ __IO uint32_t PAUSE_TIME; /* 0x0038 */ __IO uint32_t TX_PAUSE_QUANTUM; /* 0x003C */ __IO uint32_t PBUF_TXCUTTHRU; /* 0x0040 */ __IO uint32_t PBUF_RXCUTTHRU; /* 0x0044 */ __IO uint32_t JUMBO_MAX_LENGTH; /* 0x0048 */ uint32_t reserved1; /* 0x004C */ uint32_t reserved2; /* 0x0050 */ __IO uint32_t AXI_MAX_PIPELINE; /* 0x0054 */ uint32_t reserved3; /* 0x0058 */ __IO uint32_t INT_MODERATION; /* 0x005C */ __IO uint32_t SYS_WAKE_TIME; /* 0x0060 */ __IO uint32_t FATAL_OR_NON_FATAL_INT_SEL; /* 0x0064 */ __IO uint32_t LOCKUP_CONFIG; /* 0x0068 */ __IO uint32_t RX_MAC_LOCKUP_TIME; /* 0x006C */ uint32_t reserved4; /* 0x0070 */ uint32_t reserved5; /* 0x0074 */ uint32_t reserved6; /* 0x0078 */ uint32_t reserved7; /* 0x007C */ __IO uint32_t HASH_BOTTOM; /* 0x0080 */ __IO uint32_t HASH_TOP; /* 0x0084 */ __IO uint32_t SPEC_ADD1_BOTTOM; /* 0x0088 */ __IO uint32_t SPEC_ADD1_TOP; /* 0x008C */ __IO uint32_t SPEC_ADD2_BOTTOM; /* 0x0090 */ __IO uint32_t SPEC_ADD2_TOP; /* 0x0094 */ __IO uint32_t SPEC_ADD3_BOTTOM; /* 0x0098 */ __IO uint32_t SPEC_ADD3_TOP; /* 0x009C */ __IO uint32_t SPEC_ADD4_BOTTOM; /* 0x00A0 */ __IO uint32_t SPEC_ADD4_TOP; /* 0x00A4 */ __IO uint32_t SPEC_TYPE1; /* 0x00A8 */ __IO uint32_t SPEC_TYPE2; /* 0x00AC */ __IO uint32_t SPEC_TYPE3; /* 0x00B0 */ __IO uint32_t SPEC_TYPE4; /* 0x00B4 */ __IO uint32_t WOL_REGISTER; /* 0x00B8 */ __IO uint32_t STRETCH_RATIO; /* 0x00BC */ __IO uint32_t STACKED_VLAN; /* 0x00C0 */ __IO uint32_t TX_PFC_PAUSE; /* 0x00C4 */ __IO uint32_t MASK_ADD1_BOTTOM; /* 0x00C8 */ __IO uint32_t MASK_ADD1_TOP; /* 0x00CC */ __IO uint32_t DMA_ADDR_OR_MASK; /* 0x00D0 */ __IO uint32_t RX_PTP_UNICAST; /* 0x00D4 */ __IO uint32_t TX_PTP_UNICAST; /* 0x00D8 */ __IO uint32_t TSU_NSEC_CMP; /* 0x00DC */ __IO uint32_t TSU_SEC_CMP; /* 0x00E0 */ __IO uint32_t TSU_MSB_SEC_CMP; /* 0x00E4 */ __IO uint32_t TSU_PTP_TX_MSB_SEC_CMP; /* 0x00E8 */ __IO uint32_t TSU_PTP_RX_MSB_SEC_CMP; /* 0x00EC */ __IO uint32_t TSU_PEER_TX_MSB_SEC_CMP; /* 0x00F0 */ __IO uint32_t TSU_PEER_RX_MSB_SEC_CMP; /* 0x00F4 */ __IO uint32_t DPRAM_FILL_DBG; /* 0x00F8 */ __IO uint32_t REVISION_REG; /* 0x00FC */ __IO uint32_t OCTETS_TXED_BOTTOM; /* 0x0100 */ __IO uint32_t OCTETS_TXED_TOP; /* 0x0104 */ __IO uint32_t FRAMES_TXED_OK; /* 0x0108 */ __IO uint32_t BROADCAST_TXED; /* 0x010C */ __IO uint32_t MULTICAST_TXED; /* 0x0110 */ __IO uint32_t PAUSE_FRAMES_TXED; /* 0x0114 */ __IO uint32_t FRAMES_TXED_64; /* 0x0118 */ __IO uint32_t FRAMES_TXED_65; /* 0x011C */ __IO uint32_t FRAMES_TXED_128; /* 0x0120 */ __IO uint32_t FRAMES_TXED_256; /* 0x0124 */ __IO uint32_t FRAMES_TXED_512; /* 0x0128 */ __IO uint32_t FRAMES_TXED_1024; /* 0x012C */ __IO uint32_t FRAMES_TXED_1519; /* 0x0130 */ __IO uint32_t TX_UNDERRUNS; /* 0x0134 */ __IO uint32_t SINGLE_COLLISIONS; /* 0x0138 */ __IO uint32_t MULTIPLE_COLLISIONS; /* 0x013C */ __IO uint32_t EXCESSIVE_COLLISIONS; /* 0x0140 */ __IO uint32_t LATE_COLLISIONS; /* 0x0144 */ __IO uint32_t DEFERRED_FRAMES; /* 0x0148 */ __IO uint32_t CRS_ERRORS; /* 0x014C */ __IO uint32_t OCTETS_RXED_BOTTOM; /* 0x0150 */ __IO uint32_t OCTETS_RXED_TOP; /* 0x0154 */ __IO uint32_t FRAMES_RXED_OK; /* 0x0158 */ __IO uint32_t BROADCAST_RXED; /* 0x015C */ __IO uint32_t MULTICAST_RXED; /* 0x0160 */ __IO uint32_t PAUSE_FRAMES_RXED; /* 0x0164 */ __IO uint32_t FRAMES_RXED_64; /* 0x0168 */ __IO uint32_t FRAMES_RXED_65; /* 0x016C */ __IO uint32_t FRAMES_RXED_128; /* 0x0170 */ __IO uint32_t FRAMES_RXED_256; /* 0x0174 */ __IO uint32_t FRAMES_RXED_512; /* 0x0178 */ __IO uint32_t FRAMES_RXED_1024; /* 0x017C */ __IO uint32_t FRAMES_RXED_1519; /* 0x0180 */ __IO uint32_t UNDERSIZE_FRAMES; /* 0x0184 */ __IO uint32_t EXCESSIVE_RX_LENGTH; /* 0x0188 */ __IO uint32_t RX_JABBERS; /* 0x018C */ __IO uint32_t FCS_ERRORS; /* 0x0190 */ __IO uint32_t RX_LENGTH_ERRORS; /* 0x0194 */ __IO uint32_t RX_SYMBOL_ERRORS; /* 0x0198 */ __IO uint32_t ALIGNMENT_ERRORS; /* 0x019C */ __IO uint32_t RX_RESOURCE_ERRORS; /* 0x01A0 */ __IO uint32_t RX_OVERRUNS; /* 0x01A4 */ __IO uint32_t RX_IP_CK_ERRORS; /* 0x01A8 */ __IO uint32_t RX_TCP_CK_ERRORS; /* 0x01AC */ __IO uint32_t RX_UDP_CK_ERRORS; /* 0x01B0 */ __IO uint32_t AUTO_FLUSHED_PKTS; /* 0x01B4 */ uint32_t reserved8; /* 0x01B8 */ __IO uint32_t TSU_TIMER_INCR_SUB_NSEC; /* 0x01BC */ __IO uint32_t TSU_TIMER_MSB_SEC; /* 0x01C0 */ __IO uint32_t TSU_STROBE_MSB_SEC; /* 0x01C4 */ __IO uint32_t TSU_STROBE_SEC; /* 0x01C8 */ __IO uint32_t TSU_STROBE_NSEC; /* 0x01CC */ __IO uint32_t TSU_TIMER_SEC; /* 0x01D0 */ __IO uint32_t TSU_TIMER_NSEC; /* 0x01D4 */ __IO uint32_t TSU_TIMER_ADJUST; /* 0x01D8 */ __IO uint32_t TSU_TIMER_INCR; /* 0x01DC */ __IO uint32_t TSU_PTP_TX_SEC; /* 0x01E0 */ __IO uint32_t TSU_PTP_TX_NSEC; /* 0x01E4 */ __IO uint32_t TSU_PTP_RX_SEC; /* 0x01E8 */ __IO uint32_t TSU_PTP_RX_NSEC; /* 0x01EC */ __IO uint32_t TSU_PEER_TX_SEC; /* 0x01F0 */ __IO uint32_t TSU_PEER_TX_NSEC; /* 0x01F4 */ __IO uint32_t TSU_PEER_RX_SEC; /* 0x01F8 */ __IO uint32_t TSU_PEER_RX_NSEC; /* 0x01FC */ __IO uint32_t PCS_CONTROL; /* 0x0200 */ __IO uint32_t PCS_STATUS; /* 0x0204 */ __IO uint32_t PCS_PHY_TOP_ID; /* 0x0208 */ __IO uint32_t PCS_PHY_BOT_ID; /* 0x020C */ __IO uint32_t PCS_AN_ADV; /* 0x0210 */ __IO uint32_t PCS_AN_LP_BASE; /* 0x0214 */ __IO uint32_t PCS_AN_EXP; /* 0x0218 */ __IO uint32_t PCS_AN_NP_TX; /* 0x021C */ __IO uint32_t PCS_AN_LP_NP; /* 0x0220 */ uint32_t reserved9[6]; /* 0x0224 - 0x0238 */ __IO uint32_t PCS_AN_EXT_STATUS; /* 0x023C */ uint32_t reserved10[8]; /* 0x0240 - 0x025C */ __IO uint32_t TX_PAUSE_QUANTUM1; /* 0x0260 */ __IO uint32_t TX_PAUSE_QUANTUM2; /* 0x0264 */ __IO uint32_t TX_PAUSE_QUANTUM3; /* 0x0268 */ __IO uint32_t PFC_STATUS; /* 0x026C */ __IO uint32_t RX_LPI; /* 0x0270 */ __IO uint32_t RX_LPI_TIME; /* 0x0274 */ __IO uint32_t TX_LPI; /* 0x0278 */ __IO uint32_t TX_LPI_TIME; /* 0x027C */ __IO uint32_t DESIGNCFG_DEBUG1; /* 0x0280 */ __IO uint32_t DESIGNCFG_DEBUG2; /* 0x0284 */ __IO uint32_t DESIGNCFG_DEBUG3; /* 0x0288 */ __IO uint32_t DESIGNCFG_DEBUG4; /* 0x028C */ __IO uint32_t DESIGNCFG_DEBUG5; /* 0x0290 */ __IO uint32_t DESIGNCFG_DEBUG6; /* 0x0294 */ __IO uint32_t DESIGNCFG_DEBUG7; /* 0x0298 */ __IO uint32_t DESIGNCFG_DEBUG8; /* 0x029C */ __IO uint32_t DESIGNCFG_DEBUG9; /* 0x02A0 */ __IO uint32_t DESIGNCFG_DEBUG10; /* 0x02A4 */ __IO uint32_t DESIGNCFG_DEBUG11; /* 0x02A8 */ __IO uint32_t DESIGNCFG_DEBUG12; /* 0x02AC */ uint32_t reserved11[84]; /* 0x02B0 - 0x03FC */ __IO uint32_t INT_Q1_STATUS; /* 0x0400 */ __IO uint32_t INT_Q2_STATUS; /* 0x0404 */ __IO uint32_t INT_Q3_STATUS; /* 0x0408 */ uint32_t reserved12[13]; /* 0x040C - 0x043C */ __IO uint32_t TRANSMIT_Q1_PTR; /* 0x0440 */ __IO uint32_t TRANSMIT_Q2_PTR; /* 0x0444 */ __IO uint32_t TRANSMIT_Q3_PTR; /* 0x0448 */ uint32_t reserved13[13]; /* 0x044C - 0x047C */ __IO uint32_t RECEIVE_Q1_PTR; /* 0x0480 */ __IO uint32_t RECEIVE_Q2_PTR; /* 0x0484 */ __IO uint32_t RECEIVE_Q3_PTR; /* 0x0488 */ uint32_t reserved14[5]; /* 0x048C - 0x049C */ __IO uint32_t DMA_RXBUF_SIZE_Q1; /* 0x04A0 */ __IO uint32_t DMA_RXBUF_SIZE_Q2; /* 0x04A4 */ __IO uint32_t DMA_RXBUF_SIZE_Q3; /* 0x04A8 */ uint32_t reserved15[4]; /* 0x04AC - 0x04B8 */ __IO uint32_t CBS_CONTROL; /* 0x04BC */ __IO uint32_t CBS_IDLESLOPE_Q_A; /* 0x04C0 */ __IO uint32_t CBS_IDLESLOPE_Q_B; /* 0x04C4 */ __IO uint32_t UPPER_TX_Q_BASE_ADDR; /* 0x04C8 */ __IO uint32_t TX_BD_CONTROL; /* 0x04CC */ __IO uint32_t RX_BD_CONTROL; /* 0x04D0 */ __IO uint32_t UPPER_RX_Q_BASE_ADDR; /* 0x04D4 */ uint32_t reserved16[5]; /* 0x04D8 - 0x04E8 */ __IO uint32_t WD_COUNTER; /* 0x04EC */ uint32_t reserved17[2]; /* 0x04F0 - 0x04F4 */ __IO uint32_t AXI_TX_FULL_THRESH0; /* 0x04F8 */ __IO uint32_t AXI_TX_FULL_THRESH1; /* 0x04FC */ __IO uint32_t SCREENING_TYPE_1_REGISTER_0; /* 0x0500 */ __IO uint32_t SCREENING_TYPE_1_REGISTER_1; /* 0x0504 */ __IO uint32_t SCREENING_TYPE_1_REGISTER_2; /* 0x0508 */ __IO uint32_t SCREENING_TYPE_1_REGISTER_3; /* 0x050C */ uint32_t reserved18[12]; /* 0x0510 - 0x053C */ __IO uint32_t SCREENING_TYPE_2_REGISTER_0; /* 0x0540 */ __IO uint32_t SCREENING_TYPE_2_REGISTER_1; /* 0x0544 */ __IO uint32_t SCREENING_TYPE_2_REGISTER_2; /* 0x0548 */ __IO uint32_t SCREENING_TYPE_2_REGISTER_3; /* 0x054C */ uint32_t reserved18b[12]; /* 0x0550 - 0x057C */ __IO uint32_t TX_SCHED_CTRL; /* 0x0580 */ uint32_t reserved19[3]; /* 0x0584 - 0x058C */ __IO uint32_t BW_RATE_LIMIT_Q0TO3; /* 0x0590 */ uint32_t reserved20[3]; /* 0x0594 - 0x059C */ __IO uint32_t TX_Q_SEG_ALLOC_Q0TO3; /* 0x05A0 */ uint32_t reserved21[23]; /* 0x05A4 - 0x05FC */ __IO uint32_t INT_Q1_ENABLE; /* 0x0600 */ __IO uint32_t INT_Q2_ENABLE; /* 0x0604 */ __IO uint32_t INT_Q3_ENABLE; /* 0x0608 */ uint32_t reserved22[5]; /* 0x060C - 0x061C */ __IO uint32_t INT_Q1_DISABLE; /* 0x0620 */ __IO uint32_t INT_Q2_DISABLE; /* 0x0624 */ __IO uint32_t INT_Q3_DISABLE; /* 0x0628 */ uint32_t reserved23[5]; /* 0x062C - 0x063C */ __IO uint32_t INT_Q1_MASK; /* 0x0640 */ __IO uint32_t INT_Q2_MASK; /* 0x0644 */ __IO uint32_t INT_Q3_MASK; /* 0x0648 */ uint32_t reserved24[37]; /* 0x064C - 0x06DC */ __IO uint32_t SCREENING_TYPE_2_ETHERTYPE_REG_0; /* 0x06E0 */ __IO uint32_t SCREENING_TYPE_2_ETHERTYPE_REG_1; /* 0x06E4 */ __IO uint32_t SCREENING_TYPE_2_ETHERTYPE_REG_2; /* 0x06E8 */ __IO uint32_t SCREENING_TYPE_2_ETHERTYPE_REG_3; /* 0x06EC */ uint32_t reserved25[4]; /* 0x06F0 - 0x06FC */ __IO uint32_t TYPE2_COMPARE_0_WORD_0; /* 0x0700 */ __IO uint32_t TYPE2_COMPARE_0_WORD_1; /* 0x0704 */ __IO uint32_t TYPE2_COMPARE_1_WORD_0; /* 0x0708 */ __IO uint32_t TYPE2_COMPARE_1_WORD_1; /* 0x070C */ __IO uint32_t TYPE2_COMPARE_2_WORD_0; /* 0x0710 */ __IO uint32_t TYPE2_COMPARE_2_WORD_1; /* 0x0714 */ __IO uint32_t TYPE2_COMPARE_3_WORD_0; /* 0x0718 */ __IO uint32_t TYPE2_COMPARE_3_WORD_1; /* 0x071C */ uint32_t reserved26[56]; /* 0x0720 - 0x07FC */ __IO uint32_t ENST_START_TIME_Q0; /* 0x0800 */ __IO uint32_t ENST_START_TIME_Q1; /* 0x0804 */ __IO uint32_t ENST_START_TIME_Q2; /* 0x0808 */ __IO uint32_t ENST_START_TIME_Q3; /* 0x080C */ uint32_t reserved27[4]; /* 0x0810 - 0x081C */ __IO uint32_t ENST_ON_TIME_Q0; /* 0x0820 */ __IO uint32_t ENST_ON_TIME_Q1; /* 0x0824 */ __IO uint32_t ENST_ON_TIME_Q2; /* 0x0828 */ __IO uint32_t ENST_ON_TIME_Q3; /* 0x082C */ uint32_t reserved28[4]; /* 0x0830 - 0x083C */ __IO uint32_t ENST_OFF_TIME_Q0; /* 0x0840 */ __IO uint32_t ENST_OFF_TIME_Q1; /* 0x0844 */ __IO uint32_t ENST_OFF_TIME_Q2; /* 0x0848 */ __IO uint32_t ENST_OFF_TIME_Q3; /* 0x084C */ __IO uint32_t ENST_CONTROL; /* 0x0850 */ uint32_t reserved29[427]; /* 0x0854 - 0x0EFC */ __IO uint32_t MMSL_CONTROL; /* 0x0F00 */ __IO uint32_t MMSL_STATUS; /* 0x0F04 */ __IO uint32_t MMSL_ERR_STATS; /* 0x0F08 */ __IO uint32_t MMSL_ASS_OK_COUNT; /* 0x0F0C */ __IO uint32_t MMSL_FRAG_COUNT_RX; /* 0x0F10 */ __IO uint32_t MMSL_FRAG_COUNT_TX; /* 0x0F14 */ __IO uint32_t MMSL_INT_STATUS; /* 0x0F18 */ __IO uint32_t MMSL_INT_ENABLE; /* 0x0F1C */ __IO uint32_t MMSL_INT_DISABLE; /* 0x0F20 */ __IO uint32_t MMSL_INT_MASK; /* 0x0F24 */ uint32_t reserved30[54]; /* 0x0F28 - 0x0FFC */ } MAC_TypeDef; typedef struct { __IO uint32_t NETWORK_CONTROL; /* 0x1000 */ __IO uint32_t NETWORK_CONFIG; /* 0x1004 */ __IO uint32_t NETWORK_STATUS; /* 0x1008 */ uint32_t reserved31; /* 0x100C */ __IO uint32_t DMA_CONFIG; /* 0x1010 */ __IO uint32_t TRANSMIT_STATUS; /* 0x1014 */ __IO uint32_t RECEIVE_Q_PTR; /* 0x1018 */ __IO uint32_t TRANSMIT_Q_PTR; /* 0x101C */ __IO uint32_t RECEIVE_STATUS; /* 0x1020 */ __IO uint32_t INT_STATUS; /* 0x1024 */ __IO uint32_t INT_ENABLE; /* 0x1028 */ __IO uint32_t INT_DISABLE; /* 0x102C */ __IO uint32_t INT_MASK; /* 0x1030 */ __IO uint32_t PHY_MANAGEMENT; /* 0x1034 */ __IO uint32_t PAUSE_TIME; /* 0x1038 */ __IO uint32_t TX_PAUSE_QUANTUM; /* 0x103C */ __IO uint32_t PBUF_TXCUTTHRU; /* 0x1040 */ __IO uint32_t PBUF_RXCUTTHRU; /* 0x1044 */ __IO uint32_t JUMBO_MAX_LENGTH; /* 0x1048 */ uint32_t reserved32[2]; /* 0x104C - 0x1050 */ __IO uint32_t AXI_MAX_PIPELINE; /* 0x1054 */ uint32_t reserved33; /* 0x1058 */ __IO uint32_t INT_MODERATION; /* 0x105C */ __IO uint32_t SYS_WAKE_TIME; /* 0x1060 */ __IO uint32_t FATAL_OR_NON_FATAL_INT_SEL; /* 0x1064 */ __IO uint32_t LOCKUP_CONFIG; /* 0x1068 */ __IO uint32_t RX_MAC_LOCKUP_TIME; /* 0x106C */ uint32_t reserved34[4]; /* 0x1070 - 0x107C */ __IO uint32_t HASH_BOTTOM; /* 0x1080 */ __IO uint32_t HASH_TOP; /* 0x1084 */ __IO uint32_t SPEC_ADD1_BOTTOM; /* 0x1088 */ __IO uint32_t SPEC_ADD1_TOP; /* 0x108C */ __IO uint32_t SPEC_ADD2_BOTTOM; /* 0x1090 */ __IO uint32_t SPEC_ADD2_TOP; /* 0x1094 */ __IO uint32_t SPEC_ADD3_BOTTOM; /* 0x1098 */ __IO uint32_t SPEC_ADD3_TOP; /* 0x109C */ __IO uint32_t SPEC_ADD4_BOTTOM; /* 0x10A0 */ __IO uint32_t SPEC_ADD4_TOP; /* 0x10A4 */ __IO uint32_t SPEC_TYPE1; /* 0x10A8 */ __IO uint32_t SPEC_TYPE2; /* 0x10AC */ __IO uint32_t SPEC_TYPE3; /* 0x10B0 */ __IO uint32_t SPEC_TYPE4; /* 0x10B4 */ __IO uint32_t WOL_REGISTER; /* 0x10B8 */ __IO uint32_t STRETCH_RATIO; /* 0x10BC */ __IO uint32_t STACKED_VLAN; /* 0x10C0 */ __IO uint32_t TX_PFC_PAUSE; /* 0x10C4 */ __IO uint32_t MASK_ADD1_BOTTOM; /* 0x10C8 */ __IO uint32_t MASK_ADD1_TOP; /* 0x10CC */ __IO uint32_t DMA_ADDR_OR_MASK; /* 0x10D0 */ __IO uint32_t RX_PTP_UNICAST; /* 0x10D4 */ __IO uint32_t TX_PTP_UNICAST; /* 0x10D8 */ __IO uint32_t TSU_NSEC_CMP; /* 0x10DC */ __IO uint32_t TSU_SEC_CMP; /* 0x10E0 */ __IO uint32_t TSU_MSB_SEC_CMP; /* 0x10E4 */ __IO uint32_t TSU_PTP_TX_MSB_SEC; /* 0x10E8 */ __IO uint32_t TSU_PTP_RX_MSB_SEC; /* 0x10EC */ __IO uint32_t TSU_PEER_TX_MSB_SEC; /* 0x10F0 */ __IO uint32_t TSU_PEER_RX_MSB_SEC; /* 0x10F4 */ __IO uint32_t DPRAM_FILL_DBG; /* 0x10F8 */ __IO uint32_t REVISION_REG; /* 0x10FC */ __IO uint32_t OCTETS_TXED_BOTTOM; /* 0x1100 */ __IO uint32_t OCTETS_TXED_TOP; /* 0x1104 */ __IO uint32_t FRAMES_TXED_OK; /* 0x1108 */ __IO uint32_t BROADCAST_TXED; /* 0x110C */ __IO uint32_t MULTICAST_TXED; /* 0x1110 */ __IO uint32_t PAUSE_FRAMES_TXED; /* 0x1114 */ __IO uint32_t FRAMES_TXED_64; /* 0x1118 */ __IO uint32_t FRAMES_TXED_65; /* 0x111C */ __IO uint32_t FRAMES_TXED_128; /* 0x1120 */ __IO uint32_t FRAMES_TXED_256; /* 0x1124 */ __IO uint32_t FRAMES_TXED_512; /* 0x1128 */ __IO uint32_t FRAMES_TXED_1024; /* 0x112C */ __IO uint32_t FRAMES_TXED_1519; /* 0x1130 */ __IO uint32_t TX_UNDERRUNS; /* 0x1134 */ __IO uint32_t SINGLE_COLLISIONS; /* 0x1138 */ __IO uint32_t MULTIPLE_COLLISIONS; /* 0x113C */ __IO uint32_t EXCESSIVE_COLLISIONS; /* 0x1140 */ __IO uint32_t LATE_COLLISIONS; /* 0x1144 */ __IO uint32_t DEFERRED_FRAMES; /* 0x1148 */ __IO uint32_t CRS_ERRORS; /* 0x114C */ __IO uint32_t OCTETS_RXED_BOTTOM; /* 0x1150 */ __IO uint32_t OCTETS_RXED_TOP; /* 0x1154 */ __IO uint32_t FRAMES_RXED_OK; /* 0x1158 */ __IO uint32_t BROADCAST_RXED; /* 0x115C */ __IO uint32_t MULTICAST_RXED; /* 0x1160 */ __IO uint32_t PAUSE_FRAMES_RXED; /* 0x1164 */ __IO uint32_t FRAMES_RXED_64; /* 0x1168 */ __IO uint32_t FRAMES_RXED_65; /* 0x116C */ __IO uint32_t FRAMES_RXED_128; /* 0x1170 */ __IO uint32_t FRAMES_RXED_256; /* 0x1174 */ __IO uint32_t FRAMES_RXED_512; /* 0x1178 */ __IO uint32_t FRAMES_RXED_1024; /* 0x117C */ __IO uint32_t FRAMES_RXED_1519; /* 0x1180 */ __IO uint32_t UNDERSIZE_FRAMES; /* 0x1184 */ __IO uint32_t EXCESSIVE_RX_LENGTH; /* 0x1188 */ __IO uint32_t RX_JABBERS; /* 0x118C */ __IO uint32_t FCS_ERRORS; /* 0x1190 */ __IO uint32_t RX_LENGTH_ERRORS; /* 0x1194 */ __IO uint32_t RX_SYMBOL_ERRORS; /* 0x1198 */ __IO uint32_t ALIGNMENT_ERRORS; /* 0x119C */ __IO uint32_t RX_RESOURCE_ERRORS; /* 0x11A0 */ __IO uint32_t RX_OVERRUNS; /* 0x11A4 */ __IO uint32_t RX_IP_CK_ERRORS; /* 0x11A8 */ __IO uint32_t RX_TCP_CK_ERRORS; /* 0x11AC */ __IO uint32_t RX_UDP_CK_ERRORS; /* 0x11B0 */ __IO uint32_t AUTO_FLUSHED_PKTS; /* 0x11B4 */ uint32_t reserved35; /* 0x10B8 */ __IO uint32_t TSU_TIMER_INCR_SUB_NSEC; /* 0x11BC */ __IO uint32_t TSU_TIMER_MSB_SEC; /* 0x11C0 */ __IO uint32_t TSU_STROBE_MSB_SEC; /* 0x11C4 */ __IO uint32_t TSU_STROBE_SEC; /* 0x11C8 */ __IO uint32_t TSU_STROBE_NSEC; /* 0x11CC */ __IO uint32_t TSU_TIMER_SEC; /* 0x11D0 */ __IO uint32_t TSU_TIMER_NSEC; /* 0x11D4 */ __IO uint32_t TSU_TIMER_ADJUST; /* 0x11D8 */ __IO uint32_t TSU_TIMER_INCR; /* 0x11DC */ __IO uint32_t TSU_PTP_TX_SEC; /* 0x11E0 */ __IO uint32_t TSU_PTP_TX_NSEC; /* 0x11E4 */ __IO uint32_t TSU_PTP_RX_SEC; /* 0x11E8 */ __IO uint32_t TSU_PTP_RX_NSEC; /* 0x11EC */ __IO uint32_t TSU_PEER_TX_SEC; /* 0x11F0 */ __IO uint32_t TSU_PEER_TX_NSEC; /* 0x11F4 */ __IO uint32_t TSU_PEER_RX_SEC; /* 0x11F8 */ __IO uint32_t TSU_PEER_RX_NSEC; /* 0x11FC */ uint32_t reserved36[24]; /* 0x1200 - 0x125C */ __IO uint32_t TX_PAUSE_QUANTUM1; /* 0x1260 */ __IO uint32_t TX_PAUSE_QUANTUM2; /* 0x1264 */ __IO uint32_t TX_PAUSE_QUANTUM3; /* 0x1268 */ __IO uint32_t PFC_STATUS; /* 0x126C */ __IO uint32_t RX_LPI; /* 0x1270 */ __IO uint32_t RX_LPI_TIME; /* 0x1274 */ __IO uint32_t TX_LPI; /* 0x1278 */ __IO uint32_t TX_LPI_TIME; /* 0x127C */ __IO uint32_t DESIGNCFG_DEBUG1; /* 0x1280 */ __IO uint32_t DESIGNCFG_DEBUG2; /* 0x1284 */ __IO uint32_t DESIGNCFG_DEBUG3; /* 0x1288 */ __IO uint32_t DESIGNCFG_DEBUG4; /* 0x128C */ __IO uint32_t DESIGNCFG_DEBUG5; /* 0x1290 */ __IO uint32_t DESIGNCFG_DEBUG6; /* 0x1294 */ __IO uint32_t DESIGNCFG_DEBUG7; /* 0x1298 */ __IO uint32_t DESIGNCFG_DEBUG8; /* 0x129C */ __IO uint32_t DESIGNCFG_DEBUG9; /* 0x12A0 */ __IO uint32_t DESIGNCFG_DEBUG10; /* 0x12A4 */ __IO uint32_t DESIGNCFG_DEBUG11; /* 0x12A8 */ __IO uint32_t DESIGNCFG_DEBUG12; /* 0x12AC */ uint32_t reserved37[131]; /* 0x12B0 - 0x14B8 */ __IO uint32_t CBS_CONTROL; /* 0x14BC */ __IO uint32_t CBS_IDLESLOPE_Q_A; /* 0x14C0 */ __IO uint32_t CBS_IDLESLOPE_Q_B; /* 0x14C4 */ __IO uint32_t UPPER_TX_Q_BASE_ADDR; /* 0x14C8 */ __IO uint32_t TX_BD_CONTROL; /* 0x14CC */ __IO uint32_t RX_BD_CONTROL; /* 0x14D0 */ __IO uint32_t UPPER_RX_Q_BASE_ADDR; /* 0x14D4 */ uint32_t reserved38[10]; /* 0x14D8 - 0x14FC */ __IO uint32_t SCREENING_TYPE_1_REGISTER_0; /* 0x1500 - TBD PMCS Remove this and look for other possible additional registers near end of eMAC that we might be missing... */ uint32_t reserved39[15]; /* 0x1504 - 0x153C */ __IO uint32_t SCREENING_TYPE_2_REGISTER_0; /* 0x1540 */ __IO uint32_t SCREENING_TYPE_2_REGISTER_1; /* 0x1544 */ uint32_t reserved40[110]; /* 0x1548 - 0x16FC */ __IO uint32_t TYPE2_COMPARE_0_WORD_0; /* 0x1700 */ __IO uint32_t TYPE2_COMPARE_0_WORD_1; /* 0x1704 */ __IO uint32_t TYPE2_COMPARE_1_WORD_0; /* 0x1708 */ __IO uint32_t TYPE2_COMPARE_1_WORD_1; /* 0x170C */ __IO uint32_t TYPE2_COMPARE_2_WORD_0; /* 0x1710 */ __IO uint32_t TYPE2_COMPARE_2_WORD_1; /* 0x1714 */ __IO uint32_t TYPE2_COMPARE_3_WORD_0; /* 0x1718 */ __IO uint32_t TYPE2_COMPARE_3_WORD_1; /* 0x171C */ __IO uint32_t TYPE2_COMPARE_4_WORD_0; /* 0x1720 */ __IO uint32_t TYPE2_COMPARE_4_WORD_1; /* 0x1724 */ __IO uint32_t TYPE2_COMPARE_5_WORD_0; /* 0x1728 */ __IO uint32_t TYPE2_COMPARE_5_WORD_1; /* 0x172C */ uint32_t reserved41[52]; /* 0x1730 - 0x17FC */ __IO uint32_t ENST_START_TIME; /* 0x1800 */ uint32_t reserved42[7]; /* 0x1804 - 0x181C */ __IO uint32_t ENST_ON_TIME; /* 0x1820 */ uint32_t reserved43[7]; /* 0x1824 - 0x183C */ __IO uint32_t ENST_OFF_TIME; /* 0x1840 */ uint32_t reserved44[15]; /* 0x1844 - 0x187C */ __IO uint32_t ENST_CONTROL; /* 0x1820 */ } eMAC_TypeDef; #ifdef __cplusplus } #endif #endif /* MSS_ETHERNET_MAC_REGISTERS_H_ */ null_phy.c000066400000000000000000000056021432224323300405740ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * NULL PHY implementation. * * This PHY interface is used when there is a direct connection between two GEM * instances which does not involve the use of a PHY device. * * Also used when setting up the default config so that the pointers for the * PHY functions in the config always have some valid values. * */ #include "mss_plic.h" #include "fpga_design_config/fpga_design_config.h" #include "drivers/mss/mss_mac/mss_ethernet_registers.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_regs.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_user_config.h" #include "drivers/mss/mss_mac/mss_ethernet_mac.h" #include "drivers/mss/mss_mac/phy.h" #include "hal/hal.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif #if MSS_MAC_USE_PHY_NULL /**************************************************************************//** * */ void MSS_MAC_NULL_phy_init(/* mss_mac_instance_t*/ const void *v_this_mac, uint8_t phy_addr) { /* Nothing to see here... */ (void)v_this_mac; (void)phy_addr; } /**************************************************************************//** * */ void MSS_MAC_NULL_phy_set_link_speed(/* mss_mac_instance_t*/ const void *v_this_mac, uint32_t speed_duplex_select) { /* Nothing to see here... */ (void)v_this_mac; (void)speed_duplex_select; } /**************************************************************************//** * */ void MSS_MAC_NULL_phy_autonegotiate(/* mss_mac_instance_t*/ const void *v_this_mac) { /* Nothing to see here... */ (void)v_this_mac; } /**************************************************************************//** * */ uint8_t MSS_MAC_NULL_phy_get_link_status ( /* mss_mac_instance_t*/ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ) { uint8_t link_status; (void)v_this_mac; /* Assume link is up. */ link_status = MSS_MAC_LINK_UP; /* Pick fastest for now... */ *fullduplex = MSS_MAC_FULL_DUPLEX; *speed = MSS_MAC_1000MBPS; return link_status; } #if MSS_MAC_USE_PHY_DP83867 /**************************************************************************//** * */ uint16_t NULL_ti_read_extended_regs(/* mss_mac_instance_t*/ const void *v_this_mac, uint16_t reg) { (void)v_this_mac; (void)reg; return(0); } /**************************************************************************//** * */ void NULL_ti_write_extended_regs(/* mss_mac_instance_t*/ const void *v_this_mac, uint16_t reg, uint16_t data) { (void)v_this_mac; (void)reg; (void)data; /* Nothing to see here... */ } #endif #endif /* MSS_MAC_USE_PHY_NULL */ #ifdef __cplusplus } #endif /******************************** END OF FILE ******************************/ phy.h000066400000000000000000000412021432224323300375430ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit definitions for MII STA (station management entity) standard * interface. All basic MII register bits and enhanced capability register bits * are defined. * Complies with Clauses 22, 28, 37, 40 of IEEE RFC 802.3 * * SVN $Revision$ * SVN $Date$ */ #ifndef PSE_PHY_H #define PSE_PHY_H #include "../mss_mac/mss_ethernet_mac_types.h" #ifdef __cplusplus extern "C" { #endif /**************************************************************************/ /* Public definitions */ /**************************************************************************/ /*------------------------------------------------------------------------------ * MII register definitions. */ /* Generic MII registers. */ #define MII_BMCR (0X00U) /* Basic mode control register */ #define MII_BMSR (0X01U) /* Basic mode status register */ #define MII_PHYSID1 (0X02U) /* PHYS ID 1 */ #define MII_PHYSID2 (0X03U) /* PHYS ID 2 */ #define MII_ADVERTISE (0X04U) /* Advertisement control reg */ #define MII_LPA (0X05U) /* Link partner ability reg */ #define MII_EXPANSION (0X06U) /* Expansion register */ #define MII_NPAR (0X07U) #define MII_LPNPA (0X08U) #define MII_CTRL1000 (0X09U) /* 1000BASE-T control */ #define MII_STAT1000 (0X0AU) /* 1000BASE-T status */ #define MII_ESTATUS (0X0FU) /* Extended Status */ #define MII_DCOUNTER (0X12U) /* Disconnect counter */ #define MII_FCSCOUNTER (0X13U) /* False carrier counter */ #define MII_EXTEND (0X14U) /* extended PHY specific ctrl */ #define MII_RERRCOUNTER (0X15U) /* Receive error counter */ #define MII_SREVISION (0X16U) /* Silicon revision */ #define MII_RESV1 (0X17U) /* Reserved... */ #define MII_LBRERROR (0X18U) /* Lpback, rx, bypass error */ #define MII_PHYADDR (0X19U) /* PHY address */ #define MII_RESV2 (0X1AU) /* Reserved... */ #define MII_TPISTATUS (0X1BU) /* TPI status for 10mbps */ #define MII_NCONFIG (0X1CU) /* Network interface config */ #define MII_LMCS (0X1DU) #define MII_PHYCTRL1 (0X1EU) #define MII_PHYCTRL2 (0X1FU) #define MII_TI_REGCR (0X0DU) #define MII_TI_ADDAR (0X0EU) #define MII_TI_PHYCR (0X10U) #define MII_TI_CTRL (0X1FU) #define MII_TI_SGMIICTL1 (0XD3U) /* Basic mode control register. */ #define BMCR_RESV (0x003FU) /* Unused... */ #define BMCR_SPEED1000 (0x0040U) /* MSB of Speed (1000) */ #define BMCR_CTST (0x0080U) /* Collision test */ #define BMCR_FULLDPLX (0x0100U) /* Full duplex */ #define BMCR_ANRESTART (0x0200U) /* Auto negotiation restart */ #define BMCR_ISOLATE (0x0400U) /* Disconnect DP83840 from MII */ #define BMCR_PDOWN (0x0800U) /* Powerdown the DP83840 */ #define BMCR_ANENABLE (0x1000U) /* Enable auto negotiation */ #define BMCR_SPEED100 (0x2000U) /* Select 100Mbps */ #define BMCR_LOOPBACK (0x4000U) /* TXD loopback bits */ #define BMCR_RESET (0x8000U) /* Reset the DP83840 */ /* Basic mode status register. */ #define BMSR_ERCAP (0x0001U) /* Ext-reg capability */ #define BMSR_JCD (0x0002U) /* Jabber detected */ #define BMSR_LSTATUS (0x0004U) /* Link status */ #define BMSR_ANEGCAPABLE (0x0008U) /* Able to do auto-negotiation */ #define BMSR_RFAULT (0x0010U) /* Remote fault detected */ #define BMSR_ANEGCOMPLETE (0x0020U) /* Auto-negotiation complete */ #define BMSR_RESV (0x00c0U) /* Unused... */ #define BMSR_ESTATEN (0x0100U) /* Extended Status in R15 */ #define BMSR_100HALF2 (0x0200U) /* Can do 100BASE-T2 HDX */ #define BMSR_100FULL2 (0x0400U) /* Can do 100BASE-T2 FDX */ #define BMSR_10HALF (0x0800U) /* Can do 10mbps, half-duplex */ #define BMSR_10FULL (0x1000U) /* Can do 10mbps, full-duplex */ #define BMSR_100HALF (0x2000U) /* Can do 100mbps, half-duplex */ #define BMSR_100FULL (0x4000U) /* Can do 100mbps, full-duplex */ #define BMSR_100BASE4 (0x8000U) /* Can do 100mbps, 4k packets */ /* Advertisement control register. */ #define ADVERTISE_SLCT (0x001FU) /* Selector bits */ #define ADVERTISE_CSMA (0x0001U) /* Only selector supported */ #define ADVERTISE_10HALF (0x0020U) /* Try for 10mbps half-duplex */ #define ADVERTISE_1000XFULL (0x0020U) /* Try for 1000BASE-X full-duplex */ #define ADVERTISE_10FULL (0x0040U) /* Try for 10mbps full-duplex */ #define ADVERTISE_1000XHALF (0x0040U) /* Try for 1000BASE-X half-duplex */ #define ADVERTISE_100HALF (0x0080U) /* Try for 100mbps half-duplex */ #define ADVERTISE_1000XPAUSE (0x0080U) /* Try for 1000BASE-X pause */ #define ADVERTISE_100FULL (0x0100U) /* Try for 100mbps full-duplex */ #define ADVERTISE_1000XPSE_ASYM (0x0100U) /* Try for 1000BASE-X asym pause */ #define ADVERTISE_100BASE4 (0x0200U) /* Try for 100mbps 4k packets */ #define ADVERTISE_PAUSE_CAP (0x0400U) /* Try for pause */ #define ADVERTISE_PAUSE_ASYM (0x0800U) /* Try for asymetric pause */ #define ADVERTISE_RESV (0x1000U) /* Unused... */ #define ADVERTISE_RFAULT (0x2000U) /* Say we can detect faults */ #define ADVERTISE_LPACK (0x4000U) /* Ack link partners response */ #define ADVERTISE_NPAGE (0x8000U) /* Next page bit */ #define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ ADVERTISE_CSMA) #define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ ADVERTISE_100HALF | ADVERTISE_100FULL) /* Link partner ability register. */ #define LPA_SLCT (0x001FU) /* Same as advertise selector */ #define LPA_10HALF (0x0020U) /* Can do 10mbps half-duplex */ #define LPA_1000XFULL (0x0020U) /* Can do 1000BASE-X full-duplex */ #define LPA_10FULL (0x0040U) /* Can do 10mbps full-duplex */ #define LPA_1000XHALF (0x0040U) /* Can do 1000BASE-X half-duplex */ #define LPA_100HALF (0x0080U) /* Can do 100mbps half-duplex */ #define LPA_1000XPAUSE (0x0080U) /* Can do 1000BASE-X pause */ #define LPA_100FULL (0x0100U) /* Can do 100mbps full-duplex */ #define LPA_1000XPAUSE_ASYM (0x0100U) /* Can do 1000BASE-X pause asym*/ #define LPA_100BASE4 (0x0200U) /* Can do 100mbps 4k packets */ #define LPA_PAUSE_CAP (0x0400U) /* Can pause */ #define LPA_PAUSE_ASYM (0x0800U) /* Can pause asymetrically */ #define LPA_RESV (0x1000U) /* Unused... */ #define LPA_RFAULT (0x2000U) /* Link partner faulted */ #define LPA_LPACK (0x4000U) /* Link partner acked us */ #define LPA_NPAGE (0x8000U) /* Next page bit */ #define LPA_DUPLEX (LPA_10FULL | LPA_100FULL) #define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) /* Expansion register for auto-negotiation. */ #define EXPANSION_NWAY (0X0001U) /* Can do N-way auto-nego */ #define EXPANSION_LCWP (0X0002U) /* Got new RX page code word */ #define EXPANSION_ENABLENPAGE (0X0004U) /* This enables npage words */ #define EXPANSION_NPCAPABLE (0X0008U) /* Link partner supports npage */ #define EXPANSION_MFAULTS (0X0010U) /* Multiple faults detected */ #define EXPANSION_RESV (0XFFE0U) /* Unused... */ #define ESTATUS_1000_TFULL (0x2000U) /* Can do 1000BT Full */ #define ESTATUS_1000_THALF (0x1000U) /* Can do 1000BT Half */ /* N-way test register. */ #define NWAYTEST_RESV1 (0X00FFU) /* Unused... */ #define NWAYTEST_LOOPBACK (0X0100U) /* Enable loopback for N-way */ #define NWAYTEST_RESV2 (0XFE00U) /* Unused... */ /* 1000BASE-T Control register */ #define ADVERTISE_1000FULL (0x0200U) /* Advertise 1000BASE-T full duplex */ #define ADVERTISE_1000HALF (0x0100U) /* Advertise 1000BASE-T half duplex */ /* 1000BASE-T Status register */ #define LPA_1000LOCALRXOK (0x2000U) /* Link partner local receiver status */ #define LPA_1000REMRXOK (0x1000U) /* Link partner remote receiver status */ #define LPA_1000FULL (0x0800U) /* Link partner 1000BASE-T full duplex */ #define LPA_1000HALF (0x0400U) /* Link partner 1000BASE-T half duplex */ /* Indicates what features are supported by the interface. */ #define SUPPORTED_10baseT_Half (1U << 0) #define SUPPORTED_10baseT_Full (1U << 1) #define SUPPORTED_100baseT_Half (1U << 2) #define SUPPORTED_100baseT_Full (1U << 3) #define SUPPORTED_1000baseT_Half (1U << 4) #define SUPPORTED_1000baseT_Full (1U << 5) #define SUPPORTED_Autoneg (1U << 6) #define SUPPORTED_TP (1U << 7) #define SUPPORTED_AUI (1U << 8) #define SUPPORTED_MII (1U << 9) #define SUPPORTED_FIBRE (1U << 10) #define SUPPORTED_BNC (1U << 11) #define SUPPORTED_10000baseT_Full (1U << 12) #define SUPPORTED_Pause (1U << 13) #define SUPPORTED_Asym_Pause (1U << 14) #define SUPPORTED_2500baseX_Full (1U << 15) #define SUPPORTED_Backplane (1U << 16) #define SUPPORTED_1000baseKX_Full (1U << 17) #define SUPPORTED_10000baseKX4_Full (1U << 18) #define SUPPORTED_10000baseKR_Full (1U << 19) #define SUPPORTED_10000baseR_FEC (1U << 20) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1U << 0) #define ADVERTISED_10baseT_Full (1U << 1) #define ADVERTISED_100baseT_Half (1U << 2) #define ADVERTISED_100baseT_Full (1U << 3) #define ADVERTISED_1000baseT_Half (1U << 4) #define ADVERTISED_1000baseT_Full (1U << 5) #define ADVERTISED_Autoneg (1U << 6) #define ADVERTISED_TP (1U << 7) #define ADVERTISED_AUI (1U << 8) #define ADVERTISED_MII (1U << 9) #define ADVERTISED_FIBRE (1U << 10) #define ADVERTISED_BNC (1U << 11) #define ADVERTISED_10000baseT_Full (1U << 12) #define ADVERTISED_Pause (1U << 13) #define ADVERTISED_Asym_Pause (1U << 14) #define ADVERTISED_2500baseX_Full (1U << 15) #define ADVERTISED_Backplane (1U << 16) #define ADVERTISED_1000baseKX_Full (1U << 17) #define ADVERTISED_10000baseKX4_Full (1U << 18) #define ADVERTISED_10000baseKR_Full (1U << 19) #define ADVERTISED_10000baseR_FEC (1U << 20) /* TI DP83867 PHY Control Register */ #define PHYCR_TX_FIFO_DEPTH (0xC000U) #define PHYCR_RX_FIFO_DEPTH (0x3000U) #define PHYCR_SGMII_EN (0x0800U) #define PHYCR_FORCE_LINK_GOOD (0x0400U) #define PHYCR_POWER_SAVE_MODE (0x0300U) #define PHYCR_DEEP_POWER_DOWN_EN (0x0080U) #define PHYCR_MDI_CROSSOVER (0x0060U) #define PHYCR_DISABLE_CLK_125 (0x0010U) #define PHYCR_STANDBY_MODE (0x0004U) #define PHYCR_LINE_DRIVER_INV_EN (0x0002U) #define PHYCR_DISABLE_JABBER (0x0001U) /* TI DP83867 Control Register */ #define CTRL_SW_RESET (0x8000U) #define CTRL_SW_RESTART (0x4000U) /* TI DP83867 SGMII Control Register 1 */ #define SGMII_TYPE_6_WIRE (0x4000U) /* Different PHY MDIO addresses for our current designs */ #define PHY_VSC8541_MDIO_ADDR (0U) /* Aloe board PHY */ #define PHY_VSC8575_MDIO_ADDR (4U) /* G5 SoC Emulation Platform Peripheral Daughter Board PHY */ #define PHY_DP83867_MDIO_ADDR (3U) /* G5 SoC Emulation Platform native PHY */ #define PHY_NULL_MDIO_ADDR (0U) /* No PHY here actually... */ #define SGMII_MDIO_ADDR (16U) /* Internal PHY in G5 SoC Emulation Platform SGMII to GMII core */ /**************************************************************************/ /* Public function declarations */ /**************************************************************************/ /***************************************************************************//** void MSS_MAC_phy_init(mss_mac_instance_t *this_mac, uint8_t phy_addr); */ #if MSS_MAC_USE_PHY_VSC8541 void MSS_MAC_VSC8541_phy_init(/* mss_mac_instance_t */ const void *v_this_mac, uint8_t phy_addr); #endif #if MSS_MAC_USE_PHY_VSC8575 || MSS_MAC_USE_PHY_VSC8575_LITE void MSS_MAC_VSC8575_phy_init(/* mss_mac_instance_t */ const void *v_this_mac, uint8_t phy_addr); #endif #if MSS_MAC_USE_PHY_DP83867 void MSS_MAC_DP83867_phy_init(/* mss_mac_instance_t */ const void *v_this_mac, uint8_t phy_addr); #endif #if MSS_MAC_USE_PHY_NULL void MSS_MAC_NULL_phy_init(/* mss_mac_instance_t */ const void *v_this_mac, uint8_t phy_addr); #endif /***************************************************************************//** */ #if MSS_MAC_USE_PHY_VSC8541 void MSS_MAC_VSC8541_phy_set_link_speed(/* mss_mac_instance_t */ const void *v_this_mac, uint32_t speed_duplex_select); #endif #if MSS_MAC_USE_PHY_VSC8575 || MSS_MAC_USE_PHY_VSC8575_LITE void MSS_MAC_VSC8575_phy_set_link_speed(/* mss_mac_instance_t */ const void *v_this_mac, uint32_t speed_duplex_select); #endif #if MSS_MAC_USE_PHY_DP83867 void MSS_MAC_DP83867_phy_set_link_speed(/* mss_mac_instance_t */ const void *v_this_mac, uint32_t speed_duplex_select); #endif #if MSS_MAC_USE_PHY_NULL void MSS_MAC_NULL_phy_set_link_speed(/* mss_mac_instance_t */ const void *v_this_mac, uint32_t speed_duplex_select); #endif /***************************************************************************//** */ #if MSS_MAC_USE_PHY_VSC8541 void MSS_MAC_VSC8541_phy_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac); #endif #if MSS_MAC_USE_PHY_VSC8575 || MSS_MAC_USE_PHY_VSC8575_LITE void MSS_MAC_VSC8575_phy_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac); #endif #if MSS_MAC_USE_PHY_DP83867 void MSS_MAC_DP83867_phy_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac); #endif #if MSS_MAC_USE_PHY_NULL void MSS_MAC_NULL_phy_autonegotiate(/* mss_mac_instance_t */ const void *v_this_mac); #endif /***************************************************************************//** */ #if MSS_MAC_USE_PHY_VSC8541 uint8_t MSS_MAC_VSC8541_phy_get_link_status ( /* mss_mac_instance_t */ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ); #endif #if MSS_MAC_USE_PHY_VSC8575 || MSS_MAC_USE_PHY_VSC8575_LITE uint8_t MSS_MAC_VSC8575_phy_get_link_status ( /* mss_mac_instance_t */ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ); #endif #if MSS_MAC_USE_PHY_DP83867 uint8_t MSS_MAC_DP83867_phy_get_link_status ( /* mss_mac_instance_t */ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ); #endif #if MSS_MAC_USE_PHY_NULL uint8_t MSS_MAC_NULL_phy_get_link_status ( /* mss_mac_instance_t */ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ); #endif #if MSS_MAC_USE_PHY_DP83867 /***************************************************************************//** */ void ti_write_extended_regs(/* mss_mac_instance_t */ const void *v_this_mac, uint16_t reg, uint16_t data); #if MSS_MAC_USE_PHY_NULL void NULL_ti_write_extended_regs(/* mss_mac_instance_t */ const void *v_this_mac, uint16_t reg, uint16_t data); #endif /***************************************************************************//** */ uint16_t ti_read_extended_regs(/* mss_mac_instance_t */ const void *v_this_mac, uint16_t reg); #if MSS_MAC_USE_PHY_NULL uint16_t NULL_ti_read_extended_regs(/* mss_mac_instance_t */ const void *v_this_mac, uint16_t reg); #endif #endif #ifdef __cplusplus } #endif #endif /* PSE_PHY_H */ ti_dp83867_phy.c000066400000000000000000000441451432224323300413460ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * TI DP83867ISRGZ PHY interface driver implementation for use with the G5 SoC * Emulation Platform. * * This system uses the SGMII interface. * * The following are the default selections from the hardware strapping: * * RX_D0 - Strap option 4, PHY_ADD0 = 1, PHY_ADD1 = 1 * RX_D2 - Strap option 0, PHY_ADD2 = 0, PHY_ADD1 = 0 * RX_CTRL - Strap option 0, N/A - the following note applies: * Strap modes 1 and 2 are not applicable for RX_CTRL. The RX_CTRL * strap must be configured for strap mode 3 or strap mode 4. If the * RX_CTRL pin cannot be strapped to mode 3 or mode 4, bit[7] of * Configuration Register 4 (address 0x0031) must be cleared to 0. * GPIO_0 - Strap option 0, RGMII Clock Skew RX[0] = 0. GPIO_0 is connected to * I/O pin AR22 on the VU9P FPGA device. * GPIO_1 - Strap option 0, RGMII Clock Skew RX[1] = 0, * RGMII Clock Skew RX[2] = 0 * LED_2 - Strap option 2, RGMII Clock Skew TX[0] = 1, * RGMII Clock Skew TX[1] = 0 * LED_1 - Strap option 2, RGMII Clock Skew TX[2] = 1, ANEG_SEL = 0 * LED_0 - Strap option 2, SGMII_Enable = 1, Mirror Enable = 0 * */ #include "mss_plic.h" #include "fpga_design_config/fpga_design_config.h" #include "drivers/mss/mss_mac/mss_ethernet_registers.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_regs.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_user_config.h" #include "drivers/mss/mss_mac/mss_ethernet_mac.h" #include "drivers/mss/mss_mac/phy.h" #include "hal/hal.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif #if MSS_MAC_USE_PHY_DP83867 /**************************************************************************/ /* Preprocessor Macros */ /**************************************************************************/ #define BMSR_AUTO_NEGOTIATION_COMPLETE (0x0020U) /**************************************************************************//** * */ void MSS_MAC_DP83867_phy_init(/* mss_mac_instance_t*/ const void *v_this_mac, uint8_t phy_addr) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t phy_reg; (void)phy_addr; /* Start by doing a software reset of the PHY */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_CTRL, CTRL_SW_RESET); /* Enable SGMII interface */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_PHYCR); phy_reg |= PHYCR_SGMII_EN; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_PHYCR, phy_reg); /* Enable 6 wire SGMII so that the 625MHz clock to the SGMII core is active */ #if 0 ti_write_extended_regs(this_mac, MII_TI_SGMIICTL1, SGMII_TYPE_6_WIRE); #endif if(GMII_SGMII == this_mac->interface_type) { /* Reset SGMII core side of I/F. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= 0x9000U; /* Reset and start autonegotiation */ phy_reg &= 0xFBFFU; /* Clear Isolate bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg &= 0xFBFFU; /* Clear Isolate bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= 0x1000U; /* Kick off autonegotiation - belt and braces approach...*/ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); } } /**************************************************************************//** * */ void MSS_MAC_DP83867_phy_set_link_speed(/* mss_mac_instance_t*/ const void *v_this_mac, uint32_t speed_duplex_select) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t phy_reg; uint32_t inc; uint32_t speed_select; const uint16_t mii_advertise_bits[4] = {ADVERTISE_10FULL, ADVERTISE_10HALF, ADVERTISE_100FULL, ADVERTISE_100HALF}; /* Set auto-negotiation advertisement. */ /* Set 10Mbps and 100Mbps advertisement. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE); phy_reg &= (uint16_t)(~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL)); phy_reg |= 0x0C00U; /* Set Asymmetric pause and symmetric pause bits */ speed_select = speed_duplex_select; for(inc = 0U; inc < 4U; ++inc) { uint32_t advertise; advertise = speed_select & 0x00000001U; if(advertise != 0U) { phy_reg |= mii_advertise_bits[inc]; } speed_select = speed_select >> 1; } MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE, phy_reg); /* Set 1000Mbps advertisement. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000); phy_reg &= (uint16_t)(~(ADVERTISE_1000FULL | ADVERTISE_1000HALF)); if((speed_duplex_select & MSS_MAC_ANEG_1000M_FD) != 0U) { phy_reg |= ADVERTISE_1000FULL; } if((speed_duplex_select & MSS_MAC_ANEG_1000M_HD) != 0U) { phy_reg |= ADVERTISE_1000HALF; } MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, phy_reg); } /**************************************************************************//** * */ void MSS_MAC_DP83867_phy_autonegotiate(/* mss_mac_instance_t*/ const void *v_this_mac) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; volatile uint16_t phy_reg; uint16_t autoneg_complete; volatile uint32_t copper_aneg_timeout = 1000000U; volatile uint32_t sgmii_aneg_timeout = 100000U; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 2); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 3); /* Enable auto-negotiation. */ phy_reg = 0x1340U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMCR, phy_reg); /* Wait for copper auto-negotiation to complete. */ do { phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR); autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --copper_aneg_timeout; } while((0u == autoneg_complete) && (0U != copper_aneg_timeout) && (0xFFFFU != phy_reg)); if(GMII_SGMII == this_mac->interface_type) { /* Initiate auto-negotiation on the SGMII link. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U); phy_reg |= 0x1000U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U, phy_reg); phy_reg |= 0x0200U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U, phy_reg); /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMSR); autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)); } } /**************************************************************************//** * */ uint8_t MSS_MAC_DP83867_phy_get_link_status ( /* mss_mac_instance_t*/ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t phy_reg; uint16_t link_up; uint8_t link_status; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR); link_up = phy_reg & BMSR_LSTATUS; if(link_up != MSS_MAC_LINK_DOWN) { uint16_t duplex; uint16_t speed_field; /* Link is up. */ link_status = MSS_MAC_LINK_UP; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x11U); /* Device Auxillary Control and Status */ duplex = phy_reg & 0x2000U; speed_field = phy_reg >> 14; if(MSS_MAC_HALF_DUPLEX == duplex) { *fullduplex = MSS_MAC_HALF_DUPLEX; } else { *fullduplex = MSS_MAC_FULL_DUPLEX; } switch(speed_field) { case 0U: *speed = MSS_MAC_10MBPS; break; case 1U: *speed = MSS_MAC_100MBPS; break; case 2U: *speed = MSS_MAC_1000MBPS; break; default: link_status = (uint8_t)MSS_MAC_LINK_DOWN; break; } } else { /* Link is down. */ link_status = (uint8_t)MSS_MAC_LINK_DOWN; } return link_status; } /**************************************************************************//** * */ /* * TI DP83867 PHY has 32 standard registers and a collection of additional * registers that are accessed through the use of registers 0x0D and 0x0E. * Register 0x0D (REGCR) holds the control bits which determine what register * 0x0E (ADDAR) does. * * The following extended registers are available: * * 0x0025 - Testmode Channel Control * 0x002D - Fast Link Drop Configuration * 0x0031 - Configuration Register 4 * 0x0032 - RGMII Control Register * 0x0033 - RGMII Control Register 2 * 0x0037 - SGMII Auto-Negotiation Status * 0x0043 - 100BASE-TX Configuration * 0x0055 - Skew FIFO Status * 0x006E - Strap Configuration Status Register 1 * 0x006F - Strap Configuration Status Register 2 * 0x0071 - BIST Control and Status Register 1 * 0x0072 - BIST Control and Status Register 2 * 0x0086 - RGMII Delay Control Register * 0x00D3 - SGMII Control Register 1 * 0x00E9 - Sync FIFO Control * 0x00FE - Loopback Configuration Register * 0x0134 - Receive Configuration Register * 0x0135 - Receive Status Register * 0x0136 - Pattern Match Data Register 1 * 0x0137 - Pattern Match Data Register 2 * 0x0138 - Pattern Match Data Register 3 * 0x0139 - SecureOn Pass Register 1 * 0x013A - SecureOn Pass Register 2 * 0x013B - SecureOn Pass Register 3 * 0x013C - 0x015B - Receive Pattern Registers 1 to 32 * 0x015C - Receive Pattern Byte Mask Register 1 * 0x015D - Receive Pattern Byte Mask Register 2 * 0x015E - Receive Pattern Byte Mask Register 3 * 0x015F - Receive Pattern Byte Mask Register 4 * 0x0161 - Receive Pattern Control * 0x016F - 10M SGMII Configuration * 0x0170 - I/O configuration * 0x0172 - GPIO Mux Control Register * 0x0180 - TDR General Configuration Register 1 * 0x01A7 - Advanced Link Cable Diagnostics Control Register * 0x0000 - MMD3 PCS Control Register - indirect addressing only * */ uint16_t phy_reg_list[25] = { 0x0025U, /* 00 Testmode Channel Control */ 0x002DU, /* 01 Fast Link Drop Configuration */ 0x0031U, /* 02 Configuration Register 4 */ 0x0032U, /* 03 RGMII Control Register */ 0x0033U, /* 04 RGMII Control Register 2 */ 0x0037U, /* 05 SGMII Auto-Negotiation Status */ 0x0043U, /* 06 100BASE-TX Configuration */ 0x0055U, /* 07 Skew FIFO Status */ 0x006EU, /* 08 Strap Configuration Status Register 1 */ 0x006FU, /* 09 Strap Configuration Status Register 2 */ 0x0071U, /* 10 BIST Control and Status Register 1 */ 0x0072U, /* 11 BIST Control and Status Register 2 */ 0x0086U, /* 12 RGMII Delay Control Register */ 0x00D3U, /* 13 SGMII Control Register 1 */ 0x00E9U, /* 14 Sync FIFO Control */ 0x00FEU, /* 15 Loopback Configuration Register */ 0x0134U, /* 16 Receive Configuration Register */ 0x0135U, /* 17 Receive Status Register */ 0x016FU, /* 18 10M SGMII Configuration */ 0x0170U, /* 19 I/O configuration */ 0x0172U, /* 20 GPIO Mux Control Register */ 0x0180U, /* 21 TDR General Configuration Register 1 */ 0x01A7U, /* 22 Advanced Link Cable Diagnostics Control Register */ 0x0000U, /* 23 MMD3 PCS Control Register - indirect addressing only */ 0xFFFFU /* 24 End of list... */ }; uint16_t TI_reg_0[32]; uint16_t TI_reg_1[25]; uint16_t TI_MSS_SGMII_reg[17]; uint32_t TI_MSS_MAC_reg[80]; uint32_t TI_MSS_PLIC_REG[80]; void dump_ti_regs(const mss_mac_instance_t * this_mac); void dump_ti_regs(const mss_mac_instance_t * this_mac) { int32_t count; uint16_t old_ctrl; uint16_t old_addr; uint32_t *pbigdata; volatile psr_t lev; for(count = 0; count <= 0x1F; count++) { lev = HAL_disable_interrupts(); TI_reg_0[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count); HAL_restore_interrupts(lev); } lev = HAL_disable_interrupts(); old_ctrl = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR); /* Fetch current REGCR value */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ old_addr = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR); /* Fetch current indirect address */ HAL_restore_interrupts(lev); for(count = 0; 0xFFFFU != phy_reg_list[count]; count++) { lev = HAL_disable_interrupts(); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, phy_reg_list[count]); /* Select new indirect Address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x401FU); /* Select simple data mode */ TI_reg_1[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR); /* Finally, read the data */ HAL_restore_interrupts(lev); } lev = HAL_disable_interrupts(); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, old_addr); /* Restore old address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, old_ctrl); /* Restore old control mode */ HAL_restore_interrupts(lev); for(count = 0; count <= 0x10; count++) { TI_MSS_SGMII_reg[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, (uint8_t)count); } pbigdata = (uint32_t *)0x20110000UL; for(count = 0; count < 19; count++) { TI_MSS_MAC_reg[count] = *pbigdata; pbigdata++; } pbigdata =(uint32_t *)0x0C000000UL; for(count = 0; count < 8; count++) { TI_MSS_PLIC_REG[count] = *pbigdata; pbigdata++; } } /**************************************************************************//** * */ uint16_t ti_read_extended_regs(/* mss_mac_instance_t*/ const void *v_this_mac, uint16_t reg) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t old_ctrl; uint16_t old_addr; uint16_t ret_val = 0U; volatile psr_t lev; lev = HAL_disable_interrupts(); old_ctrl = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR); /* Fetch current REGCR value */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ old_addr = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR); /* Fetch current indirect address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, reg); /* Select new indirect Address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x401FU); /* Select simple data mode */ ret_val = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR); /* Finally, read the data */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, old_addr); /* Restore old address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, old_ctrl); /* Restore old control mode */ HAL_restore_interrupts(lev); return(ret_val); } /**************************************************************************//** * */ void ti_write_extended_regs(/* mss_mac_instance_t*/ const void *v_this_mac, uint16_t reg, uint16_t data) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t old_ctrl; uint16_t old_addr; volatile psr_t lev; lev = HAL_disable_interrupts(); old_ctrl = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR); /* Fetch current REGCR value */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ old_addr = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR); /* Fetch current indirect address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, reg); /* Select new indirect Address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x401FU); /* Select simple data mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, data); /* Now write the data */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, 0x001FU); /* Select Address mode */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_ADDAR, old_addr); /* Restore old address */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_TI_REGCR, old_ctrl); /* Restore old control mode */ HAL_restore_interrupts(lev); } #endif /* #if defined(TARGET_ALOE) */ #ifdef __cplusplus } #endif /******************************** END OF FILE ******************************/ vsc8541_phy.c000066400000000000000000000242661432224323300407460ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microsemi VSC8541 PHY interface driver implementation to support the FU540 * Aloe board. * * SVN $Revision$ * SVN $Date$ */ #include "mss_plic.h" #include "fpga_design_config/fpga_design_config.h" #include "drivers/mss/mss_mac/mss_ethernet_registers.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_regs.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_user_config.h" #include "drivers/mss/mss_mac/mss_ethernet_mac.h" #include "drivers/mss/mss_mac/phy.h" #include "hal/hal.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif #if MSS_MAC_USE_PHY_VSC8541 /**************************************************************************/ /* Preprocessor Macros */ /**************************************************************************/ #define BMSR_AUTO_NEGOTIATION_COMPLETE (0x0020U) /**************************************************************************//** * */ typedef struct { __IO uint32_t INPUT_VAL; /* 0x0000 */ __IO uint32_t INPUT_EN; /* 0x0004 */ __IO uint32_t OUTPUT_VAL; /* 0x0008 */ __IO uint32_t OUTPUT_EN; /* 0x000C */ __IO uint32_t PUE; /* 0x0010 */ __IO uint32_t DS; /* 0x0014 */ __IO uint32_t RISE_IE; /* 0x0018 */ __IO uint32_t RISE_IP; /* 0x001C */ __IO uint32_t FALL_IE; /* 0x0020 */ __IO uint32_t FALL_IP; /* 0x0024 */ __IO uint32_t HIGH_IE; /* 0x0028 */ __IO uint32_t HIGH_IP; /* 0x002C */ __IO uint32_t LOW_IE; /* 0x0030 */ __IO uint32_t LOW_IP; /* 0x0034 */ __IO uint32_t reserved0; /* 0x0038 */ __IO uint32_t reserved1; /* 0x003C */ __IO uint32_t OUT_XOR; /* 0x0040 */ } AloeGPIO_TypeDef; void MSS_MAC_VSC8541_phy_init(/* mss_mac_instance_t*/ const void *v_this_mac, uint8_t phy_addr) { #if defined(TARGET_ALOE) volatile uint32_t loop; AloeGPIO_TypeDef *g_aloe_gpio = (AloeGPIO_TypeDef *)0x10060000UL; (void)v_this_mac; (void)phy_addr; /* * Init includes toggling the reset line which is connected to GPIO 0 pin 12. * This is the only pin I can see on the 16 GPIO which is currently set as an. * output. We will hard code the setup here to avoid having to have a GPIO * driver as well... * * The Aloe board is strapped for unmanaged mode and needs two pulses of the * reset line to configure the device properly. * * The RX_CLK, TX_CLK and RXD7 pins are strapped high and the remainder low. * This selects GMII mode with auto 10/100/1000 and 125MHz clkout. */ g_aloe_gpio->OUTPUT_EN |= 0x00001000UL; /* Configure pin 12 as an output */ g_aloe_gpio->OUTPUT_VAL &= 0x0000EFFFUL; /* Clear pin 12 to reset PHY */ for(loop = 0U; loop != 1000U; loop++) /* Short delay, I'm not sure how much is needed... */ { ; } g_aloe_gpio->OUTPUT_VAL |= 0x00001000UL; /* Take PHY^ out of reset */ for(loop = 0U; loop != 1000U; loop++) /* Short delay, I'm not sure how much is needed... */ { ; } g_aloe_gpio->OUTPUT_VAL &= 0x0000EFFFUL; /* Second reset pulse */ for(loop = 0U; loop != 1000U; loop++) /* Short delay, I'm not sure how much is needed... */ { ; } g_aloe_gpio->OUTPUT_VAL |= 0x00001000UL; /* Out of reset once more */ /* Need at least 15mS delay before accessing PHY after reset... */ for(loop = 0U; loop != 10000000U; loop++) /* Long delay, I'm not sure how much is needed... */ { ; } #endif } /**************************************************************************//** * */ void MSS_MAC_VSC8541_phy_set_link_speed(/* mss_mac_instance_t*/ const void *v_this_mac, uint32_t speed_duplex_select) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t phy_reg; uint32_t inc; uint32_t speed_select; const uint16_t mii_advertise_bits[4] = {ADVERTISE_10FULL, ADVERTISE_10HALF, ADVERTISE_100FULL, ADVERTISE_100HALF}; /* Set auto-negotiation advertisement. */ /* Set 10Mbps and 100Mbps advertisement. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE); phy_reg &= (uint16_t)(~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL)); speed_select = speed_duplex_select; for(inc = 0U; inc < 4U; ++inc) { uint32_t advertise; advertise = speed_select & 0x00000001U; if(advertise != 0U) { phy_reg |= mii_advertise_bits[inc]; } speed_select = speed_select >> 1U; } MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE, phy_reg); /* Set 1000Mbps advertisement. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000); phy_reg &= (uint16_t)(~(ADVERTISE_1000FULL | ADVERTISE_1000HALF)); if((speed_duplex_select & MSS_MAC_ANEG_1000M_FD) != 0U) { phy_reg |= ADVERTISE_1000FULL; } if((speed_duplex_select & MSS_MAC_ANEG_1000M_HD) != 0U) { phy_reg |= ADVERTISE_1000HALF; } MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_CTRL1000, phy_reg); } /**************************************************************************//** * */ void MSS_MAC_VSC8541_phy_autonegotiate(/* mss_mac_instance_t*/ const void *v_this_mac) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; volatile uint16_t phy_reg; uint16_t autoneg_complete; volatile uint32_t copper_aneg_timeout = 1000000U; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 2U); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 3U); /* Enable auto-negotiation. */ phy_reg = 0x1340U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMCR, phy_reg); /* Wait for copper auto-negotiation to complete. */ do { phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR); autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --copper_aneg_timeout; } while(((0U == autoneg_complete) && (copper_aneg_timeout != 0u)) || (0xFFFF == phy_reg)); } /**************************************************************************//** * */ uint8_t MSS_MAC_VSC8541_phy_get_link_status ( /* mss_mac_instance_t*/ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t phy_reg; uint16_t link_up; uint8_t link_status; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR); link_up = phy_reg & BMSR_LSTATUS; if(link_up != MSS_MAC_LINK_DOWN) { uint16_t duplex; uint16_t speed_field; /* Link is up. */ link_status = MSS_MAC_LINK_UP; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1CU); /* Device Auxillary Control and Status */ duplex = phy_reg & 0x0020U; speed_field = phy_reg & 0x0018U; if(MSS_MAC_HALF_DUPLEX == duplex) { *fullduplex = MSS_MAC_HALF_DUPLEX; } else { *fullduplex = MSS_MAC_FULL_DUPLEX; } switch(speed_field >> 3) { case 0U: *speed = MSS_MAC_10MBPS; break; case 1U: *speed = MSS_MAC_100MBPS; break; case 2U: *speed = MSS_MAC_1000MBPS; break; default: link_status = (uint8_t)MSS_MAC_LINK_DOWN; break; } } else { /* Link is down. */ link_status = (uint8_t)MSS_MAC_LINK_DOWN; } return link_status; } /**************************************************************************//** * */ uint16_t VSC8541_reg_0[32]; uint16_t VSC8541_reg_1[16]; uint16_t VSC8541_reg_2[16]; uint16_t VSC8541_reg_16[32]; void dump_vsc8541_regs(const mss_mac_instance_t * this_mac); void dump_vsc8541_regs(const mss_mac_instance_t * this_mac) { int32_t count; uint16_t page; uint16_t old_page; uint16_t *pdata; volatile psr_t lev; for(page = 0U; page <= 0x10U; page++) { if(0U == page) { pdata = VSC8541_reg_0; } else if(1U == page) { pdata = VSC8541_reg_1; } else if(2U == page) { pdata = VSC8541_reg_2; } else if(16U == page) { pdata = VSC8541_reg_16; } else { pdata = VSC8541_reg_0; } if((0U == page) || (0x10U == page)) { for(count = 0; count <= 0x1F; count++) { lev = HAL_disable_interrupts(); old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page); pdata[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); HAL_restore_interrupts(lev); } } else { for(count = 0x10; count <= 0x1F; count++) { lev = HAL_disable_interrupts(); old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page); pdata[count - 0X10] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); HAL_restore_interrupts(lev); } } if(2U == page) { page = 0x0FU; } } } #endif /* #if defined(TARGET_ALOE) */ #ifdef __cplusplus } #endif /******************************** END OF FILE ******************************/ vsc8575_phy.c000066400000000000000000000761641432224323300407610ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microsemi VSC8575 PHY interface driver implementation to support the * peripheral daughter board for the G5 SoC Emulation Platform. * * SVN $Revision$ * SVN $Date$ * */ #include "mss_plic.h" #include "drivers/mss/mss_mac/mss_ethernet_registers.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_regs.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_user_config.h" #include "drivers/mss/mss_mac/mss_ethernet_mac.h" #include "drivers/mss/mss_mac/phy.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_types.h" #include "mss_plic.h" #include "fpga_design_config/fpga_design_config.h" #include "mss_coreplex.h" #include "hal/hal.h" #include #include #include #include #if MSS_MAC_USE_PHY_VSC8575 #include "vtss_api.h" /* For BOOL and friends */ #include "vtss_phy_api.h" /* For PHY API Pre and Post Resets */ #include "vtss_init_api.h" extern int32_t viper_fmc_board_init(vtss_init_conf_t *config); #endif #if MSS_MAC_USE_PHY_VSC8575_LITE #include "vtss_phy_common.h" #include "vtss_viper_phy_prototypes.h" extern int32_t viper_fmc_board_init(struct phy_control_t *control); #endif #ifdef __cplusplus extern "C" { #endif /**************************************************************************/ /* Preprocessor Macros */ /**************************************************************************/ #define BMSR_AUTO_NEGOTIATION_COMPLETE (0x0020U) /**************************************************************************//** * */ uint16_t VSC8575_reg_0[32]; uint16_t VSC8575_reg_1[16]; uint16_t VSC8575_reg_2[16]; uint16_t VSC8575_reg_3[20]; /* Additional 4 to hold MAC Serdes RX and TX stats */ uint16_t VSC8575_reg_4[16]; uint16_t VSC8575_reg_16[32]; uint16_t VSC8575_MSS_SGMII_reg16[17]; uint32_t VSC8575_MSS_MAC_reg[80]; uint32_t VSC8575_MSS_PLIC_REG[80]; void dump_vsc8575_regs(const mss_mac_instance_t * this_mac); void dump_vsc8575_regs(const mss_mac_instance_t * this_mac) { int32_t count; uint16_t page; uint16_t old_page; uint16_t *pdata; volatile psr_t lev; for(page = 0U; page <= 0x10U; page++) { if(0U == page) { pdata = VSC8575_reg_0; } else if(1U == page) { pdata = VSC8575_reg_1; } else if(2U == page) { pdata = VSC8575_reg_2; } else if(3U == page) { pdata = VSC8575_reg_3; } else if(4U == page) { pdata = VSC8575_reg_4; } else if(16U == page) { pdata = VSC8575_reg_16; } else { pdata = VSC8575_reg_0; } if((0U == page) || (0x10U == page)) { for(count = 0; count <= 0x1F; count++) { lev = HAL_disable_interrupts(); old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page); pdata[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, (uint8_t)count); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); HAL_restore_interrupts(lev); } } else { for(count = 0x10; count <= 0x1F; count++) { lev = HAL_disable_interrupts(); old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page); pdata[count - 0X10] = MSS_MAC_read_phy_reg(this_mac,(uint8_t) this_mac->phy_addr, (uint8_t)count); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); HAL_restore_interrupts(lev); } if(3U == page) /* Circle back and get MAC Serdes stats... */ { lev = HAL_disable_interrupts(); old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, page); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, 0x4000U); /* Select MAC stats */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x16U, 0x4000U); /* Select MAC stats */ pdata[0x10] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1CU); /* Fetch MAC stats */ pdata[0x11] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU); pdata[0x12] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x15U); /* Fetch MAC stats */ pdata[0x13] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x16U); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x16U, 0x0000U); /* Select Media stats */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, 0x0000U); /* Select Media stats */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); HAL_restore_interrupts(lev); } } if(4U == page) { page = 0x0FU; } } for(count = 0; count <= 0x10; count++) { VSC8575_MSS_SGMII_reg16[count] = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, (uint8_t)count); } #if 0 /* Only enable as necessary as reading some regs can interfere with ISR operation */ { uint32_t *pbigdata; pbigdata = (uint32_t *)0x20110000UL; for(count = 0; count < 19; count++, pbigdata++) { VSC8575_MSS_MAC_reg[count] = *pbigdata; } pbigdata =(uint32_t *)0x0C000000UL; for(count = 0; count < 8; count++, pbigdata++) { VSC8575_MSS_PLIC_REG[count] = *pbigdata; } } #endif } /**************************************************************************//** * Note: The following assumes there is only one VSC8757 PHY in the system. * We will need to revisit it at some stage to provide for multiple * devices connected to separate GEMs or for the case of multiple * GEMs connected to the same PHY but to different ports. * * For now we need to at least record somewhere which GEM this PHY * is associated with so that the MDIO functions can work correctly as * it is currently assumed GEM0 is the one connected to the VSC8575. * * May need to consider adding entry to vtss_inst_t to hold the mac * reference so MDIO can figure out who to talk to. This will also mean * that the some or all of following globals will need to be changed to * allow for multiple connections... * */ mss_mac_instance_t *g_my_mac = (mss_mac_instance_t *)0; #if MSS_MAC_USE_PHY_VSC8575 void MSS_MAC_VSC8575_phy_init(/* mss_mac_instance_t*/ const void *v_this_mac, uint8_t phy_addr) { static vtss_inst_t g_vtss_inst_p; static vtss_inst_create_t g_vtss_create_inst; static vtss_init_conf_t g_vtss_init_conf; static vtss_phy_conf_t g_phy; static vtss_phy_conf_1g_t g_phy_conf_1g; static vtss_phy_reset_conf_t g_phy_reset_conf; static vtss_phy_reset_conf_t vts_phy_init_params = {VTSS_PORT_INTERFACE_SGMII, VTSS_PHY_MEDIA_IF_CU, {1,2}, {TRUE},VTSS_PHY_FORCE_RESET, VTSS_PHY_PKT_MODE_IEEE_1_5_KB, TRUE}; const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; volatile vtss_rc vrc; volatile int32_t vrc_i32; (void)phy_addr; g_my_mac = this_mac; /* For now, simply record which MAC we are associated with * assuming there is only one... */ (void)memset (&g_phy, 0, sizeof(vtss_phy_conf_t)); g_vtss_create_inst.target = VTSS_TARGET_CU_PHY; vrc = vtss_inst_create(&g_vtss_create_inst, &g_vtss_inst_p); vrc = vtss_init_conf_get(g_vtss_inst_p, &g_vtss_init_conf); vrc_i32 = viper_fmc_board_init(&g_vtss_init_conf); g_vtss_init_conf.warm_start_enable = 0; g_vtss_init_conf.restart_info_src = VTSS_RESTART_INFO_SRC_CU_PHY; g_vtss_init_conf.restart_info_port = 0; vrc = vtss_init_conf_set(g_vtss_inst_p, &g_vtss_init_conf); (void)memset(&g_phy_reset_conf, 0, sizeof(g_phy_reset_conf)); g_phy_reset_conf.mac_if = VTSS_PORT_INTERFACE_SGMII; g_phy_reset_conf.media_if = VTSS_PHY_MEDIA_IF_CU; g_phy_reset_conf.rgmii.rx_clk_skew_ps = 0; g_phy_reset_conf.rgmii.tx_clk_skew_ps = 0; g_phy_reset_conf.tbi.aneg_enable = 1; vrc = vtss_phy_pre_reset(g_vtss_inst_p, 0); /* HH: unsure why vts_phy_init_params being passed instead of g_phy_reset_conf to vtss_phy_reset(...) ??? */ vrc = vtss_phy_reset(g_vtss_inst_p, 0, &vts_phy_init_params); /* HH: moved SerDes calibration to after the MAC PCS settings configured */ /* Configure PHY 1G master/slave preference (for SyncE timing) */ (void)memset(&g_phy_conf_1g, 0, sizeof(g_phy_conf_1g)); /* HH: conf_get to pre-populate all entries with valid defaults, prior to application settings */ vtss_phy_conf_get(g_vtss_inst_p, 0 /* port_no */, &g_phy); g_phy_conf_1g.master.cfg = TRUE; /* 1=Enabled */ g_phy_conf_1g.master.val = TRUE; /* 1=Master */ /* HH move conf get/set until after port conf setting configured below */ g_phy.mode = VTSS_PHY_MODE_ANEG; /* Example for PHY speed support for auto-neg */ g_phy.aneg.speed_10m_hdx = 1; g_phy.aneg.speed_10m_fdx = 1; g_phy.aneg.speed_100m_hdx = 1; g_phy.aneg.speed_100m_fdx = 1; g_phy.aneg.speed_1g_hdx = 0; g_phy.aneg.speed_1g_fdx = 1; g_phy.sigdet = VTSS_PHY_SIGDET_POLARITY_ACT_HIGH; /* Example for PHY flow control settings */ g_phy.aneg.symmetric_pause = 1; g_phy.aneg.tx_remote_fault = 1; g_phy.mdi = VTSS_PHY_MDIX_AUTO; /* always enable auto detection of crossed/non-crossed cables */ g_phy.flf = VTSS_PHY_FAST_LINK_FAIL_DISABLE; /* Setup the MAC Interface PCS Parameters */ g_phy.mac_if_pcs.disable = 0; g_phy.mac_if_pcs.restart = 0; g_phy.mac_if_pcs.pd_enable = 0; g_phy.mac_if_pcs.aneg_restart = 0; g_phy.mac_if_pcs.force_adv_ability = 0; g_phy.mac_if_pcs.sgmii_in_pre = VTSS_PHY_MAC_SERD_PCS_SGMII_IN_PRE_NONE; g_phy.mac_if_pcs.sgmii_out_pre = 0; g_phy.mac_if_pcs.serdes_aneg_ena = 1; g_phy.mac_if_pcs.serdes_pol_inv_in = 0; g_phy.mac_if_pcs.serdes_pol_inv_out = 0; g_phy.mac_if_pcs.fast_link_stat_ena = 0; g_phy.mac_if_pcs.inhibit_odd_start = 0; /* Does nothing as this bit id default on... */ /* Setup the MEDIA Interface PCS Parameters */ g_phy.media_if_pcs.remote_fault = VTSS_PHY_MEDIA_SERD_PCS_REM_FAULT_NO_ERROR; g_phy.media_if_pcs.aneg_pd_detect = 0; g_phy.media_if_pcs.force_adv_ability = 0; g_phy.media_if_pcs.serdes_pol_inv_in = 0; g_phy.media_if_pcs.serdes_pol_inv_out = 0; g_phy.media_if_pcs.inhibit_odd_start = 1; g_phy.media_if_pcs.force_hls = 0; g_phy.media_if_pcs.force_fefi = 0; g_phy.media_if_pcs.force_fefi_value = 0; #if 0 { vtss_phy_clock_conf_t clock_conf; clock_conf.freq = VTSS_PHY_FREQ_125M; clock_conf.squelch = VTSS_PHY_CLK_SQUELCH_MAX; clock_conf.src = 0; vtss_phy_clock_conf_set(g_vtss_inst_p, 0, 0, &clock_conf); } #endif vrc = vtss_phy_conf_set(g_vtss_inst_p, 0 /*port_no*/, &g_phy); /* HH: moved SerDes calibration here */ vrc = vtss_phy_post_reset(g_vtss_inst_p, 0); { uint16_t old_page; uint16_t temp_reg; old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 3U); temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U); temp_reg &= (uint16_t)(~0x0010U); /* Clear media inhibit odd start delay bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, temp_reg); temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U); temp_reg &= (uint16_t)(~0x0004U); /* Clear mac inhibit odd start delay bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg); temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U); temp_reg &= (uint16_t)(~0x0100U); /* Turn off 2 byte preamble */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); } { uint16_t phy_reg; volatile uint32_t sgmii_aneg_timeout = 100000U; uint16_t autoneg_complete; if(TBI == this_mac->interface_type) { phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL; phy_reg |= 0x1000U; this_mac->mac_base->PCS_CONTROL = phy_reg; phy_reg |= 0x0200U; this_mac->mac_base->PCS_CONTROL = phy_reg; /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS; autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while(((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)) || (0xFFFF == phy_reg)); } if(GMII_SGMII == this_mac->interface_type) { /* * SGMII to GMII core with embedded MDIO interface for SGMII * link control. * * Reset SGMII core side of I/F. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= 0x9000U; /* Reset and start autonegotiation */ phy_reg &= 0xFBFFU; /* Clear Isolate bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= 0x1000U; /* start autonegotiation */ phy_reg &= 0xFBFFU; /* Clear gmii Isolate bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); } #if 0 /* Far-end loopback - enable at your peril... DO NOT try this on an open network*/ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U); phy_reg |= 0x8U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, phy_reg); #endif /* LED control - configure LED 0 as RX indicator and LED 1 as TX indicator */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU); phy_reg &= 0xFF00U; phy_reg |= 0x00ABU; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU); phy_reg |= 0x4000U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU, phy_reg); #if 0 /* Ethernet Packet Generator - enable at your peril... DO NOT try this on an open network */ old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 1U); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU); phy_reg |= 0xC000U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); #endif } } #endif /* MSS_MAC_USE_PHY_VSC8575 */ #if MSS_MAC_USE_PHY_VSC8575_LITE extern int32_t usleep(uint32_t usecs); void MSS_MAC_VSC8575_phy_init(/* mss_mac_instance_t*/ const void *v_this_mac, uint8_t phy_addr) { static vsc_phy_loopback_t loopback; static vsc_phy_control_t cntrl; static vsc_phy_conf_t phy_config; static vsc_phy_port_status_t phy_status; uint16_t old_page; uint16_t temp_reg; uint16_t phy_reg; volatile uint32_t sgmii_aneg_timeout = 100000U; uint16_t autoneg_complete; const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; volatile int32_t rc; /* Volatile so we can see rc when debugging as * otherwise it tends to get removed as we don't use * it. */ (void)phy_addr; /* For now, simply record which MAC we are associated with, this is not * going to work with more than 1 VSC8575 in the system so we should really * have this stored in the cntrl structure but this involves modifying the * API code... */ g_my_mac = this_mac; /* Start out blank for consistency */ (void)memset (&cntrl, 0, sizeof(cntrl)); (void)memset (&phy_config, 0, sizeof(phy_config)); (void)memset (&phy_status, 0, sizeof(phy_status)); (void)memset (&loopback, 0, sizeof(vsc_phy_loopback_t)); phy_config.mode = VSC_PHY_MODE_ANEG; /* Forced Mode Config */ phy_config.forced.port_speed = VSC_SPEED_1G; phy_config.forced.fdx = 1; /* ANEG Config */ phy_config.aneg.speed_10m_hdx = 1U; phy_config.aneg.speed_10m_fdx = 1U; phy_config.aneg.speed_100m_hdx = 1U; phy_config.aneg.speed_100m_fdx = 1U; phy_config.aneg.speed_1g_hdx = 0U; phy_config.aneg.speed_1g_fdx = 1U; phy_config.aneg.symmetric_pause = 1U; phy_config.aneg.asymmetric_pause = 0U; phy_config.aneg.tx_remote_fault = 1U; /* forced Mode, 1G Config of Master/Slave */ phy_config.conf_1g.master.cfg = 0U; /* Manual Master/Slave config to Force Master cfg */ phy_config.conf_1g.master.val = 0U; /* Master=1, Slave=0 */ /* MDI/MDIX Config */ phy_config.mdi = VSC_PHY_AUTO_MDIX; /* FastLink Fail Config */ phy_config.flf.flf = VSC_PHY_FAST_LINK_FAIL_DISABLE; /* SigDet Config */ phy_config.sigdet = VSC_PHY_SIGDET_POLARITY_ACT_HIGH; /* UniDirectional Config */ phy_config.unidir = VSC_PHY_UNIDIR_DISABLE; /* Pkt Mode Config */ phy_config.pkt_mode = VSC_PHY_PKT_MODE_IEEE_1_5_KB; /* MAC PCS Config */ /* Note: MAC PCS Config only sets bits, does not clear bits */ /* Therefore, to use Chip Defaults, just use all 0's */ phy_config.mac_if_pcs.disable = 0U; phy_config.mac_if_pcs.restart = 0U; phy_config.mac_if_pcs.pd_enable = 0U; phy_config.mac_if_pcs.aneg_restart = 0U; phy_config.mac_if_pcs.force_adv_ability = 0U; phy_config.mac_if_pcs.sgmii_in_pre = 0U; phy_config.mac_if_pcs.sgmii_out_pre = 0U; phy_config.mac_if_pcs.serdes_aneg_ena = 1U; phy_config.mac_if_pcs.serdes_pol_inv_in = 0U; phy_config.mac_if_pcs.serdes_pol_inv_out = 0U; phy_config.mac_if_pcs.fast_link_stat_ena = 0U; phy_config.mac_if_pcs.inhibit_odd_start = 0U; /* Media PCS Config */ /* Note: Media PCS Config only sets bits, does not clear bits */ /* Therefore, to use Chip Defaults, just use all 0's */ phy_config.media_if_pcs.remote_fault = VSC_PHY_MEDIA_SERD_PCS_REM_FAULT_NO_ERROR; phy_config.media_if_pcs.aneg_pd_detect = 1U; phy_config.media_if_pcs.force_adv_ability = 0U; phy_config.media_if_pcs.serdes_pol_inv_in = 0U; phy_config.media_if_pcs.serdes_pol_inv_out = 0U; phy_config.media_if_pcs.inhibit_odd_start = 1U; phy_config.media_if_pcs.force_hls = 0U; phy_config.media_if_pcs.force_fefi = 0U; phy_config.media_if_pcs.force_fefi_value = 0U; rc = viper_fmc_board_init(&cntrl); cntrl.phy_addr = 0U; /* This is actually the port number 0-3 on the VSC8575 */ cntrl.phy_usleep = usleep; rc = vsc_get_phy_type(&cntrl); cntrl.mac_if = PHY_MAC_IF_MODE_SGMII; cntrl.media_if = PHY_MEDIA_IF_CU; /*------------------------------------------------------------------------------------------------ * Initialize PHY, Only run on Base Port of the PHY, Run any Init Scripts and Micro-Patch Downloads *------------------------------------------------------------------------------------------------*/ rc = initialize_viper_phy(&cntrl); /*------------------------------------------------------------------------------------------------ * Reset the PHY Port, Run on each Port of the PHY, Run any configs, etc. *------------------------------------------------------------------------------------------------*/ rc = reset_viper_phy(&cntrl); rc = viper_phy_config_set(&cntrl, &phy_config); /* The cntrl struct only saves the MEDIA i/f for the current port */ /* Adjust the 1G SerDes SigDet Input Threshold and Signal Sensitivity for 100FX */ /* This function gets called from Port 0, ie. cntrl->portAddr == BasePort * The tgt_port_no is the port_no that the operation is to occur upon. * The tgt_media_if is the tgt_port_no's Media i/f setting, which may or may * not be the same as Port 0, found in the cntl struct. */ #if 0 /* Not needed for our setup as we are Cu only... */ cntrl.phy_addr = 0U; rc = viper_phy_media_sig_adjust(&cntrl, cntrl.media_if, 0); #endif /*------------------------------------------------------------------------------------------------ * Post-Reset the PHY, Run on the Base Port of the PHY, This will release Comma Mode *------------------------------------------------------------------------------------------------*/ /* Now Run Post Reset on PHY Port 0, Initialized the 6G SerDes */ rc = post_reset_viper_phy(&cntrl); /*------------------------------------------------------------------------------------------------ * Manually tweak some settings in the PHY *------------------------------------------------------------------------------------------------*/ old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 3U); temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U); temp_reg &= (uint16_t)(~0x0010U); /* Clear media inhibit odd start delay bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, temp_reg); temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U); temp_reg &= (uint16_t)(~0x0004U); /* Clear mac inhibit odd start delay bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg); temp_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U); temp_reg &= (uint16_t)(~0x0100U); /* Turn off 2 byte preamble */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x10U, temp_reg); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); if(TBI == this_mac->interface_type) { phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL; phy_reg |= 0x1000U; this_mac->mac_base->PCS_CONTROL = phy_reg; phy_reg |= 0x0200U; this_mac->mac_base->PCS_CONTROL = phy_reg; /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS; autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while(((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)) || (0xFFFFU == phy_reg)); } if(GMII_SGMII == this_mac->interface_type) { /* * SGMII to GMII core with embedded MDIO interface for SGMII * link control. * * Reset SGMII core side of I/F. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= 0x9000U; /* Reset and start autonegotiation */ phy_reg &= 0xFBFFU; /* Clear Isolate bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR); phy_reg |= 0x1000U; /* start autonegotiation */ phy_reg &= 0xFBFFU; /* Clear gmii Isolate bit */ MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMCR, phy_reg); } #if 0 /* Far-end loopback - enable at your peril... DO NOT try this on an open network*/ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U); phy_reg |= 0x8U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x17U, phy_reg); #endif /* LED control - configure LED 0 as RX indicator and LED 1 as TX indicator */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU); phy_reg &= 0xFF00U; phy_reg |= 0x00ABU; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU); phy_reg |= 0x4000U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1EU, phy_reg); #if 0 /* Ethernet Packet Generator - enable at your peril... DO NOT try this on an open network */ old_page = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, 1U); phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU); phy_reg |= 0xC000U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1DU, phy_reg); MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1FU, old_page); #endif } #endif /* MSS_MAC_USE_PHY_VSC8575_LITE */ /**************************************************************************//** * */ void MSS_MAC_VSC8575_phy_set_link_speed(/* mss_mac_instance_t*/ const void *v_this_mac, uint32_t speed_duplex_select) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint16_t phy_reg; uint32_t inc; uint32_t speed_select; const uint16_t mii_advertise_bits[4] = {ADVERTISE_10FULL, ADVERTISE_10HALF, ADVERTISE_100FULL, ADVERTISE_100HALF}; /* Set auto-negotiation advertisement. */ /* Set 10Mbps and 100Mbps advertisement. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE); phy_reg &= (uint16_t)(~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL)); speed_select = speed_duplex_select; for(inc = 0U; inc < 4U; ++inc) { uint32_t advertise; advertise = speed_select & 0x00000001U; if(advertise != 0U) { phy_reg |= mii_advertise_bits[inc]; } speed_select = speed_select >> 1; } MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_ADVERTISE, phy_reg); } /**************************************************************************//** * */ void MSS_MAC_VSC8575_phy_autonegotiate(/* mss_mac_instance_t*/ const void *v_this_mac) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; uint8_t link_fullduplex; mss_mac_speed_t link_speed; uint8_t copper_link_up; volatile uint16_t phy_reg; uint16_t autoneg_complete; volatile uint32_t sgmii_aneg_timeout = 100000U; copper_link_up = this_mac->phy_get_link_status(this_mac, &link_speed, &link_fullduplex); if(1U == copper_link_up) { #if 0 /* PMCS fixup */ SYSREG->MAC_CR = (SYSREG->MAC_CR & ~MAC_CONFIG_SPEED_MASK) | link_speed; /* Configure duplex mode */ if(0U == link_fullduplex) { /* half duplex */ MAC->CFG2 &= ~CFG2_FDX_MASK; } else { /* full duplex */ MAC->CFG2 |= CFG2_FDX_MASK; } #endif if(TBI == this_mac->interface_type) { phy_reg = (uint16_t)this_mac->mac_base->PCS_CONTROL; phy_reg |= 0x1000U; this_mac->mac_base->PCS_CONTROL = phy_reg; phy_reg |= 0x0200U; this_mac->mac_base->PCS_CONTROL = phy_reg; /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = (uint16_t)this_mac->mac_base->PCS_STATUS; autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while(((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)) || (0xFFFFU == phy_reg)); } if(GMII_SGMII == this_mac->interface_type) { /* * SGMII to GMII core with embedded MDIO interface for SGMII * link control. * * Initiate auto-negotiation on the SGMII link. */ phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U); phy_reg |= 0x1000U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U, phy_reg); phy_reg |= 0x0200U; MSS_MAC_write_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, 0x00U, phy_reg); /* Wait for SGMII auto-negotiation to complete. */ do { phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->pcs_phy_addr, MII_BMSR); autoneg_complete = phy_reg & BMSR_AUTO_NEGOTIATION_COMPLETE; --sgmii_aneg_timeout; } while((0U == autoneg_complete) && (0U != sgmii_aneg_timeout)); } } } /**************************************************************************//** * */ uint8_t MSS_MAC_VSC8575_phy_get_link_status ( /* mss_mac_instance_t*/ const void *v_this_mac, mss_mac_speed_t * speed, uint8_t * fullduplex ) { const mss_mac_instance_t *this_mac = (const mss_mac_instance_t *)v_this_mac; volatile uint16_t phy_reg; uint16_t copper_link_up; uint8_t link_status; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, MII_BMSR); copper_link_up = phy_reg & BMSR_LSTATUS; if(copper_link_up != MSS_MAC_LINK_DOWN) { uint16_t op_mode; /* Link is up. */ link_status = MSS_MAC_LINK_UP; phy_reg = MSS_MAC_read_phy_reg(this_mac, (uint8_t)this_mac->phy_addr, 0x1CU); op_mode = (phy_reg >> 3) & 0x0003U; if(0U == (phy_reg & 0x0020U)) { *fullduplex = MSS_MAC_HALF_DUPLEX; } else { *fullduplex = MSS_MAC_FULL_DUPLEX; } switch(op_mode) { case 0U: *speed = MSS_MAC_10MBPS; break; case 1U: *speed = MSS_MAC_100MBPS; break; case 2U: *speed = MSS_MAC_1000MBPS; break; default: link_status = (uint8_t)MSS_MAC_LINK_DOWN; break; } } else { /* Link is down. */ link_status = (uint8_t)MSS_MAC_LINK_DOWN; } return link_status; } #ifdef __cplusplus } #endif /******************************** END OF FILE ******************************/ vsc8575_support.c000066400000000000000000000372461432224323300416730ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_ethernet_mac/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Support routines for the VTS API for the Microsemi VSC8575 PHY interface * to support the peripheral daughter board for the G5 SoC Emulation Platform. * * SVN $Revision$ * SVN $Date$ * */ #include #include /* For va_list */ #include #include #include #include #include "drivers/mss/mss_mac/mss_ethernet_mac_user_config.h" #if MSS_MAC_USE_PHY_VSC8575 #include "vtss_api.h" /* For BOOL and friends */ #include "vtss_phy_api.h" /* For PHY API Pre and Post Resets */ #endif #if MSS_MAC_USE_PHY_VSC8575_LITE #include "vtss_phy_common.h" #include "vtss_viper_phy_prototypes.h" #endif #include "mss_plic.h" #include "drivers/mss/mss_mac/mss_ethernet_registers.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_regs.h" #include "drivers/mss/mss_mac/mss_ethernet_mac.h" #include "drivers/mss/mss_mac/phy.h" #include "drivers/mss/mss_mac/mss_ethernet_mac_types.h" #ifdef _ZL303XX_FMC_BOARD /* Only needed if SPI interfaces required */ #include "mss_spi.h" #include "core_spi.h" #endif /* Kernel includes. */ #if defined(USING_FREERTOS) #include "FreeRTOS.h" #include "task.h" #else extern volatile uint64_t g_tick_counter; #endif /* Uncomment the following to enable logging of MDIO writes to memory */ /* VSC8575_DEBUG_MDIO */ #ifdef __DEBUG_SOCKET__ #ifndef T_E #define T_E(...) \ printf("Error: %s, %s, %d, \n", __FILE__, __FUNCTION__, __LINE__); \ printf(__VA_ARGS__); #endif #ifndef T_W #define T_W(...) \ printf("Warning: %s, %s, %d, \n", __FILE__, __FUNCTION__, __LINE__); \ printf(__VA_ARGS__); #endif #ifndef T_N #define T_N(...) \ printf("Notify: %s, %s, %d, \n", __FILE__, __FUNCTION__, __LINE__); \ printf(__VA_ARGS__); #endif #else #define T_E(...) #define T_W(...) #define T_N(...) #endif extern mss_mac_instance_t *g_my_mac; #if MSS_MAC_USE_PHY_VSC8575 /* ================================================================= * * Trace * ================================================================= */ vtss_trace_conf_t vtss_appl_trace_conf = { .level = {VTSS_TRACE_LEVEL_ERROR, VTSS_TRACE_LEVEL_ERROR} }; static void printf_trace_head(const vtss_trace_layer_t layer, const vtss_trace_group_t group, const vtss_trace_level_t level, const char *file, const int line, const char *function, const char *lcont) { time_t t; int h, m, s; (void)group; (void)file; (void)line; t = 0; /* time(NULL); */ h = (int)(t / 3600 % 24); m = (int)(t / 60 % 60); s = (int)(t % 60); printf("%u:%02u:%02u %s/%s %s%s", h, m, s, layer == VTSS_TRACE_LAYER_COUNT ? "APPL": layer == VTSS_TRACE_LAYER_AIL ? "AIL" : "CIL", level == VTSS_TRACE_LEVEL_ERROR ? "Error" : level == VTSS_TRACE_LEVEL_INFO ? "Info " : level == VTSS_TRACE_LEVEL_DEBUG ? "Debug" : level == VTSS_TRACE_LEVEL_NOISE ? "Noise" : "?????", function, lcont); } /* Trace callout function */ void vtss_callout_trace_printf(const vtss_trace_layer_t layer, const vtss_trace_group_t group, const vtss_trace_level_t level, const char *file, const int line, const char *function, const char *format, ...) { va_list va; printf_trace_head(layer, group, level, file, line, function, ": "); va_start(va, format); vprintf(format, va); va_end(va); printf("\n"); } /* Trace hex-dump callout function */ void vtss_callout_trace_hex_dump(const vtss_trace_layer_t layer, const vtss_trace_group_t group, const vtss_trace_level_t level, const char *file, const int line, const char *function, const unsigned char *byte_p, const int byte_cnt) { int i; printf_trace_head(layer, group, level, file, line, function, "\n"); for (i= 0; i < byte_cnt; i += 16) { int j = 0; printf("%04x:", i); while (j+i < byte_cnt && j < 16) { printf(" %02x", byte_p[i+j]); j++; } putchar('\n'); } } vtss_rc miim_read(const vtss_inst_t inst, const vtss_port_no_t phy_port, const u8 phy_reg, u16 *const value); vtss_rc miim_write(const vtss_inst_t inst, const vtss_port_no_t phy_port, const u8 phy_reg, const u16 value); int32_t viper_fmc_board_init(vtss_init_conf_t *target); /* Function for initializing the hardware board. */ int32_t viper_fmc_board_init(vtss_init_conf_t *target) { #ifdef _ZL303XX_FMC_BOARD /* 0x30200000U is the base address of the CoreSPI in the fabric */ SPI_init(&g_vsc_spi, 0x30200000U , 32); /* Now is probably a good time to take care of this... */ /* * Note: for the FMC board, the APB clock frequency is 83MHz and the maximum * allowed clock frequency for the 1588 SPI interface is 25MHz. We can only choose * even clock divisors and a divisor of 4 used in the design gives us a 20.75MHz SPI clock. */ SPI_configure_master_mode(&g_vsc_spi); /* Motorola Mode 0, 8 bits selected in design */ SPI_set_slave_select(&g_vsc_spi, SPI_SLAVE_0); target->spi_read_write = spi_read_write; /* Set pointer to SPI interface r/w function for this board */ #endif target->miim_read = miim_read; /* Set pointer to the MIIM read function for this board. */ target->miim_write = miim_write; /* Set pointer to the MIIM write function for this board. */ return 0; } void vtss_callout_lock(const vtss_api_lock_t *const lock) { (void)lock; } void vtss_callout_unlock(const vtss_api_lock_t *const lock) { (void)lock; } /** * brief SPI read/write function * * param inst [IN] Vitesse API instance. * param port_no [IN] Port number. * param bitsize [IN] Size (in bytes) of bitstream following this parameter. * param data [IN|OUT] Pointer to the data to be written to SPI Slave, if doing write operation. * Pointer to the data read from SPI Slave, if doing read operation. * * return Return code. **/ /* G5 SOC Emulation platform has no SPI interface at the moment... */ #ifdef _ZL303XX_FMC_BOARD vtss_rc spi_read_write(const vtss_inst_t inst, const vtss_port_no_t port_no, const u8 bitsize, u8 *const bitstream); vtss_rc spi_read_write(const vtss_inst_t inst, const vtss_port_no_t port_no, const u8 bitsize, u8 *const bitstream) { (void)inst; (void)port_no; /* * The VTSS API transfers 32 bit values using this function. * * We use the bitsize parameter to determine read vs write as * it will be 7 for writes and 10 for reads. * * The first 3 bytes are the R/W status and the register address * information. * * When writing, the next 4 values are the frame to write, * When reading, the next 3 values are padding and the last 4 * bytes are the read data. */ if(7 == bitsize) /* Write operation */ { SPI_transfer_block_vsc(&g_vsc_spi, bitstream, bitsize, 0, 0); } else { SPI_transfer_block_vsc(&g_vsc_spi, bitstream, 6, &bitstream[6], 4); } return VTSS_RC_OK; } #endif /* _ZL303XX_FMC_BOARD */ /* ================================================================= * * Misc. functions * ================================================================= */ #if 0 /* PMCS: Remove for now */ /* Function defining the port interface. */ static vtss_port_interface_t port_interface(vtss_port_no_t port_no) { return VTSS_PORT_INTERFACE_SGMII; } /* Function defining the port interface. */ static void viper_phy_pre_reset(void) { vtss_rc rc; rc = vtss_phy_pre_reset (NULL, 0); return; } /* Function defining the port interface. */ static vtss_rc viper_phy_post_reset(void) { return (vtss_phy_post_reset (NULL, 0)); } #endif /* * Each board can have it own way of communicating with the chip. The miim read and write function are called by the API * when the API needs to do register access. * * Miim read access specific for this board. * In : port_no - The port to access. * addr - The address to access * * In/Out: value - Pointer to the value to be returned */ vtss_rc miim_read(const vtss_inst_t inst, const vtss_port_no_t phy_port, const u8 phy_reg, u16 *const value) { #ifdef __DEBUG_SOCKET__ const uint16_t port_no = (uint16_t) phy_port; uint8_t addr = (uint8_t)phy_reg & 0xff; #endif (void)inst; if((void *)0 != g_my_mac) { *value = MSS_MAC_read_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */ } T_N("miim read port_no = %d, addr = %d, value = 0x%X", port_no, addr, *value); return VTSS_RC_OK; } #if defined(VSC8575_DEBUG_MDIO) /* Store all in 32 bit values so mem dump can view them neatly on 16 byte boundaries... */ typedef struct mii_debug_data { #if defined(USING_FREERTOS) TickType_t time; #else uint64_t time; #endif /* vtss_port_no_t */ uint32_t page; /* u8 */ uint32_t reg; /*u16 */ uint32_t data; } mii_debug_data_t; mii_debug_data_t mii_data[1000]; uint32_t mii_data_index = 0; uint32_t mii_page; #endif /* * Miim write access specific for this board. * In : port_no - The port to access. * addr - The address to access * value - The value to written */ vtss_rc miim_write(const vtss_inst_t inst, const vtss_port_no_t phy_port, const u8 phy_reg, const u16 value) { #ifdef __DEBUG_SOCKET__ const uint16_t port_no = (uint16_t) phy_port; uint8_t addr = phy_reg & 0xff; #endif (void)inst; #if defined(VSC8575_DEBUG_MDIO) if(0x1f == phy_reg) { mii_page = value; } else { #if defined(USING_FREERTOS) mii_data[mii_data_index].time = xTaskGetTickCount(); #else mii_data[mii_data_index].time = g_tick_counter; #endif mii_data[mii_data_index].page = mii_page; mii_data[mii_data_index].reg = phy_reg; mii_data[mii_data_index].data = value; mii_data_index++; if(1000 == mii_data_index) { mii_data_index = 0; } } #endif T_N("miim_writes port_no = %d, addr = %d, value = 0x%X", port_no, addr ,value); if((void *)0 != g_my_mac) { MSS_MAC_write_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg, value); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */ } return VTSS_RC_OK; } #endif /* MSS_MAC_USE_PHY_VSC8575 */ #if MSS_MAC_USE_PHY_VSC8575_LITE int32_t miim_read(const uint32_t phy_port, const uint16_t phy_reg, uint16_t *const value); int32_t miim_write(const uint32_t phy_port, const uint16_t phy_reg, const uint16_t value); int32_t usleep(uint32_t usecs); int32_t viper_fmc_board_init(struct phy_control_t *cntrl); /*============================================================================== * emulate the Unix usleep function using the taskdelay functionality of * FreeRTOS. It is not very close as our example system currently uses a 1mS * tick but all the instances of usleep() being called in the VTSS API Lite are * for 1000uS so it should do... */ int32_t usleep(uint32_t usecs) { #if defined(USING_FREERTOS) uint32_t ustick = portTICK_PERIOD_MS * 1000U; /* calculate microseconds per tick */ /* convert uS to ticks, rounding up to the nearest tick */ usecs = (usecs + (ustick - 1)) / ustick; vTaskDelay(usecs); #else /* Assumes 1mS tick... */ volatile uint64_t timeout = g_tick_counter + (((uint64_t)usecs + 999ULL) / 1000ULL); volatile uint64_t index = 0U; while(g_tick_counter <= timeout) { index++; /* Stop debugger from locking up... */ } #endif return(0); } /* * Each board can have it own way of communicating with the chip. The miim read and write function are called by the API * when the API needs to do register access. * * Miim read access specific for this board. * In : port_no - The port to access. * addr - The address to access * * In/Out: value - Pointer to the value to be returned */ int32_t miim_read( const uint32_t phy_port, const uint16_t phy_reg, uint16_t *const value) { #ifdef __DEBUG_SOCKET__ const uint16_t port_no = (uint16_t) phy_port; uint8_t addr = (uint8_t)phy_reg & 0xff; #endif if((void *)0 != g_my_mac) { *value = MSS_MAC_read_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */ } T_N("miim read port_no = %d, addr = %d, value = 0x%X", port_no, addr, *value); return 0; } /* * Miim write access specific for this board. * In : port_no - The port to access. * addr - The address to access * value - The value to written * * Store all in 32 bit values so mem dump can view them neatly on 16 byte boundaries... */ #if defined(VSC8575_DEBUG_MDIO) typedef struct mii_debug_data { TickType_t time; /* vtss_port_no_t */ uint32_t page; /* u8 */ uint32_t reg; /*u16 */ uint32_t data; } mii_debug_data_t; mii_debug_data_t mii_data[1000]; uint32_t mii_data_index = 0; uint32_t mii_page = 0; #endif int32_t miim_write( const uint32_t phy_port, const uint16_t phy_reg, const uint16_t value) { #ifdef __DEBUG_SOCKET__ const uint16_t port_no = (uint16_t) phy_port; uint8_t addr = phy_reg & 0xff; #endif #if defined(VSC8575_DEBUG_MDIO) if(0 == phy_port) { if(0x1f == phy_reg) { mii_page = value; } else { mii_data[mii_data_index].time = xTaskGetTickCount(); mii_data[mii_data_index].page = mii_page; mii_data[mii_data_index].reg = phy_reg; mii_data[mii_data_index].data = value; mii_data_index++; if(1000 == mii_data_index) { mii_data_index = 0; } } } #endif T_N("miim_writes port_no = %d, addr = %d, value = 0x%X", port_no, addr ,value); if((void *)0 != g_my_mac) { MSS_MAC_write_phy_reg(g_my_mac, (uint8_t)(phy_port + g_my_mac->phy_addr), (uint8_t)phy_reg, value); /* TBD: PMCS Warning only works for single MAC/VSC8575 combination */ } return 0; } /* Function for initializing the hardware board. */ int32_t viper_fmc_board_init(struct phy_control_t *cntrl) { cntrl->phy_reg_read = miim_read; /* Set pointer to the MIIM read function for this board. */ cntrl->phy_reg_write = miim_write; /* Set pointer to the MIIM write function for this board. */ return 0; } #endif /* MSS_MAC_USE_PHY_VSC8575_LITE */ mss_gpio/000077500000000000000000000000001432224323300350735ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_gpio.c000066400000000000000000000324441432224323300370660ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_gpio/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC microprocessor subsystem GPIO bare metal driver implementation. * * This driver is based on SmartFusion2 MSS GPIO driver v2.1.102 * */ #include "mss_hal.h" #include "mss_gpio.h" #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** * Defines. */ #define GPIO_INT_ENABLE_MASK ((uint32_t)0x00000008u) #define OUTPUT_BUFFER_ENABLE_MASK ((uint32_t)0x00000004u) /*These constants define the number of GPIO bits available on each GPIO * hardware block*/ #define NB_OF_GPIO_GPIO0 ((uint32_t)14u) #define NB_OF_GPIO_GPIO1 ((uint32_t)24u) #define NB_OF_GPIO_GPIO2 ((uint32_t)32u) /*This constant indicates the total number of GPIO interrupt inputs at the PLIC * (includes the direct and non-direct GPIO interrupts)*/ #define NB_OF_GPIO_INTR ((uint32_t)41) /*-------------------------------------------------------------------------*//** * Lookup table of GPIO interrupt number indexed on GPIO ID. * The GPIO interrupts are multiplexed. Total GPIO interrupts are 41. * 41 = (14 from GPIO0 + 24 from GPIO1 + 3 non direct interrupts) * GPIO2 interrupts are not available by default. Setting the corresponding bit * in GPIO_INTERRUPT_FAB_CR(31:0) will enable GPIO2(31:0) corresponding * interrupt on PLIC. * * PLIC GPIO_INTERRUPT_FAB_CR 0 1 0 GPIO0 bit 0 GPIO2 bit 0 1 GPIO0 bit 1 GPIO2 bit 1 . . 12 GPIO0 bit 12 GPIO2 bit 12 13 GPIO0 bit 13 GPIO2 bit 13 14 GPIO1 bit 0 GPIO2 bit 14 15 GPIO1 bit 1 GPIO2 bit 15 . . . 30 GPIO1 bit 16 GPIO2 bit 30 31 GPIO1 bit 17 GPIO2 bit 31 32 GPIO1 bit 18 33 GPIO1 bit 19 34 GPIO1 bit 20 35 GPIO1 bit 21 36 GPIO1 bit 22 37 GPIO1 bit 23 38 Or of all GPIO0 interrupts who do not have a direct connection enabled 39 Or of all GPIO1 interrupts who do not have a direct connection enabled 40 Or of all GPIO2 interrupts who do not have a direct connection enabled * */ static const PLIC_IRQn_Type g_gpio_irqn_lut[NB_OF_GPIO_INTR] = { GPIO0_BIT0_or_GPIO2_BIT0_PLIC_0, GPIO0_BIT1_or_GPIO2_BIT1_PLIC_1, GPIO0_BIT2_or_GPIO2_BIT2_PLIC_2, GPIO0_BIT3_or_GPIO2_BIT3_PLIC_3, GPIO0_BIT4_or_GPIO2_BIT4_PLIC_4, GPIO0_BIT5_or_GPIO2_BIT5_PLIC_5, GPIO0_BIT6_or_GPIO2_BIT6_PLIC_6, GPIO0_BIT7_or_GPIO2_BIT7_PLIC_7, GPIO0_BIT8_or_GPIO2_BIT8_PLIC_8, GPIO0_BIT9_or_GPIO2_BIT9_PLIC_9, GPIO0_BIT10_or_GPIO2_BIT10_PLIC_10, GPIO0_BIT11_or_GPIO2_BIT11_PLIC_11, GPIO0_BIT12_or_GPIO2_BIT12_PLIC_12, GPIO0_BIT13_or_GPIO2_BIT13_PLIC_13, GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14, GPIO1_BIT1_or_GPIO2_BIT15_PLIC_15, GPIO1_BIT2_or_GPIO2_BIT16_PLIC_16, GPIO1_BIT3_or_GPIO2_BIT17_PLIC_17, GPIO1_BIT4_or_GPIO2_BIT18_PLIC_18, GPIO1_BIT5_or_GPIO2_BIT19_PLIC_19, GPIO1_BIT6_or_GPIO2_BIT20_PLIC_20, GPIO1_BIT7_or_GPIO2_BIT21_PLIC_21, GPIO1_BIT8_or_GPIO2_BIT22_PLIC_22, GPIO1_BIT9_or_GPIO2_BIT23_PLIC_23, GPIO1_BIT10_or_GPIO2_BIT24_PLIC_24, GPIO1_BIT11_or_GPIO2_BIT25_PLIC_25, GPIO1_BIT12_or_GPIO2_BIT26_PLIC_26, GPIO1_BIT13_or_GPIO2_BIT27_PLIC_27, GPIO1_BIT14_or_GPIO2_BIT28_PLIC_28, GPIO1_BIT15_or_GPIO2_BIT29_PLIC_29, GPIO1_BIT16_or_GPIO2_BIT30_PLIC_30, GPIO1_BIT17_or_GPIO2_BIT31_PLIC_31, GPIO1_BIT18_PLIC_32, GPIO1_BIT19_PLIC_33, GPIO1_BIT20_PLIC_34, GPIO1_BIT21_PLIC_35, GPIO1_BIT22_PLIC_36, GPIO1_BIT23_PLIC_37, GPIO0_NON_DIRECT_PLIC, GPIO1_NON_DIRECT_PLIC, GPIO2_NON_DIRECT_PLIC }; /*-------------------------------------------------------------------------*//** * Local functions */ static uint8_t gpio_number_validate(GPIO_TypeDef const * gpio, mss_gpio_id_t gpio_idx); /*-------------------------------------------------------------------------*//** * MSS_GPIO_init * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_init(GPIO_TypeDef * gpio) { #ifdef CONFIG_MODULE_M100PFS uint32_t clock_mask; uint32_t reset_mask; if (GPIO0_LO == gpio || GPIO0_HI == gpio) { clock_mask = (uint32_t)SUBBLK_CLOCK_CR_GPIO0_MASK; reset_mask = (uint32_t)SOFT_RESET_CR_GPIO0_MASK; } else if (GPIO1_LO == gpio || GPIO1_HI == gpio) { clock_mask = (uint32_t)SUBBLK_CLOCK_CR_GPIO1_MASK; reset_mask = (uint32_t)SOFT_RESET_CR_GPIO1_MASK; } else { clock_mask = (uint32_t)SUBBLK_CLOCK_CR_GPIO2_MASK; reset_mask = (uint32_t)SOFT_RESET_CR_GPIO2_MASK; } /* Enable clock to GPIO block and toggle reset signal */ SYSREG->SUBBLK_CLOCK_CR |= clock_mask; SYSREG->SOFT_RESET_CR |= reset_mask; SYSREG->SOFT_RESET_CR &= ~reset_mask; #endif /* CONFIG_MODULE_M100PFS */ /* clear all pending interrupts*/ gpio->GPIO_IRQ = 0xFFFFFFFFU; } /*-------------------------------------------------------------------------*//** * MSS_GPIO_config * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_config(GPIO_TypeDef * gpio, mss_gpio_id_t port_id, uint32_t config) { if (0U == gpio_number_validate(gpio, port_id)) { gpio->GPIO_CFG[port_id] = config; } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_config_byte * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_config_byte(GPIO_TypeDef * gpio, mss_gpio_byte_num_t byte_num, uint32_t config) { if (((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) && (byte_num >= MSS_GPIO_BYTE_1)) { ASSERT(0); } else if (((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) && (byte_num > MSS_GPIO_BYTE_2)) { ASSERT(0); } else if (((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) && (byte_num > MSS_GPIO_BYTE_3)) { ASSERT(0); } else { gpio->GPIO_CFG_BYTE[byte_num] = config; } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_config_all * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_config_all(GPIO_TypeDef * gpio, uint32_t config) { gpio->GPIO_CFG_ALL = config; } /*-------------------------------------------------------------------------*//** * MSS_GPIO_set_output * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_set_output( GPIO_TypeDef * gpio, mss_gpio_id_t port_id, uint8_t value) { if (0U == gpio_number_validate(gpio, port_id)) { /* Setting the bit in GPIO_SET_BITS (offset 0xA4) sets the corresponding * output port. * Setting the bit in GPIO_CLR_BITS (offset 0xA0) clears the * corresponding output port.*/ if (value > 0u) { gpio->GPIO_SET_BITS = ((uint32_t)0x01 << port_id); } else { gpio->GPIO_CLR_BITS = ((uint32_t)0x01 << port_id); } } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_drive_inout * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_drive_inout(GPIO_TypeDef * gpio, mss_gpio_id_t port_id, mss_gpio_inout_state_t inout_state) { uint32_t config; if (0U == gpio_number_validate(gpio, port_id)) { switch (inout_state) { case MSS_GPIO_DRIVE_HIGH: /* Set output high */ gpio->GPIO_SET_BITS = ((uint32_t)1 << port_id); /* Enable output buffer */ config = gpio->GPIO_CFG[port_id]; config |= OUTPUT_BUFFER_ENABLE_MASK; gpio->GPIO_CFG[port_id] = config; break; case MSS_GPIO_DRIVE_LOW: /* Set output low */ gpio->GPIO_CLR_BITS = (uint32_t)1 << port_id; /* Enable output buffer */ config = gpio->GPIO_CFG[port_id]; config |= OUTPUT_BUFFER_ENABLE_MASK; gpio->GPIO_CFG[port_id] = config; break; case MSS_GPIO_HIGH_Z: /* Disable output buffer */ config = gpio->GPIO_CFG[port_id]; config &= ~OUTPUT_BUFFER_ENABLE_MASK; gpio->GPIO_CFG[port_id] = config; break; default: ASSERT(0); break; } } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_enable_irq * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_enable_irq(GPIO_TypeDef * gpio, mss_gpio_id_t port_id) { uint32_t cfg_value; if (0U == gpio_number_validate(gpio, port_id)) { cfg_value = gpio->GPIO_CFG[(uint8_t)port_id]; gpio->GPIO_CFG[(uint8_t)port_id] = (cfg_value | GPIO_INT_ENABLE_MASK); if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) { PLIC_EnableIRQ(g_gpio_irqn_lut[port_id]); } else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) { PLIC_EnableIRQ(g_gpio_irqn_lut[port_id + GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14]); } else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) { PLIC_EnableIRQ(g_gpio_irqn_lut[port_id]); } else { ASSERT(0); /*LDRA warning*/ } } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_disable_irq * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_disable_irq(GPIO_TypeDef * gpio, mss_gpio_id_t port_id) { uint32_t cfg_value; if (0U == gpio_number_validate(gpio, port_id)) { cfg_value = gpio->GPIO_CFG[(uint8_t)port_id]; gpio->GPIO_CFG[(uint8_t)port_id] = (cfg_value & (~GPIO_INT_ENABLE_MASK)); if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) { PLIC_DisableIRQ(g_gpio_irqn_lut[port_id]); } else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) { PLIC_DisableIRQ(g_gpio_irqn_lut[port_id + GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14]); } else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) { PLIC_DisableIRQ(GPIO2_NON_DIRECT_PLIC); } else { ASSERT(0); /*LDRA warning*/ } } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_enable_nondirect_irq * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_enable_nondirect_irq(GPIO_TypeDef const * gpio) { if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) { PLIC_EnableIRQ(GPIO0_NON_DIRECT_PLIC); } else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) { PLIC_EnableIRQ(GPIO1_NON_DIRECT_PLIC); } else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) { PLIC_EnableIRQ(GPIO2_NON_DIRECT_PLIC); } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_disable_nondirect_irq * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_disable_nondirect_irq(GPIO_TypeDef const * gpio) { if ((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) { PLIC_DisableIRQ(GPIO0_NON_DIRECT_PLIC); } else if ((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) { PLIC_DisableIRQ(GPIO1_NON_DIRECT_PLIC); } else if ((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) { PLIC_DisableIRQ(GPIO2_NON_DIRECT_PLIC); } else { ASSERT(0); /*LDRA warning*/ } } /*-------------------------------------------------------------------------*//** * MSS_GPIO_clear_irq * See "mss_gpio.h" for details of how to use this function. */ void MSS_GPIO_clear_irq(GPIO_TypeDef * gpio, mss_gpio_id_t port_id) { if (0U == gpio_number_validate(gpio, port_id)) { gpio->GPIO_IRQ = ((uint32_t)1) << port_id; __asm("fence"); } else { ASSERT(0); /*LDRA warning*/ } } static uint8_t gpio_number_validate(GPIO_TypeDef const * gpio, mss_gpio_id_t gpio_idx) { uint8_t ret; if (((GPIO0_LO == gpio) || (GPIO0_HI == gpio)) && (gpio_idx >= NB_OF_GPIO_GPIO0)) { ret = 1u; } else if (((GPIO1_LO == gpio) || (GPIO1_HI == gpio)) && (gpio_idx >= NB_OF_GPIO_GPIO1)) { ret = 1u; } else if (((GPIO2_LO == gpio) || (GPIO2_HI == gpio)) && (gpio_idx >= NB_OF_GPIO_GPIO2)) { ret = 1u; } else { ret = 0u; } return ret; } #ifdef __cplusplus } #endif mss_gpio.h000066400000000000000000001160421432224323300370700ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_gpio/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * PolarFire SoC Microprocessor Subsystem GPIO bare metal software driver * public API. * * This driver is based on SmartFusion2 MSS GPIO driver v2.1.102 * */ /*=========================================================================*//** @mainpage PolarFire SoC MSS GPIO Bare Metal Driver ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor Subsystem (MSS) includes three blocks of general purpose input/outputs (GPIO). The GPIO0, GPIO1 and GPIO2 blocks have 14, 24 and 32 GPIO ports respectively. This software driver provides a set of functions for controlling the MSS GPIO blocks as part of a bare metal system where no operating system is available. This driver can be adapted for use as part of an operating system but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all features of the MSS GPIO peripherals is covered by this driver with the exception of the PolarFire SoC IOMUX configuration. PolarFire SoC allows multiple non-concurrent uses of some external pins through IOMUX configuration. This feature allows optimization of external pin usage by assigning external pins for use by either the microprocessor subsystem or the FPGA fabric. The MSS GPIO signals are routed through IOMUXs to the PolarFire SoC device external pins. The MSS GPIO serial signals may also be routed through IOMUXs to the PolarFire SoC FPGA fabric. For more information on IOMUX, refer to the IOMUX section of the PolarFire SoC Microprocessor Subsystem (MSS) User's Guide. The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You must ensure that the MSS GPIO peripherals are enabled and configured in the PolarFire SoC MSS configurator if you wish to use them. For more information on IOMUXs, refer to the IOMUX section of the PolarFire SoC microprocessor Subsystem (MSS) User's Guide. On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple masters and multiple slaves. Five RISC-V CPUs connect to the Master ports M10 to M14 of the AXI switch. By default, all the APB peripherals are accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB bridges (referred as main APB bus). However, to support logical separation in the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to APB bridges (referred as the AMP APB bus). Application must make sure that the desired GPIO instance is appropriately configured on one of the APB bus described above by configuring the PolarFire SoC system registers (SYSREG) as per the application need and that the appropriate data structures are provided to this driver as parameter to the functions provided by this driver. The base address and register addresses are defined in this driver as constants. The interrupt number assignment for the MSS GPIO peripherals are defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole tool chain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS GPIO driver functions are grouped into the following categories: - Initialization - Configuration - Reading and setting GPIO state - Interrupt control -------------------------------- Initialization -------------------------------- The MSS GPIO driver is initialized through a call to the MSS_GPIO_init() function. The MSS_GPIO_init() function must be called before any other MSS GPIO driver functions can be called. -------------------------------- Configuration -------------------------------- Each GPIO port is individually configured through a call to the MSS_GPIO_config() function. Configuration includes deciding if a GPIO port will be used as an input, an output or both. GPIO ports configured as inputs can be further configured to generate interrupts based on the input's state. Interrupts can be level or edge sensitive. The MSS_GPIO_config_byte() function can be used to configure eight consecutive GPIO ports identically. The MSS_GPIO_config_byte() function can be used to configure all available GPIO ports identically. -------------------------------- Reading and Setting GPIO State -------------------------------- The state of the GPIO ports can be read and set using the following functions: - MSS_GPIO_get_inputs() - MSS_GPIO_get_outputs() - MSS_GPIO_set_outputs() - MSS_GPIO_set_output() - MSS_GPIO_drive_inout() -------------------------------- Interrupt Control -------------------------------- Interrupts generated by GPIO ports configured as inputs are controlled using the following functions: - MSS_GPIO_enable_irq() - MSS_GPIO_disable_irq() - MSS_GPIO_clear_irq() - MSS_GPIO_get_irq() - MSS_GPIO_enable_nondirect_irq() - MSS_GPIO_disable_nondirect_irq() The GPIO interrupts are multiplexed. Total GPIO interrupt inputs on PLIC are 41. 41 = (14 from GPIO0 + 24 from GPIO1 + 3 non direct interrupts) GPIO2 interrupts are not available by default. Setting the corresponding bit in GPIO_INTERRUPT_FAB_CR(31:0) system register will enable GPIO2(31:0) corresponding interrupt on PLIC. e.g. If GPIO_INTERRUPT_FAB_CR bit0 is set then GPIO2 bit0 interrupt is available on the direct input pin on the PLIC. In this case GPIO0 bit 0 interrupt will not be available on the direct input pin on the PLIC however, the GPIO0 non-direct input will be asserted as OR of all the GPIO0 interrupts which don't have a direct interrupt input on PLIC are connected to corresponding non-direct input pin. The table below explains all the GPIO direct and non-direct interrupt connectivity options. | PLIC | GPIO_INTERRUPT_FAB_CR = 0 | GPIO_INTERRUPT_FAB_CR = 1 | |------|---------------------------|---------------------------| | 0 | GPIO0 bit 0 | GPIO2 bit 0 | | 1 | GPIO0 bit 1 | GPIO2 bit 1 | | ... | ... | ... | | 12 | GPIO0 bit 12 | GPIO2 bit 12 | | 13 | GPIO0 bit 13 | GPIO2 bit 13 | | 14 | GPIO1 bit 0 | GPIO2 bit 14 | | 15 | GPIO1 bit 1 | GPIO2 bit 15 | | ... | ... | ... | | 30 | GPIO1 bit 16 | GPIO2 bit 30 | | 31 | GPIO1 bit 17 | GPIO2 bit 31 | | PLIC | Interrupt source | |------|----------------------------------------------------------------------| | 32 | GPIO1 bit 18 | | 33 | GPIO1 bit 19 | | 34 | GPIO1 bit 20 | | 35 | GPIO1 bit 21 | | 36 | GPIO1 bit 22 | | 37 | GPIO1 bit 23 | | 38 | OR of all GPIO0 interrupts who don't have a direct connection enabled| | 39 | OR of all GPIO1 interrupts who don't have a direct connection enabled| | 40 | OR of all GPIO2 interrupts who don't have a direct connection enabled| NOTE: GPIO_INTERRUPT_FAB_CR controls the multiplexing in above table. It is your responsibility to set up the GPIO_INTERRUPT_FAB_CR bits in application code. you must make sure that you are using the valid combination of GPIO0/1/2 interrupt per above table. *//*=========================================================================*/ #ifndef MSS_GPIO_H_ #define MSS_GPIO_H_ #ifdef __cplusplus extern "C" { #endif #include /*-------------------------------------------------------------------------*//** The mss_gpio_id_t enumeration is used to identify individual GPIO ports as an argument to functions: - MSS_GPIO_config() - MSS_GPIO_set_output() and MSS_GPIO_drive_inout() - MSS_GPIO_enable_irq(), MSS_GPIO_disable_irq() and MSS_GPIO_clear_irq() Note that the GPIO0, GPIO1 and GPIO2 blocks have 14, 24 and 32 GPIO ports respectively. */ typedef enum mss_gpio_id { MSS_GPIO_0 = 0, MSS_GPIO_1 = 1, MSS_GPIO_2 = 2, MSS_GPIO_3 = 3, MSS_GPIO_4 = 4, MSS_GPIO_5 = 5, MSS_GPIO_6 = 6, MSS_GPIO_7 = 7, MSS_GPIO_8 = 8, MSS_GPIO_9 = 9, MSS_GPIO_10 = 10, MSS_GPIO_11 = 11, MSS_GPIO_12 = 12, MSS_GPIO_13 = 13, MSS_GPIO_14 = 14, MSS_GPIO_15 = 15, MSS_GPIO_16 = 16, MSS_GPIO_17 = 17, MSS_GPIO_18 = 18, MSS_GPIO_19 = 19, MSS_GPIO_20 = 20, MSS_GPIO_21 = 21, MSS_GPIO_22 = 22, MSS_GPIO_23 = 23, MSS_GPIO_24 = 24, MSS_GPIO_25 = 25, MSS_GPIO_26 = 26, MSS_GPIO_27 = 27, MSS_GPIO_28 = 28, MSS_GPIO_29 = 29, MSS_GPIO_30 = 30, MSS_GPIO_31 = 31 } mss_gpio_id_t; /*-------------------------------------------------------------------------*//** The mss_gpio_inout_state_t enumeration is used to specify the output state of an INOUT GPIO port as an argument to the MSS_GPIO_drive_inout() function. */ typedef enum mss_gpio_inout_state { MSS_GPIO_DRIVE_LOW = 0, MSS_GPIO_DRIVE_HIGH, MSS_GPIO_HIGH_Z } mss_gpio_inout_state_t; /*-------------------------------------------------------------------------*//** The mss_gpio_byte_num_t enumeration is used to specify the set of the 8 consecutive GPIO ports that are to be configured as an argument to the MSS_GPIO_config_byte() function. */ typedef enum mss_gpio_byte_num { MSS_GPIO_BYTE_0 = 0, MSS_GPIO_BYTE_1, MSS_GPIO_BYTE_2, MSS_GPIO_BYTE_3, MSS_GPIO_BYTE_INVALID, } mss_gpio_byte_num_t; /*-------------------------------------------------------------------------*//** GPIO Instance Identification ============================ These constants are provided for the application use. These constants must be passed as a first parameter of all the APIs provided by this driver. The GPIO0_LO, GPIO1_LO, GPIO2_LO represent the GPIO0, GPIO1 and GPIO2 hardware blocks when they are connected on the main APB bus. The GPIO0_HI, GPIO1_HI, GPIO2_HI represent the GPIO0, GPIO1 and GPIO2 hardware blocks when they are connected on the AMP APB bus. | Constant | Description | |----------|---------------------------------------| | GPIO0_LO | GPIO0 block connected on main APB bus | | GPIO1_LO | GPIO1 block connected on main APB bus | | GPIO2_LO | GPIO2 block connected on main APB bus | | GPIO0_HI | GPIO0 block connected on AMP APB bus | | GPIO1_HI | GPIO1 block connected on AMP APB bus | | GPIO2_HI | GPIO2 block connected on AMP APB bus | */ #define GPIO0_LO ((GPIO_TypeDef*)0x20120000UL) #define GPIO1_LO ((GPIO_TypeDef*)0x20121000UL) #define GPIO2_LO ((GPIO_TypeDef*)0x20122000UL) #define GPIO0_HI ((GPIO_TypeDef*)0x28120000UL) #define GPIO1_HI ((GPIO_TypeDef*)0x28121000UL) #define GPIO2_HI ((GPIO_TypeDef*)0x28122000UL) /*-------------------------------------------------------------------------*//** GPIO Port Masks =============== These constant definitions are used as an argument to the MSS_GPIO_set_outputs() function to identify GPIO ports. A logical OR of these constants can be used to specify multiple GPIO ports. These definitions can also be used to identify GPIO ports through logical operations on the return value of the MSS_GPIO_get_inputs() function. | Constant | Description | |------------------|-----------------------| | MSS_GPIO_0_MASK | GPIO port 0-bit mask | | MSS_GPIO_1_MASK | GPIO port 1-bit mask | | MSS_GPIO_2_MASK | GPIO port 2-bit mask | | MSS_GPIO_3_MASK | GPIO port 3-bit mask | | MSS_GPIO_4_MASK | GPIO port 4-bit mask | | MSS_GPIO_5_MASK | GPIO port 5-bit mask | | MSS_GPIO_6_MASK | GPIO port 6-bit mask | | MSS_GPIO_7_MASK | GPIO port 7-bit mask | | MSS_GPIO_8_MASK | GPIO port 8-bit mask | | MSS_GPIO_9_MASK | GPIO port 9-bit mask | | MSS_GPIO_10_MASK | GPIO port 10-bit mask | | MSS_GPIO_11_MASK | GPIO port 11-bit mask | | MSS_GPIO_12_MASK | GPIO port 12-bit mask | | MSS_GPIO_13_MASK | GPIO port 13-bit mask | | MSS_GPIO_14_MASK | GPIO port 14-bit mask | | MSS_GPIO_15_MASK | GPIO port 15-bit mask | | MSS_GPIO_16_MASK | GPIO port 16-bit mask | | MSS_GPIO_17_MASK | GPIO port 17-bit mask | | MSS_GPIO_18_MASK | GPIO port 18-bit mask | | MSS_GPIO_19_MASK | GPIO port 19-bit mask | | MSS_GPIO_20_MASK | GPIO port 20-bit mask | | MSS_GPIO_21_MASK | GPIO port 21-bit mask | | MSS_GPIO_22_MASK | GPIO port 22-bit mask | | MSS_GPIO_23_MASK | GPIO port 23-bit mask | | MSS_GPIO_24_MASK | GPIO port 24-bit mask | | MSS_GPIO_25_MASK | GPIO port 25-bit mask | | MSS_GPIO_26_MASK | GPIO port 26-bit mask | | MSS_GPIO_27_MASK | GPIO port 27-bit mask | | MSS_GPIO_28_MASK | GPIO port 28-bit mask | | MSS_GPIO_29_MASK | GPIO port 29-bit mask | | MSS_GPIO_30_MASK | GPIO port 30-bit mask | | MSS_GPIO_31_MASK | GPIO port 31-bit mask | */ #define MSS_GPIO_0_MASK 0x00000001UL #define MSS_GPIO_1_MASK 0x00000002UL #define MSS_GPIO_2_MASK 0x00000004UL #define MSS_GPIO_3_MASK 0x00000008UL #define MSS_GPIO_4_MASK 0x00000010UL #define MSS_GPIO_5_MASK 0x00000020UL #define MSS_GPIO_6_MASK 0x00000040UL #define MSS_GPIO_7_MASK 0x00000080UL #define MSS_GPIO_8_MASK 0x00000100UL #define MSS_GPIO_9_MASK 0x00000200UL #define MSS_GPIO_10_MASK 0x00000400UL #define MSS_GPIO_11_MASK 0x00000800UL #define MSS_GPIO_12_MASK 0x00001000UL #define MSS_GPIO_13_MASK 0x00002000UL #define MSS_GPIO_14_MASK 0x00004000UL #define MSS_GPIO_15_MASK 0x00008000UL #define MSS_GPIO_16_MASK 0x00010000UL #define MSS_GPIO_17_MASK 0x00020000UL #define MSS_GPIO_18_MASK 0x00040000UL #define MSS_GPIO_19_MASK 0x00080000UL #define MSS_GPIO_20_MASK 0x00100000UL #define MSS_GPIO_21_MASK 0x00200000UL #define MSS_GPIO_22_MASK 0x00400000UL #define MSS_GPIO_23_MASK 0x00800000UL #define MSS_GPIO_24_MASK 0x01000000UL #define MSS_GPIO_25_MASK 0x02000000UL #define MSS_GPIO_26_MASK 0x04000000UL #define MSS_GPIO_27_MASK 0x08000000UL #define MSS_GPIO_28_MASK 0x10000000UL #define MSS_GPIO_29_MASK 0x20000000UL #define MSS_GPIO_30_MASK 0x40000000UL #define MSS_GPIO_31_MASK 0x80000000UL /*-------------------------------------------------------------------------*//** GPIO Port I/O Mode ================== These constant definitions are used as an argument to the MSS_GPIO_config() function to specify the I/O mode of each GPIO port. | Constant | Description | |----------------------|----------------------------| | MSS_GPIO_INPUT_MODE | Input port only | | MSS_GPIO_OUTPUT_MODE | Output port only | | MSS_GPIO_INOUT_MODE | Both input and output port | */ #define MSS_GPIO_INPUT_MODE 0x0000000002UL #define MSS_GPIO_OUTPUT_MODE 0x0000000005UL #define MSS_GPIO_INOUT_MODE 0x0000000003UL /*-------------------------------------------------------------------------*//** GPIO Interrupt Mode =================== These constant definitions are used as an argument to the MSS_GPIO_config() function to specify the interrupt mode of each GPIO port. | Constant | Description | |----------------------------|-----------------------------------------------------| | MSS_GPIO_IRQ_LEVEL_HIGH | Interrupt on GPIO input level High | | MSS_GPIO_IRQ_LEVEL_LOW | Interrupt on GPIO input level Low | | MSS_GPIO_IRQ_EDGE_POSITIVE | Interrupt on GPIO input positive edge | | MSS_GPIO_IRQ_EDGE_NEGATIVE | Interrupt on GPIO input negative edge | | MSS_GPIO_IRQ_EDGE_BOTH | Interrupt on GPIO input positive and negative edges | */ #define MSS_GPIO_IRQ_LEVEL_HIGH 0x0000000000UL #define MSS_GPIO_IRQ_LEVEL_LOW 0x0000000020UL #define MSS_GPIO_IRQ_EDGE_POSITIVE 0x0000000040UL #define MSS_GPIO_IRQ_EDGE_NEGATIVE 0x0000000060UL #define MSS_GPIO_IRQ_EDGE_BOTH 0x0000000080UL /*------------------------Private data structures-----------------------------*/ /*----------------------------------- GPIO -----------------------------------*/ /*----------------------------------------------------------------------------*/ typedef struct { volatile uint32_t GPIO_CFG[32]; volatile uint32_t GPIO_IRQ; volatile const uint32_t GPIO_IN; volatile uint32_t GPIO_OUT; volatile uint32_t GPIO_CFG_ALL; volatile uint32_t GPIO_CFG_BYTE[4]; volatile uint32_t GPIO_CLR_BITS; volatile uint32_t GPIO_SET_BITS; } GPIO_TypeDef; /*--------------------------------Public APIs---------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_GPIO_init() function initializes the PolarFire SoC MSS GPIO block. It resets the MSS GPIO hardware block and it also clears any pending MSS GPIO interrupts in the interrupt controller. When the function exits, it takes the MSS GPIO block out of reset. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @return This function does not return a value. Example: @code #include "mss_gpio.h" int main(void) { MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); return (0u); } @endcode */ void MSS_GPIO_init ( GPIO_TypeDef * gpio ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_config() function is used to configure an individual GPIO port. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param port_id The port_id parameter identifies the GPIO port to be configured. An enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. @param config The config parameter specifies the configuration to be applied to the GPIO port identified by the port_id parameter. It is a logical OR of the required I/O mode and the required interrupt mode. The interrupt mode is not relevant if the GPIO is configured as an output only. These I/O mode constants are allowed: - MSS_GPIO_INPUT_MODE - MSS_GPIO_OUTPUT_MODE - MSS_GPIO_INOUT_MODE These interrupt mode constants are allowed: - MSS_GPIO_IRQ_LEVEL_HIGH - MSS_GPIO_IRQ_LEVEL_LOW - MSS_GPIO_IRQ_EDGE_POSITIVE - MSS_GPIO_IRQ_EDGE_NEGATIVE - MSS_GPIO_IRQ_EDGE_BOTH @return This function does not return any value. Example: The following call will configure GPIO 4 on GPIO0 hardware block on main APB bus as an input generating interrupts on a Low to High transition of the input @code #include "mss_gpio.h" int main(void) { MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); return (0u); } @endcode */ void MSS_GPIO_config ( GPIO_TypeDef * gpio, mss_gpio_id_t port_id, uint32_t config ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_set_outputs() function is used to set the state of all GPIO ports configured as outputs. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param value The value parameter specifies the state of the GPIO ports configured as outputs. It is a bit mask of the form (MSS_GPIO_n_MASK | MSS_GPIO_m_MASK) where n and m are numbers identifying GPIOs. For example, (MSS_GPIO_0_MASK | MSS_GPIO_1_MASK | MSS_GPIO_2_MASK ) specifies that the first, second and third GPIO outputs must be set High and all other GPIO outputs set Low. The driver provides 32 mask constants, MSS_GPIO_0_MASK to MSS_GPIO_31_MASK inclusive, for this purpose. @return This function does not return any value. Example 1: Set GPIOs outputs 0 and 8 high and all other GPIO outputs low. @code #include "mss_gpio.h" int main(void) { MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); MSS_GPIO_set_outputs(GPIO0_LO, MSS_GPIO_0_MASK | MSS_GPIO_8_MASK ); return (0u); } @endcode Example 2: Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs. @code #include "mss_gpio.h" int main(void) { uint32_t gpio_outputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); gpio_outputs = MSS_GPIO_get_outputs(); gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK ); MSS_GPIO_set_outputs(GPIO0_LO, gpio_outputs ); return (0u); } @endcode @see MSS_GPIO_get_outputs() */ static inline void MSS_GPIO_set_outputs ( GPIO_TypeDef * gpio, uint32_t value ) { gpio->GPIO_OUT = value; } /*-------------------------------------------------------------------------*//** The MSS_GPIO_config_all() function is used to configure all the ports of the GPIO block. This function will apply the same configuration values to all the GPIO ports. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param config The config parameter specifies the configuration to be applied to the all the GPIO ports. It is a logical OR of the required I/O mode and the required interrupt mode. The interrupt mode is not relevant if the GPIO is configured as an output only. These I/O mode constants are allowed: - MSS_GPIO_INPUT_MODE - MSS_GPIO_OUTPUT_MODE - MSS_GPIO_INOUT_MODE These interrupt mode constants are allowed: - MSS_GPIO_IRQ_LEVEL_HIGH - MSS_GPIO_IRQ_LEVEL_LOW - MSS_GPIO_IRQ_EDGE_POSITIVE - MSS_GPIO_IRQ_EDGE_NEGATIVE - MSS_GPIO_IRQ_EDGE_BOTH @return This function does not return any value. Example: @code #include "mss_gpio.h" int main(void) { MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); return (0u); } @endcode */ void MSS_GPIO_config_all ( GPIO_TypeDef * gpio, uint32_t config ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_config_byte() function is used to byte wise (consecutive 8 ports) configure the gpio ports. @param gpio The gpio parameter specifies the GPIO block that needs to be configured. @param byte_num The byte_num parameter specifies the byte (consecutive 8 ports) which needs to be configured. The value 0 indicates the bunch from gpio port0 to gpio port7. Value of 3 indicates the bunch from gpio port25 to gpio port31. When you use this function, you must make sure that the gpio ports that you are trying to configure do exist for that GPIO hardware block. GPIO0 has 14 ports.GPIO1 has 24 ports.GPIO3 has 32 ports. @param config The config parameter specifies the configuration to be applied to the GPIO byte identified by the byte_num parameter. It is a logical OR of the required I/O mode and the required interrupt mode. The interrupt mode is not relevant if the GPIO is configured as an output only. These I/O mode constants are allowed: - MSS_GPIO_INPUT_MODE - MSS_GPIO_OUTPUT_MODE - MSS_GPIO_INOUT_MODE These interrupt mode constants are allowed: - MSS_GPIO_IRQ_LEVEL_HIGH - MSS_GPIO_IRQ_LEVEL_LOW - MSS_GPIO_IRQ_EDGE_POSITIVE - MSS_GPIO_IRQ_EDGE_NEGATIVE - MSS_GPIO_IRQ_EDGE_BOTH @return This function does not return any value. Example: @code #include "mss_gpio.h" int main(void) { MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_byte(GPIO0_LO, MSS_GPIO_BYTE_1, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); return (0u); } @endcode */ void MSS_GPIO_config_byte ( GPIO_TypeDef * gpio, mss_gpio_byte_num_t byte_num, uint32_t config ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_set_output() function is used to set the state of a single GPIO port configured as an output. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param port_id The port_id parameter identifies the GPIO port that is to have its output set. An enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. @param value The value parameter specifies the desired state for the GPIO output. A value of 0 will set the output Low and a value of 1 will set the output High. @return This function does not return a value. Example: The following call will set GPIO output 12 High, leaving all other GPIO outputs unaffected: @code #include "mss_gpio.h" int main(void) { MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE); MSS_GPIO_set_output(GPIO0_LO, MSS_GPIO_13, 1); return (0u); } @endcode */ void MSS_GPIO_set_output ( GPIO_TypeDef * gpio, mss_gpio_id_t port_id, uint8_t value ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_get_inputs() function is used to read the current state all GPIO ports configured as inputs. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @return This function returns a 32-bit unsigned integer where each bit represents the state of a GPIO input. The least significant bit represents the state of GPIO input 0 and the most significant bit the state of GPIO input 31. Example: Read and assign the current state of the GPIO outputs to a variable. @code #include "mss_gpio.h" int main(void) { uint32_t gpio_inputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE); gpio_inputs = MSS_GPIO_get_inputs(GPIO0_LO); return (0u); } @endcode */ static inline uint32_t MSS_GPIO_get_inputs( GPIO_TypeDef const * gpio ) { return gpio->GPIO_IN; } /*-------------------------------------------------------------------------*//** The MSS_GPIO_enable_nondirect_irq() function is used to enable the non-direct interrupt input at the PLIC. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @return This function does not return any value. Example: Read and assign the current state of the GPIO outputs to a variable. @code #include "mss_gpio.h" int main(void) { uint32_t gpio_inputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE); MSS_GPIO_enable_nondirect_irq(GPIO1_LO); return (0u); } @endcode */ void MSS_GPIO_enable_nondirect_irq ( GPIO_TypeDef const * gpio ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_disable_nondirect_irq() function is used to disable the non-direct interrupt input at the PLIC. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @return This function does not return any value. Example: @code #include "mss_gpio.h" int main(void) { uint32_t gpio_inputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE); MSS_GPIO_disable_nondirect_irq(GPIO1_LO); return (0u); } @endcode */ void MSS_GPIO_disable_nondirect_irq ( GPIO_TypeDef const * gpio ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_get_outputs() function is used to read the current state of all GPIO ports configured as outputs. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @return This function returns a 32-bit unsigned integer where each bit represents the state of a GPIO output. The least significant bit represents the state of GPIO output 0 and the most significant bit the state of GPIO output 31. Example: Read and assign the current state of the GPIO outputs to a variable. @code #include "mss_gpio.h" int main(void) { uint32_t gpio_outputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config(GPIO0_LO, MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); gpio_outputs = MSS_GPIO_get_outputs(); gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK ); MSS_GPIO_set_outputs( gpio_outputs ); return (0u); } @endcode */ static inline uint32_t MSS_GPIO_get_outputs( GPIO_TypeDef const * gpio ) { return gpio->GPIO_OUT; } /*-------------------------------------------------------------------------*//** The MSS_GPIO_get_irq() function is used to read the current value of the IRQ register. The GPIO interrupts are multiplexed. The GPIO interrupts which are not available on the direct GPIO interrupt line on the PLIC are ORed and routed to the non-direct interrupt line on the PLIC for the corresponding GPIO hardware block. When the non-direct interrupt is asserted, this function can be used to determine which exact GPIO bit(s) caused the interrupt. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @return This function returns a 32-bit unsigned integer value of the IRQ register. Example: In the non-direct interrupt ISR, read the IRQ register to know which are the GPIO port causing the interrupt. @code uint8_t gpio2_non_direct_plic_IRQHandler(void) { uint32_t intr_num = 0; intr_num = MSS_GPIO_get_irq(GPIO2_LO); for(int cnt=0; cnt<32; cnt++) { if (1u == (intr_num & 0x00000001U)) { MSS_GPIO_clear_irq(GPIO0_LO, (mss_gpio_id_t)cnt); } intr_num >>= 1u; } return EXT_IRQ_KEEP_ENABLED; } @endcode */ static inline uint32_t MSS_GPIO_get_irq( GPIO_TypeDef const * gpio ) { return gpio->GPIO_IRQ; } /*-------------------------------------------------------------------------*//** The MSS_GPIO_drive_inout() function is used to set the output state of a single GPIO port configured as an INOUT. An INOUT GPIO can be in one of three states: - High - Low - High impedance An INOUT output would typically be used where several devices can drive the state of a shared signal line. The High and Low states are equivalent to the High and Low states of a GPIO configured as an output. The High impedance state is used to prevent the GPIO from driving its output state onto the signal line, while at the same time allowing the input state of the GPIO to be read. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param port_id The port_id parameter identifies the GPIO port for which you want to change the output state. An enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. @param inout_state The inout_state parameter specifies the state of the GPIO port identified by the port_id parameter. Allowed values of type mss_gpio_inout_state_t are as follows: - MSS_GPIO_DRIVE_HIGH - MSS_GPIO_DRIVE_LOW - MSS_GPIO_HIGH_Z (High impedance) @return This function does not return a value. Example: The call to MSS_GPIO_drive_inout() below will set the GPIO 7 output to the high impedance state. @code #include "mss_gpio.h" int main(void) { uint32_t gpio_inputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE); MSS_GPIO_drive_inout(GPIO0_LO, MSS_GPIO_7, MSS_GPIO_HIGH_Z); return (0u); } @endcode */ void MSS_GPIO_drive_inout ( GPIO_TypeDef * gpio, mss_gpio_id_t port_id, mss_gpio_inout_state_t inout_state ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_enable_irq() function is used to enable interrupt generation for the specified GPIO input. Interrupts are generated based on the state of the GPIO input and the interrupt mode configured for it by MSS_GPIO_config(). This function enables the corresponding GPIO direct interrupt on the PLIC as well. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param port_id The port_id parameter identifies the GPIO port for which you want to enable interrupt generation. An enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one in GPIO2 block. @return This function does not return a value. Example: The call to MSS_GPIO_enable_irq() below will allow GPIO 8 to generate interrupts. @code #include "mss_gpio.h" int main(void) { uint32_t gpio_inputs; MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config_all(GPIO0_LO, MSS_GPIO_INOUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE); MSS_GPIO_enable_irq(GPIO0_LO, MSS_GPIO_8); return (0u); } @endcode */ void MSS_GPIO_enable_irq ( GPIO_TypeDef * gpio, mss_gpio_id_t port_id ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_disable_irq() function is used to disable interrupt generation for the specified GPIO input. This function disables the corresponding GPIO direct interrupt on the PLIC as well. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param port_id The port_id parameter identifies the GPIO port for which you want to disable interrupt generation. An enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. @return This function does not return a value. Example: The call to MSS_GPIO_disable_irq() below will prevent GPIO 8 from generating interrupts. @code MSS_GPIO_disable_irq( MSS_GPIO_8 ); @endcode */ void MSS_GPIO_disable_irq ( GPIO_TypeDef * gpio, mss_gpio_id_t port_id ); /*-------------------------------------------------------------------------*//** The MSS_GPIO_clear_irq() function is used to clear a pending interrupt from the specified GPIO input. Note: The MSS_GPIO_clear_irq() function must be called as part of any GPIO interrupt service routine (ISR) in order to prevent the same interrupt event retriggering a call to the GPIO ISR. @param gpio The gpio parameter specifies the GPIO block that needs to be configured @param port_id The port_id parameter identifies the GPIO port for which you want to clear the interrupt. An enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. @return This function does not return a value. Example: The example below demonstrates the use of the MSS_GPIO_clear_irq() function as part of the GPIO 9 interrupt service routine. @code uint8_t gpio2_non_direct_plic_IRQHandler(void) { uint32_t intr_num = 0; intr_num = MSS_GPIO_get_irq(GPIO2_LO); for(int cnt=0; cnt<32; cnt++) { if (1u == (intr_num & 0x00000001U)) { MSS_GPIO_clear_irq(GPIO0_LO, (mss_gpio_id_t)cnt); } intr_num >>= 1u; } return EXT_IRQ_KEEP_ENABLED; } @endcode */ void MSS_GPIO_clear_irq ( GPIO_TypeDef * gpio, mss_gpio_id_t port_id ); #ifdef __cplusplus } #endif #endif /* MSS_GPIO_H_ */ mss_i2c/000077500000000000000000000000001432224323300346125ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_i2c.c000066400000000000000000001411151432224323300363200ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_i2c/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC Microprocessor Subsystem I2C bare metal software driver * implementation. * * SVN $Revision$ * SVN $Date$ */ #include "mss_i2c.h" #include "ASSERT.h" #include "mss_sysreg.h" #include "mss_plic.h" #include #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------------ * I2C transaction direction. */ #define WRITE_DIR 0u #define READ_DIR 1u /* -- TRANSACTIONS TYPES -- */ #define NO_TRANSACTION 0u #define MASTER_WRITE_TRANSACTION 1u #define MASTER_READ_TRANSACTION 2u #define MASTER_RANDOM_READ_TRANSACTION 3u #define WRITE_SLAVE_TRANSACTION 4u #define READ_SLAVE_TRANSACTION 5u /* -- SMBUS H/W STATES -- */ /* -- MASTER STATES -- */ #define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ #define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ #define ST_START 0x08u /* start condition sent */ #define ST_RESTART 0x10u /* repeated start */ #define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ #define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ #define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ #define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ #define ST_LOST_ARB 0x38u /* Master lost arbitration */ #define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ #define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ #define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ #define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ #define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ /* -- SLAVE STATES -- */ #define ST_SLAVE_SLAW 0x60u /* SLA+W received */ #define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ #define ST_SLV_LA 0x68u /* Slave lost arbitration */ #define ST_GCA 0x70u /* GCA received */ #define ST_GCA_LA 0x78u /* GCA lost arbitration */ #define ST_RDATA 0x80u /* Data received */ #define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ #define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ #define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ #define ST_RSTOP 0xA0u /* Stop received */ #define ST_SLARW_LA 0xB0u /* Arbitration lost */ #define ST_RACK 0xB8u /* Byte sent, ACK received */ #define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ #define ST_FINAL 0xC8u /* Final byte sent, ACK received */ #define ST_SLV_RST 0xD8u /* Slave reset state */ /* * Maximum address offset length in slave write-read transactions. * A maximum of two bytes will be interpreted as address offset within the slave * tx buffer. */ #define MAX_OFFSET_LENGTH 2u uint8_t g_i2c_axi_pos = 0x0u; /*------------------------------------------------------------------------------ * Local Function */ static uint32_t disable_interrupts( void ); static void restore_interrupts( uint32_t primask ); static void mss_i2c_isr( mss_i2c_instance_t * this_i2c ); static void enable_slave_if_required( mss_i2c_instance_t * this_i2c ); static void global_init( mss_i2c_instance_t * this_i2c ); /***************************************************************************//** * Disable all interrupts at the processor core level. * Return the interrupts enable state before disabling occurred so that it can * later be restored. */ extern psr_t HAL_disable_interrupts( void ); /***************************************************************************//** * Restore the interrupts enable state at the processor core level. * This function is normally passed the value returned from a previous call to * HAL_disable_interrupts(). */ extern void HAL_restore_interrupts( psr_t saved_psr ); /*------------------------------------------------------------------------------ * I2C instances *------------------------------------------------------------------------------ */ #define MSS_I2C0_LO_BASE (I2C_TypeDef*)0x2010A000u #define MSS_I2C1_LO_BASE (I2C_TypeDef*)0x2010B000u #define MSS_I2C0_HI_BASE (I2C_TypeDef*)0x2810A000u #define MSS_I2C1_HI_BASE (I2C_TypeDef*)0x2810B000u mss_i2c_instance_t g_mss_i2c0_lo; mss_i2c_instance_t g_mss_i2c1_lo; mss_i2c_instance_t g_mss_i2c0_hi; mss_i2c_instance_t g_mss_i2c1_hi; /*------------------------------------------------------------------------------ * MSS_I2C_init() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_init ( mss_i2c_instance_t * this_i2c, uint8_t ser_address, mss_i2c_clock_divider_t ser_clock_speed ) { uint32_t primask; uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); /* * Initialize all items of the this_i2c data structure to zero. This * initializes all state variables to their init value. It relies on * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all * have an actual value of zero. */ primask = disable_interrupts(); (void)memset(this_i2c, 0, sizeof(mss_i2c_instance_t)); global_init(this_i2c); /* Update Serial address of the device */ this_i2c->ser_address = (uint_fast8_t)ser_address << 1u; this_i2c->hw_reg->CTRL |= (uint8_t)((((clock_speed >> 2u) & 0x01u) << CR2) & CR2_MASK); this_i2c->hw_reg->CTRL |= (uint8_t)((((clock_speed >> 1u) & 0x01u) << CR1) & CR1_MASK); this_i2c->hw_reg->CTRL |= (uint8_t)(((clock_speed & (uint8_t)0x01u) << CR0) & CR0_MASK); this_i2c->hw_reg->ADDR = (uint8_t)this_i2c->ser_address; this_i2c->hw_reg->CTRL |= ENS1_MASK; /* set enable bit */ this_i2c->transfer_completion_handler = NULL; restore_interrupts(primask); } /*------------------------------------------------------------------------------ * MSS_I2C_write() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_write ( mss_i2c_instance_t * this_i2c, uint8_t serial_addr, const uint8_t * write_buffer, uint16_t write_size, uint8_t options ) { uint32_t primask; volatile uint8_t stat_ctrl; mss_i2c_status_t stat_slave = this_i2c->slave_status; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); primask = disable_interrupts(); /* Update the transaction only when there is no transaction going on I2C */ if (this_i2c->transaction == NO_TRANSACTION) { this_i2c->transaction = MASTER_WRITE_TRANSACTION; } /* Update the Pending transaction information so that transaction can restarted */ this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; /* Update target address */ this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; this_i2c->dir = WRITE_DIR; this_i2c->master_tx_buffer = write_buffer; this_i2c->master_tx_size = write_size; this_i2c->master_tx_idx = 0u; /* Set I2C status in progress */ this_i2c->master_status = MSS_I2C_IN_PROGRESS; this_i2c->options = options; if (MSS_I2C_IN_PROGRESS == stat_slave) { this_i2c->is_transaction_pending = 1u; } else { this_i2c->hw_reg->CTRL |= STA_MASK; } /* * Clear interrupts if required (depends on repeated starts). * Since the Bus is on hold, only then prior status needs to * be cleared. */ if (MSS_I2C_HOLD_BUS == this_i2c->bus_status) { this_i2c->hw_reg->CTRL &= ~SI_MASK; stat_ctrl = this_i2c->hw_reg->STATUS; } /* Enable the interrupt. (Re-enable) */ PLIC_EnableIRQ(this_i2c->irqn); restore_interrupts(primask); } /*------------------------------------------------------------------------------ * MSS_I2C_read() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_read ( mss_i2c_instance_t * this_i2c, uint8_t serial_addr, uint8_t * read_buffer, uint16_t read_size, uint8_t options ) { uint32_t primask; volatile uint8_t stat_ctrl; mss_i2c_status_t stat_slave = this_i2c->slave_status; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); primask = disable_interrupts(); /* Update the transaction only when there is no transaction going on I2C */ if (this_i2c->transaction == NO_TRANSACTION) { this_i2c->transaction = MASTER_READ_TRANSACTION; } /* Update the Pending transaction information so that transaction can restarted */ this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; /* Update target address */ this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; this_i2c->dir = READ_DIR; this_i2c->master_rx_buffer = read_buffer; this_i2c->master_rx_size = read_size; this_i2c->master_rx_idx = 0u; /* Set I2C status in progress */ this_i2c->master_status = MSS_I2C_IN_PROGRESS; this_i2c->options = options; if (MSS_I2C_IN_PROGRESS == stat_slave) { this_i2c->is_transaction_pending = 1u; } else { this_i2c->hw_reg->CTRL |= STA_MASK; } /* * Clear interrupts if required (depends on repeated starts). * Since the Bus is on hold, only then prior status needs to * be cleared. */ if (MSS_I2C_HOLD_BUS == this_i2c->bus_status) { this_i2c->hw_reg->CTRL &= ~SI_MASK; stat_ctrl = this_i2c->hw_reg->STATUS; } /* Enable the interrupt. ( Re-enable) */ PLIC_EnableIRQ(this_i2c->irqn); restore_interrupts(primask); } /*------------------------------------------------------------------------------ * MSS_I2C_write_read() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_write_read ( mss_i2c_instance_t * this_i2c, uint8_t serial_addr, const uint8_t * addr_offset, uint16_t offset_size, uint8_t * read_buffer, uint16_t read_size, uint8_t options ) { mss_i2c_status_t stat_slave = this_i2c->slave_status; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); ASSERT(offset_size > 0u); ASSERT(addr_offset != (const uint8_t *)0); ASSERT(read_size > 0u); ASSERT(read_buffer != (uint8_t *)0); if((read_size > 0u) && (offset_size > 0u)) { uint32_t primask; volatile uint8_t stat_ctrl; primask = disable_interrupts(); /* Update the transaction only when there is no transaction going on I2C */ if (this_i2c->transaction == NO_TRANSACTION) { this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; } /* Update the Pending transaction information so that transaction can restarted */ this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; /* Update target address */ this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; this_i2c->dir = WRITE_DIR; this_i2c->master_tx_buffer = addr_offset; this_i2c->master_tx_size = offset_size; this_i2c->master_tx_idx = 0u; this_i2c->master_rx_buffer = read_buffer; this_i2c->master_rx_size = read_size; this_i2c->master_rx_idx = 0u; /* Set I2C status in progress */ this_i2c->master_status = MSS_I2C_IN_PROGRESS; this_i2c->options = options; if (MSS_I2C_IN_PROGRESS == stat_slave) { this_i2c->is_transaction_pending = 1u; } else { this_i2c->hw_reg->CTRL |= STA_MASK; } /* * Clear interrupts if required (depends on repeated starts). * Since the Bus is on hold, only then prior status needs to * be cleared. */ if (MSS_I2C_HOLD_BUS == this_i2c->bus_status) { this_i2c->hw_reg->CTRL &= ~SI_MASK; stat_ctrl = this_i2c->hw_reg->STATUS; } /* Enable the interrupt. ( Re-enable) */ PLIC_EnableIRQ(this_i2c->irqn); restore_interrupts(primask); } } /*------------------------------------------------------------------------------ * MSS_I2C_get_status() * See "mss_i2c.h" for details of how to use this function. */ mss_i2c_status_t MSS_I2C_get_status ( mss_i2c_instance_t * this_i2c ) { mss_i2c_status_t i2c_status; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); i2c_status = this_i2c->master_status; return i2c_status; } /*------------------------------------------------------------------------------ * MSS_I2C_wait_complete() * See "mss_i2c.h" for details of how to use this function. */ mss_i2c_status_t MSS_I2C_wait_complete ( mss_i2c_instance_t * this_i2c, uint32_t timeout_ms ) { mss_i2c_status_t i2c_status; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); this_i2c->master_timeout_ms = timeout_ms; /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ do { i2c_status = this_i2c->master_status; } while(MSS_I2C_IN_PROGRESS == i2c_status); return i2c_status; } /*------------------------------------------------------------------------------ * I2C_system_tick() * See "core_i2c.h" for details of how to use this function. */ void MSS_I2C_system_tick ( mss_i2c_instance_t * this_i2c, uint32_t ms_since_last_tick ) { if(this_i2c->master_timeout_ms != MSS_I2C_NO_TIMEOUT) { if(this_i2c->master_timeout_ms > ms_since_last_tick) { this_i2c->master_timeout_ms -= ms_since_last_tick; } else { /* * Mark current transaction as having timed out. */ this_i2c->master_status = MSS_I2C_TIMED_OUT; this_i2c->transaction = NO_TRANSACTION; this_i2c->is_transaction_pending = (uint8_t)0; /* * Make sure we do not incorrectly signal a timeout for subsequent * transactions. */ this_i2c->master_timeout_ms = MSS_I2C_NO_TIMEOUT; } } } /*------------------------------------------------------------------------------ * MSS_I2C_set_slave_tx_buffer() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_set_slave_tx_buffer ( mss_i2c_instance_t * this_i2c, const uint8_t * tx_buffer, uint16_t tx_size ) { uint32_t primask; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); primask = disable_interrupts(); this_i2c->slave_tx_buffer = tx_buffer; this_i2c->slave_tx_size = tx_size; this_i2c->slave_tx_idx = 0u; restore_interrupts(primask); } /*------------------------------------------------------------------------------ * MSS_I2C_set_slave_rx_buffer() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_set_slave_rx_buffer ( mss_i2c_instance_t * this_i2c, uint8_t * rx_buffer, uint16_t rx_size ) { uint32_t primask; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); primask = disable_interrupts(); this_i2c->slave_rx_buffer = rx_buffer; this_i2c->slave_rx_size = rx_size; this_i2c->slave_rx_idx = 0u; restore_interrupts(primask); } /*------------------------------------------------------------------------------ * MSS_I2C_set_slave_mem_offset_length() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_set_slave_mem_offset_length ( mss_i2c_instance_t * this_i2c, uint8_t offset_length ) { ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); ASSERT(offset_length <= MAX_OFFSET_LENGTH); if(offset_length > MAX_OFFSET_LENGTH) { this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; } else { this_i2c->slave_mem_offset_length = offset_length; } } /*------------------------------------------------------------------------------ * MSS_I2C_register_transfer_completion_handler() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_register_transfer_completion_handler ( mss_i2c_instance_t * this_i2c, mss_i2c_transfer_completion_t completion_handler ) { ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); if(completion_handler == NULL) { this_i2c->transfer_completion_handler = 0u; } else { this_i2c->transfer_completion_handler = completion_handler; } } /*------------------------------------------------------------------------------ * MSS_I2C_register_write_handler() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_register_write_handler ( mss_i2c_instance_t * this_i2c, mss_i2c_slave_wr_handler_t handler ) { ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); this_i2c->slave_write_handler = handler; } /*------------------------------------------------------------------------------ * MSS_I2C_enable_slave() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_enable_slave ( mss_i2c_instance_t * this_i2c ) { uint32_t primask; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); primask = disable_interrupts(); /* Set the assert acknowledge bit. */ this_i2c->hw_reg->CTRL |= AA_MASK; /* Enable slave */ this_i2c->is_slave_enabled = 1u; restore_interrupts(primask); /* Enable Interrupt */ PLIC_EnableIRQ(this_i2c->irqn); } /*------------------------------------------------------------------------------ * MSS_I2C_disable_slave() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_disable_slave ( mss_i2c_instance_t * this_i2c ) { uint32_t primask; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); primask = disable_interrupts(); /* Reset the assert acknowledge bit. */ this_i2c->hw_reg->CTRL &= ~AA_MASK; /* Disable slave */ this_i2c->is_slave_enabled = 0u; restore_interrupts(primask); } /*------------------------------------------------------------------------------ * MSS Slave enable function */ static void enable_slave_if_required ( mss_i2c_instance_t * this_i2c ) { if(this_i2c->is_slave_enabled) { this_i2c->hw_reg->CTRL |= AA_MASK; } } /*------------------------------------------------------------------------------ * MSS I2C interrupt service routine. *------------------------------------------------------------------------------ * Parameters: * * mss_i2c_instance_t * this_i2c: * Pointer to the mss_i2c_instance_t data structure holding all data related to * the MSS I2C instance that generated the interrupt. */ static void mss_i2c_isr ( mss_i2c_instance_t * this_i2c ) { volatile uint8_t status; uint8_t data; uint8_t hold_bus; uint8_t clear_irq = 1u; ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); status = this_i2c->hw_reg->STATUS; switch( status ) { /************** MASTER TRANSMITTER / RECEIVER *******************/ case ST_START: /* start has been xmt'd */ case ST_RESTART: /* repeated start has been xmt'd */ this_i2c->hw_reg->CTRL &= ~STA_MASK; this_i2c->hw_reg->DATA = (uint8_t)(this_i2c->target_addr | (this_i2c->dir & DATA_DIR_MASK)); if (this_i2c->dir == WRITE_DIR) { this_i2c->master_tx_idx = 0u; } else if (this_i2c->dir == READ_DIR) { this_i2c->master_rx_idx = 0u; } else { ; /* For LDRA*/ } /* * Clear the pending transaction. This condition will be true if the slave * has acquired the bus to carry out pending master transaction which * it had received during its slave transmission or reception mode. */ if (this_i2c->is_transaction_pending) { this_i2c->is_transaction_pending = 0u; } /* * Make sure to update proper transaction after master START * or RESTART */ if (this_i2c->transaction != this_i2c->pending_transaction) { this_i2c->transaction = this_i2c->pending_transaction; } break; case ST_LOST_ARB: /* Set start bit. Let's keep trying! Don't give up! */ this_i2c->hw_reg->CTRL |= STA_MASK; break; /******************* MASTER TRANSMITTER *************************/ case ST_SLAW_NACK: /* SLA+W has been transmitted; not ACK has been received - let's stop. */ this_i2c->hw_reg->CTRL |= STO_MASK; this_i2c->master_status = MSS_I2C_FAILED; this_i2c->transaction = NO_TRANSACTION; enable_slave_if_required(this_i2c); break; case ST_SLAW_ACK: case ST_TX_DATA_ACK: /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ if (this_i2c->master_tx_idx < this_i2c->master_tx_size) { this_i2c->hw_reg->DATA = this_i2c->master_tx_buffer[this_i2c->master_tx_idx]; this_i2c->master_tx_idx++; } else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) { /* We are finished sending the address offset part of a random read transaction. * It is is time to send a restart in order to change direction. */ this_i2c->dir = READ_DIR; this_i2c->hw_reg->CTRL |= STA_MASK; } else /* done sending. let's stop */ { /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS; /* Store the information of current I2C bus status in the bus_status*/ this_i2c->bus_status = hold_bus; if (hold_bus == 0u) { this_i2c->hw_reg->CTRL |= STO_MASK; /*xmt stop condition */ enable_slave_if_required(this_i2c); } else { PLIC_DisableIRQ(this_i2c->irqn); clear_irq = 0u; } this_i2c->master_status = MSS_I2C_SUCCESS; } break; case ST_TX_DATA_NACK: /* data byte SENT, ACK to be received * In fact, this means we've received a NACK (This may not be * obvious, but if we've rec'd an ACK then we would be in state * 0x28!) hence, let's send a stop bit */ this_i2c->hw_reg->CTRL |= STO_MASK; this_i2c->master_status = MSS_I2C_FAILED; /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; enable_slave_if_required(this_i2c); break; /********************* MASTER (or slave?) RECEIVER *************************/ /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ case ST_SLAR_ACK: /* SLA+R tx'ed. */ /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless * the next byte is the last byte of the read transaction. */ if (this_i2c->master_rx_size > 1u) { this_i2c->hw_reg->CTRL |= AA_MASK; } else if (1u == this_i2c->master_rx_size) { this_i2c->hw_reg->CTRL &= ~AA_MASK; } else /* this_i2c->master_rx_size == 0u */ { this_i2c->hw_reg->CTRL |= AA_MASK; this_i2c->hw_reg->CTRL |= STO_MASK; this_i2c->master_status = MSS_I2C_SUCCESS; this_i2c->transaction = NO_TRANSACTION; } break; case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ this_i2c->hw_reg->CTRL |= STO_MASK; this_i2c->master_status = MSS_I2C_FAILED; /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; enable_slave_if_required(this_i2c); break; case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ /* First, get the data */ this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = this_i2c->hw_reg->DATA; this_i2c->master_rx_idx++; if (this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) { /* If we're at the second last byte, let's set AA to 0 so * we return a NACK at the last byte. */ this_i2c->hw_reg->CTRL &= ~AA_MASK; } break; case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ /* Get the data, then send a stop condition */ this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = this_i2c->hw_reg->DATA; hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS; /* Store the information of current I2C bus status in the bus_status*/ this_i2c->bus_status = hold_bus; if (hold_bus == 0u) { this_i2c->hw_reg->CTRL |= STO_MASK; /*xmt stop condition */ /* Bus is released, now we can start listening to bus, if it is slave */ enable_slave_if_required(this_i2c); } else { PLIC_DisableIRQ(this_i2c->irqn); clear_irq = 0u; } /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; this_i2c->master_status = MSS_I2C_SUCCESS; break; /******************** SLAVE RECEIVER **************************/ case ST_GCA_NACK: /* NACK after, GCA addressing */ case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ this_i2c->hw_reg->CTRL |= AA_MASK; this_i2c->transaction = NO_TRANSACTION; this_i2c->slave_status = MSS_I2C_SUCCESS; /* Check if transaction was pending. If yes, set the START bit */ if (this_i2c->is_transaction_pending) { this_i2c->hw_reg->CTRL |= STA_MASK ; } break; case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ /* * We lost arbitration and either the GCE or our address was the * one received so pend the master operation we were starting. */ this_i2c->is_transaction_pending = 1u; /* Fall through to normal ST processing as we are now in slave mode */ case ST_GCA: /* General call address received, ACK returned */ case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ this_i2c->transaction = WRITE_SLAVE_TRANSACTION; this_i2c->slave_rx_idx = 0u; this_i2c->random_read_addr = 0u; /* If Start Bit is set, clear it, but store that information since it is because of * pending transaction */ if (this_i2c->hw_reg->CTRL & STA_MASK) { this_i2c->hw_reg->CTRL &= ~STA_MASK ; this_i2c->is_transaction_pending = 1u; } this_i2c->slave_status = MSS_I2C_IN_PROGRESS; #ifdef MSS_I2C_INCLUDE_SLA_IN_RX_PAYLOAD /* Fall through to put address as first byte in payload buffer */ #else /* Only break from this case if the slave address must NOT be included at the * beginning of the received write data. */ break; #endif case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ case ST_RDATA: /* DATA received; must clear DATA register */ if ((this_i2c->slave_rx_buffer != (uint8_t *)0) && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) { data = this_i2c->hw_reg->DATA; this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx] = data; this_i2c->slave_rx_idx++; #ifdef MSS_I2C_INCLUDE_SLA_IN_RX_PAYLOAD if((ST_RDATA == status) || (ST_GCA_ACK == status)) { /* Ignore the slave address byte in the random read address computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD is defined. */ #endif this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; #ifdef MSS_I2C_INCLUDE_SLA_IN_RX_PAYLOAD } #endif } if (this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) { this_i2c->hw_reg->CTRL &= ~AA_MASK; /* send a NACK when done (next reception) */ } break; case ST_RSTOP: /* STOP or repeated START occurred. */ /* We cannot be sure if the transaction has actually completed as * this hardware state reports that either a STOP or repeated START * condition has occurred. We assume that this is a repeated START * if the transaction was a write from the master to this point.*/ if (this_i2c->transaction == WRITE_SLAVE_TRANSACTION) { if (this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length) { this_i2c->slave_tx_idx = this_i2c->random_read_addr; } { /* Call the slave's write transaction handler if it exists. */ if (this_i2c->slave_write_handler != (mss_i2c_slave_wr_handler_t)0u) { mss_i2c_slave_handler_ret_t h_ret; h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); if (MSS_I2C_REENABLE_SLAVE_RX == h_ret) { /* There is a small risk that the write handler could * call MSS_I2C_disable_slave() but return * MSS_I2C_REENABLE_SLAVE_RX in error so we only * enable ACKs if still in slave mode. */ enable_slave_if_required(this_i2c); this_i2c->hw_reg->CTRL |= AA_MASK; } else { this_i2c->hw_reg->CTRL &= ~AA_MASK; /* Clear slave mode flag as well otherwise in mixed * master/slave applications, the AA bit will get set by * subsequent master operations. */ this_i2c->is_slave_enabled = 0u; } } else { /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ this_i2c->hw_reg->CTRL |= AA_MASK; } } } else /* A stop or repeated start outside a write/read operation */ { /* * Reset slave_tx_idx so that a subsequent read will result in the slave's * transmit buffer being sent from the first byte. */ this_i2c->slave_tx_idx = 0u; /* * See if we need to re-enable acknowledgment as some error conditions, such * as a master prematurely ending a transfer, can see us get here with AA set * to 0 which will disable slave operation if we are not careful. */ enable_slave_if_required(this_i2c); } /* Mark any previous master write transaction as complete. */ this_i2c->slave_status = MSS_I2C_SUCCESS; /* Check if transaction was pending. If yes, set the START bit */ if (this_i2c->is_transaction_pending) { this_i2c->hw_reg->CTRL |= STA_MASK ; } /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; break; case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction. */ this_i2c->transaction = NO_TRANSACTION; /* * Reset slave_tx_idx so that a subsequent read will result in the slave's * transmit buffer being sent from the first byte. */ this_i2c->slave_tx_idx = 0u; /* * Clear status to I2C_FAILED only if there was an operation in progress. */ if (MSS_I2C_IN_PROGRESS == this_i2c->slave_status) { this_i2c->slave_status = MSS_I2C_FAILED; } enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ break; /****************** SLAVE TRANSMITTER **************************/ case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ case ST_SLARW_LA: /* Arbitration lost, SLA+R received, ACK returned */ case ST_RACK: /* Data tx'ed, ACK received */ if (status == ST_SLAVE_SLAR_ACK) { this_i2c->transaction = READ_SLAVE_TRANSACTION; this_i2c->random_read_addr = 0u; this_i2c->slave_status = MSS_I2C_IN_PROGRESS; /* If Start Bit is set, clear it, but store that information since it is because of * pending transaction */ if ((this_i2c->hw_reg->CTRL & STA_MASK)) { this_i2c->hw_reg->CTRL &= ~STA_MASK ; this_i2c->is_transaction_pending = 1u; } } if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) { /* Ensure 0xFF is returned to the master when the slave specifies * an empty transmit buffer. */ this_i2c->hw_reg->DATA = 0xFFu; } else { /* Load the data the data byte to be sent to the master. */ this_i2c->hw_reg->DATA = this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx]; this_i2c->slave_tx_idx++; } /* Determine if this is the last data byte to send to the master. */ if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ { this_i2c->hw_reg->CTRL &= ~AA_MASK; /* Next read transaction will result in slave's transmit buffer * being sent from the first byte. */ this_i2c->slave_tx_idx = 0u; } break; case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ case ST_FINAL: /* Last Data byte tx'ed, ACK received */ /* We assume that the transaction will be stopped by the master. * Reset slave_tx_idx so that a subsequent read will result in the slave's * transmit buffer being sent from the first byte. */ this_i2c->slave_tx_idx = 0u; this_i2c->hw_reg->CTRL |= AA_MASK; /* Mark previous state as complete */ this_i2c->slave_status = MSS_I2C_SUCCESS; /* Check if transaction was pending. If yes, set the START bit */ if (this_i2c->is_transaction_pending) { this_i2c->hw_reg->CTRL |= STA_MASK ; } /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; break; /* Master Reset has been activated Wait 35 ms for interrupt to be set, * clear interrupt and proceed to 0xF8 state. */ case ST_RESET_ACTIVATED: case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ default: /* Some undefined state has encountered. Clear Start bit to make * sure, next good transaction happen */ this_i2c->hw_reg->CTRL &= ~STA_MASK; /* * Set the transaction back to NO_TRANSACTION to allow user to do further * transaction */ this_i2c->transaction = NO_TRANSACTION; /* * Reset slave_tx_idx so that a subsequent read will result in the slave's * transmit buffer being sent from the first byte. */ this_i2c->slave_tx_idx = 0u; /* * Clear statuses to I2C_FAILED only if there was an operation in progress. */ if (MSS_I2C_IN_PROGRESS == this_i2c->master_status) { this_i2c->master_status = MSS_I2C_FAILED; } if (MSS_I2C_IN_PROGRESS == this_i2c->slave_status) { this_i2c->slave_status = MSS_I2C_FAILED; } break; } if ((this_i2c->master_status != MSS_I2C_IN_PROGRESS) && (this_i2c->slave_status != MSS_I2C_IN_PROGRESS) && (this_i2c->transfer_completion_handler) && (this_i2c->is_slave_enabled == 0)) { if ((this_i2c->master_status != MSS_I2C_IN_PROGRESS)) { this_i2c->transfer_completion_handler(this_i2c, this_i2c->master_status); } else if ((this_i2c->slave_status != MSS_I2C_IN_PROGRESS)) { this_i2c->transfer_completion_handler(this_i2c, this_i2c->slave_status); } else { ; /* For LDRA */ } } /* ST_BUS_ERROR */ if (clear_irq) { /* clear interrupt. */ this_i2c->hw_reg->CTRL &= ~SI_MASK; } /* Read the status register to ensure the last I2C registers write took place * in a system built around a bus making use of posted writes. */ status = this_i2c->hw_reg->STATUS; } /*------------------------------------------------------------------------------ * MSS_I2C_smbus_init() * See "mss_i2c.h" for details of how to use this function. */ /* * SMBSUS_NO = 1 * SMBALERT_NO = 1 * SMBus enable = 1 */ #define MSS_INIT_AND_ENABLE_SMBUS 0x54u void MSS_I2C_smbus_init ( mss_i2c_instance_t * this_i2c, uint8_t frequency ) { /* Set the frequency before enabling time out logic */ this_i2c->hw_reg->FREQ = frequency; /* Enable SMBUS */ this_i2c->hw_reg->SMBUS = MSS_INIT_AND_ENABLE_SMBUS; } /*------------------------------------------------------------------------------ * MSS_I2C_enable_smbus_irq() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_enable_smbus_irq ( mss_i2c_instance_t * this_i2c, uint8_t irq_type ) { ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); /* Enable any interrupts selected by the user */ if ((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi)) { if (irq_type & MSS_I2C_SMBALERT_IRQ) { this_i2c->hw_reg->SMBUS |= SMBALERT_IE_MASK; /* Enable the interrupt at the PLIC */ PLIC_EnableIRQ(I2C0_ALERT_PLIC); } if (irq_type & MSS_I2C_SMBSUS_IRQ) { this_i2c->hw_reg->SMBUS |= SMBSUS_IE_MASK; /* Enable the interrupt at the PLIC */ PLIC_EnableIRQ(I2C0_SUS_PLIC); } } else { if (irq_type & MSS_I2C_SMBALERT_IRQ) { this_i2c->hw_reg->SMBUS |= SMBALERT_IE_MASK; /* Enable the interrupt at the PLIC */ PLIC_EnableIRQ(I2C1_ALERT_PLIC); } if (irq_type & MSS_I2C_SMBSUS_IRQ) { this_i2c->hw_reg->SMBUS |= SMBSUS_IE_MASK; /* Enable the interrupt at the PLIC */ PLIC_EnableIRQ(I2C1_SUS_PLIC); } } } /*------------------------------------------------------------------------------ * MSS_I2C_disable_smbus_irq() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_disable_smbus_irq ( mss_i2c_instance_t * this_i2c, uint8_t irq_type ) { ASSERT((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi) || (this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)); /* Disable any interrupts selected by the user */ if ((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi)) { if (irq_type & MSS_I2C_SMBALERT_IRQ) { /* Disable interrupt at the PLIC and the MSS I2C */ this_i2c->hw_reg->SMBUS &= ~SMBALERT_IE_MASK; PLIC_DisableIRQ(I2C0_ALERT_PLIC); } if (irq_type & MSS_I2C_SMBSUS_IRQ) { /* Disable interrupt at the PLIC and the MSS I2C */ this_i2c->hw_reg->SMBUS &= ~SMBSUS_IE_MASK; PLIC_DisableIRQ(I2C0_SUS_PLIC); } } else { if (irq_type & MSS_I2C_SMBALERT_IRQ) { /* Disable interrupt at the PLIC and the MSS I2C */ this_i2c->hw_reg->SMBUS &= ~SMBALERT_IE_MASK; PLIC_DisableIRQ(I2C1_ALERT_PLIC); } if (irq_type & MSS_I2C_SMBSUS_IRQ) { /* Disable interrupt at the PLIC and the MSS I2C */ this_i2c->hw_reg->SMBUS &= ~SMBSUS_IE_MASK; PLIC_DisableIRQ(I2C1_SUS_PLIC); } } } /*------------------------------------------------------------------------------ * MSS_I2C_suspend_slave() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_suspend_smbus_slave ( mss_i2c_instance_t * this_i2c ) { /* Active low output so 0 asserts condition */ this_i2c->hw_reg->SMBUS &= ~SMBSUS_NO_MASK; } /*------------------------------------------------------------------------------ * MSS_I2C_resume_slave() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_resume_smbus_slave ( mss_i2c_instance_t * this_i2c ) { /* Active low output so 1 clears condition */ this_i2c->hw_reg->SMBUS |= SMBSUS_NO_MASK; } /*------------------------------------------------------------------------------ * MSS_I2C_reset_smbus() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_reset_smbus ( mss_i2c_instance_t * this_i2c ) { this_i2c->hw_reg->SMBUS |= SMBUS_RESET_MASK; } /*------------------------------------------------------------------------------ * MSS_I2C_set_smbus_alert() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_set_smbus_alert ( mss_i2c_instance_t * this_i2c ) { /* Active low output so 0 asserts condition */ this_i2c->hw_reg->SMBUS &= ~SMBALERT_NO_MASK; } /*------------------------------------------------------------------------------ * MSS_I2C_clear_smbus_alert() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_clear_smbus_alert ( mss_i2c_instance_t * this_i2c ) { /* Active low output so 1 clears condition */ this_i2c->hw_reg->SMBUS |= SMBALERT_NO_MASK; } /*------------------------------------------------------------------------------ * MSS_i2C_set_gca() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_set_gca ( mss_i2c_instance_t * this_i2c ) { /* accept GC addressing. */ this_i2c->hw_reg->ADDR |= ADDR_GC_MASK; } /*------------------------------------------------------------------------------ * MSS_I2C_clear_gca() * See "mss_i2c.h" for details of how to use this function. */ void MSS_I2C_clear_gca ( mss_i2c_instance_t * this_i2c ) { /* Disable GC addressing. */ this_i2c->hw_reg->ADDR &= ~ADDR_GC_MASK; } /*------------------------------------------------------------------------------ * MSS_I2C_set_user_data() * See "i2c.h" for details of how to use this function. */ void MSS_I2C_set_user_data ( mss_i2c_instance_t * this_i2c, void * p_user_data ) { this_i2c->p_user_data = p_user_data ; } /*------------------------------------------------------------------------------ * MSS_I2C_get_user_data() * See "i2c.h" for details of how to use this function. */ void * MSS_I2C_get_user_data ( mss_i2c_instance_t * this_i2c ) { return (this_i2c->p_user_data); } /*------------------------------------------------------------------------------ * Disable Interrupt */ static uint32_t disable_interrupts(void) { uint32_t primask; primask = HAL_disable_interrupts(); return primask; } /*------------------------------------------------------------------------------ * Restore Interrupt */ static void restore_interrupts(uint32_t primask) { HAL_restore_interrupts(primask); } /******************************************************************************* * Global initialization based on instance */ static void global_init ( mss_i2c_instance_t * this_i2c ) { if (&g_mss_i2c0_lo == this_i2c) { this_i2c->hw_reg = MSS_I2C0_LO_BASE; g_i2c_axi_pos |= 0x01; } else if (&g_mss_i2c1_lo == this_i2c) { this_i2c->hw_reg = MSS_I2C1_LO_BASE; g_i2c_axi_pos |= 0x02; } else if (&g_mss_i2c0_hi == this_i2c) { this_i2c->hw_reg = MSS_I2C0_HI_BASE; g_i2c_axi_pos |= 0x04; } else if (&g_mss_i2c1_hi == this_i2c) { this_i2c->hw_reg = MSS_I2C1_HI_BASE; g_i2c_axi_pos |= 0x08; } else { ; } if ((this_i2c == &g_mss_i2c0_lo) || (this_i2c == &g_mss_i2c0_hi)) { this_i2c->irqn = I2C0_MAIN_PLIC; /* reset I2C0 */ SYSREG->SOFT_RESET_CR |= (uint32_t)(0x01UL << 12); /* Take I2C0 out of reset. */ SYSREG->SOFT_RESET_CR &= ~(0x01UL << 12); } else if ((this_i2c == &g_mss_i2c1_lo) || (this_i2c == &g_mss_i2c1_hi)) { this_i2c->irqn = I2C1_MAIN_PLIC; /* reset I2C1 */ SYSREG->SOFT_RESET_CR |= (uint32_t)(0x01UL << 13); /* Take I2C1 out of reset. */ SYSREG->SOFT_RESET_CR &= ~(0x01UL << 13); } else { ; } } /*------------------------------------------------------------------------------ * External_i2c0_main_plic_IRQHandler interrupt handler */ uint8_t External_i2c0_main_plic_IRQHandler(void) { if (g_i2c_axi_pos & 0x01) { mss_i2c_isr(&g_mss_i2c0_lo); } else { mss_i2c_isr(&g_mss_i2c0_hi); } return (uint8_t)EXT_IRQ_KEEP_ENABLED; } /*------------------------------------------------------------------------------ * i2c1_main_plic_IRQHandler interrupt handler */ uint8_t i2c1_main_plic_IRQHandler(void) { if (g_i2c_axi_pos & 0x02) { mss_i2c_isr(&g_mss_i2c1_lo); } else { mss_i2c_isr(&g_mss_i2c1_hi); } return (uint8_t)EXT_IRQ_KEEP_ENABLED; } #ifdef __cplusplus } #endif mss_i2c.h000066400000000000000000002567471432224323300363470ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_i2c/******************************************************************************* * (c) Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * All rights reserved. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC Microprocessor Subsystem I2C bare metal software driver * public API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS I2C Bare Metal Driver. ============================================================================== Introduction ============================================================================== The PolarFire SoC microcontroller subsystem (MSS) includes two I2C peripherals for serial communication. This driver provides a set of functions for controlling the MSS I2Cs as part of a bare metal system where no operating system is available. The driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of this driver. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all features of the MSS I2C peripherals is covered by this driver with the exception of the PolarFire SoC IOMUX configuration. PolarFire SoC allows multiple non-concurrent uses of some external pins through IOMUX configuration. This feature allows optimization of external pin usage by assigning external pins for use by either the microcontroller subsystem or the FPGA fabric. The MSS I2C serial signals are routed through IOMUXs to the PolarFire SoC device external pins. The MSS I2C serial signals may also be routed through IOMUXs to the PolarFire SoC FPGA fabric. For more information on IOMUX, refer to the IOMUX section of the PolarFire SoC Microcontroller Subsystem (MSS) User's Guide. The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You must ensure that the MSS I2C peripherals are enabled and configured in the PolarFire SoC MSS configurator if you wish to use them. For more information on IOMUXs, refer to the IOMUX section of the PolarFire SoC Microcontroller Subsystem (MSS) User's Guide. On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple masters and multiple slaves. Five RISC-V CPUs connect to the Master ports M10 to M14 of the AXI switch. By default, all the APB peripherals are accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB bridges (referred as main APB bus). However, to support logical separation in the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to APB bridges (referred as the AMP APB bus). Application must make sure that the desired I2C instance is connected appropriately on the desired APB bus by configuring the PolarFire SoC system registers (SYSREG) as per the application need and that the appropriate data structures are provided to this driver as parameter to the functions provided by this driver. The base address and register addresses are defined in this driver as constants. The interrupt number assignment for the MSS I2C peripherals are defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole tool chain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS I2C driver functions are grouped into the following categories: - Initialization and configuration functions - Interrupt control - I2C slave address configuration - I2C master operations - functions to handle write, read and write-read transactions - I2C slave operations - functions to handle write, read and write-read transactions - Mixed master and slave operations - SMBus interface configuration and control -------------------------------- Initialization and Configuration -------------------------------- The MSS I2C driver is initialized through a call to the MSS_I2C_init() function. This function takes the MSS I2C's configuration as parameters. The MSS_I2C_init() function must be called before any other MSS I2C driver functions can be called. The first parameter of the MSS_I2C_init() function is a pointer to one of four global data structures used by the driver to store state information for each MSS I2C. A pointer to these data structures is also used as the first parameter to any of the driver functions to identify which MSS I2C will be used by the called function. The names of these data structures are g_mss_i2c0_lo g_mss_i2c0_hi g_mss_i2c1_lo g_mss_i2c1_hi Therefore any call to an MSS I2C driver function should be of the form MSS_I2C_function_name( &g_mss_i2c0_lo, ... ) or MSS_I2C_function_name( &g_mss_i2c1_lo, ... ). The MSS_I2C_init() function call for each MSS I2C also takes the I2C serial address assigned to the MSS I2C and the serial clock divider to be used to generate its I2C clock as configuration parameters. -------------------------------- Interrupt Control -------------------------------- The MSS I2C driver is interrupt driven and it enables and disables the generation of INT interrupts by MSS I2C at various times when it is operating. The driver automatically handles MSS I2C interrupts internally, including enabling, disabling and clearing MSS I2C interrupts in the RISC-V interrupt controller when required. The function MSS_I2C_register_write_handler() is used to register a write handler function with the MSS I2C driver that it calls on completion of an I2C write transaction by the MSS I2C slave. It is your responsibility to create and register the implementation of this handler function that processes or triggers the processing of the received data. The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are enabled and disabled through MSS_I2C_enable_smbus_irq() and MSS_I2C_disable_smbus_irq() respectively. It is your responsibility to create interrupt handler functions in your application to get the desired response for the SMBus interrupts. -------------------------------- I2C Slave Address Configuration -------------------------------- The PolarFire SoC MSS I2C can respond to two slave addresses: - Slave address - This is the address that is used for accessing an MSS I2C peripheral when it acts as a slave in I2C transactions. You must configure the slave address via MSS_I2C_init(). - General call address - An MSS I2C slave can be configured to respond to a broadcast command by a master transmitting the general call address of 0x00. Use the MSS_I2C_set_gca() function to enable the slave to respond to the general call address. If the I2C slave is not required to respond to the general call address, disable this address by calling MSS_I2C_clear_gca(). -------------------------------- Transaction Types -------------------------------- The MSS I2C driver is designed to handle three types of I2C transactions: Write transactions Read transactions Write-read transactions Write transaction The master I2C device initiates a write transaction by sending a START bit as soon as the bus becomes free. The START bit is followed by the 7-bit serial address of the target slave device followed by the read/write bit indicating the direction of the transaction. The slave acknowledges the receipt of its address with an acknowledge bit. The master sends data one byte at a time to the slave, which must acknowledge the receipt of each byte for the next byte to be sent. The master sends a STOP bit to complete the transaction. The slave can abort the transaction by replying with a non-acknowledge bit instead of an acknowledge bit. The application programmer can choose not to send a STOP bit at the end of the transaction causing the next transaction to begin with a repeated START bit. Read transaction The master I2C device initiates a read transaction by sending a START bit as soon as the bus becomes free. The START bit is followed by the 7-bit serial address of the target slave device followed by the read/write bit indicating the direction of the transaction. The slave acknowledges the receipt of its slave address with an acknowledge bit. The slave sends data one byte at a time to the master, which must acknowledge receipt of each byte for the next byte to be sent. The master sends a non-acknowledge bit following the last byte it wishes to read followed by a STOP bit. The application programmer can choose not to send a STOP bit at the end of the transaction causing the next transaction to begin with a repeated START bit. Write-read transaction The write-read transaction is a combination of a write transaction immediately followed by a read transaction. There is no STOP bit between the write and read phases of a write-read transaction. A repeated START bit is sent between the write and read phases. Whilst the write handler is being executed, the slave holds the clock line low to stretch the clock until the response is ready. The write-read transaction is typically used to send a command or offset in the write transaction specifying the logical data to be transferred during the read phase. The application programmer can choose not to send a STOP bit at the end of the transaction causing the next transaction to begin with a repeated START bit. -------------------------------- Master Operations -------------------------------- The application can use the MSS_I2C_write(), MSS_I2C_read() and MSS_I2C_write_read() functions to initiate an I2C bus transaction. The application can then wait for the transaction to complete using the MSS_I2C_wait_complete() function or poll the status of the I2C transaction using the MSS_I2C_get_status() function until it returns a value different from MSS_I2C_IN_PROGRESS or register a call back function using MSS_I2C_register_transfer_completion_handler() to notify the completion of the previously initiated I2C transfer. The MSS_I2C_system_tick() function can be used to set a time base for the MSS_I2C_wait_complete() function's time out delay. -------------------------------- Slave Operations -------------------------------- The configuration of the MSS I2C driver to operate as an I2C slave requires the use of the following functions: - MSS_I2C_set_slave_tx_buffer() - MSS_I2C_set_slave_rx_buffer() - MSS_I2C_set_slave_mem_offset_length() - MSS_I2C_register_write_handler() - MSS_I2C_enable_slave() Use of all functions is not required if the slave I2C does not need to support all types of I2C read transactions. The subsequent sections list the functions that must be used to support each transaction type. Responding to read transactions The following functions are used to configure the MSS I2C driver to respond to I2C read transactions: - MSS_I2C_set_slave_tx_buffer() - MSS_I2C_enable_slave() The function MSS_I2C_set_slave_tx_buffer() specifies the data buffer that will be transmitted when the I2C slave is the target of an I2C read transaction. It is then up to the application to manage the content of that buffer to control the data that will be transmitted to the I2C master as a result of the read transaction. The function MSS_I2C_enable_slave() enables the MSS I2C hardware instance to respond to I2C transactions. It must be called after the MSS I2C driver has been configured to respond to the required transaction types. Responding to write transactions The following functions are used to configure the MSS I2C driver to respond to I2C write transactions: - MSS_I2C_set_slave_rx_buffer() - MSS_I2C_register_write_handler() - MSS_I2C_enable_slave() The function MSS_I2C_set_slave_rx_buffer() specifies the data buffer that will be used to store the data received by the I2C slave when it is the target an I2C write transaction. The function MSS_I2C_register_write_handler() specifies the handler function that must be called on completion of the I2C write transaction. It is this handler function that will process or trigger the processing of the received data. The function MSS_I2C_enable_slave() enables the MSS I2C hardware instance to respond to I2C transactions. It must be called after the MSS I2C driver has been configured to respond to the required transaction types. Responding to write-read transactions The following functions are used to configure the MSS I2C driver to respond to write-read transactions: - MSS_I2C_set_slave_mem_offset_length() - MSS_I2C_set_slave_tx_buffer() - MSS_I2C_set_slave_rx_buffer() - MSS_I2C_register_write_handler() - MSS_I2C_enable_slave() The function MSS_I2C_set_slave_mem_offset_length() specifies the number of bytes expected by the I2C slave during the write phase of the write-read transaction. The function MSS_I2C_set_slave_tx_buffer() specifies the data that will be transmitted to the I2C master during the read phase of the write-read transaction. The value received by the I2C slave during the write phase of the transaction will be used as an index into the transmit buffer specified by this function to decide which part of the transmit buffer will be transmitted to the I2C master as part of the read phase of the write-read transaction. The function MSS_I2C_set_slave_rx_buffer() specifies the data buffer that will be used to store the data received by the I2C slave during the write phase of the write-read transaction. This buffer must be at least large enough to accommodate the number of bytes specified through the MSS_I2C_set_slave_mem_offset_length() function. The function MSS_I2C_register_write_handler() can optionally be used to specify a handler function that is called on completion of the write phase of the I2C write-read transaction. If a handler function is registered, it is responsible for processing the received data in the slave receive buffer and populating the slave transmit buffer with the data that will be transmitted to the I2C master as part of the read phase of the write-read transaction. The function MSS_I2C_enable_slave() enables the MSS I2C hardware instance to respond to I2C transactions. It must be called after the MSS I2C driver has been configured to respond to the required transaction types. -------------------------------- Mixed Master and Slave Operations -------------------------------- The MSS I2C device supports mixed master and slave operations. If the MSS I2C slave has a transaction in progress and your application attempts to begin a master mode transaction, the MSS I2C driver queues the master mode transaction until the bus is released and the MSS I2C can switch to master mode and acquire the bus. The MSS I2C master then starts the previously pended transaction. -------------------------------- SMBus Interface Configuration and Control -------------------------------- The MSS I2C driver enables the MSS I2C peripherals SMBus functionality using the MSS_I2C_smbus_init() function. The MSS_I2C_suspend_smbus_slave() function is used, with a master mode MSS I2C, to force slave devices on the SMBus to enter their power-down/suspend mode. The MSS_I2C_resume_smbus_slave() function is used to end the suspend operation on the SMBus. The MSS_I2C_reset_smbus() function is used, with a master mode MSS I2C, to force all devices on the SMBus to reset their SMBUs interface. The MSS_I2C_set_smsbus_alert() function is used, by a slave mode MSS I2C, to force communication with the SMBus master. Once communications with the master is initiated, the MSS_I2C_clear_smsbus_alert() function is used to clear the alert condition. The MSS_I2C_enable_smbus_irq() and MSS_I2C_disable_smbus_irq() functions are used to enable and disable the SMBSUS and SMBALERT SMBus interrupts. *//*=========================================================================*/ #ifndef MSS_I2C_H_ #define MSS_I2C_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include "mss_plic.h" #include "mss_i2c_regs.h" #include "hal/hal.h" /*-------------------------------------------------------------------------*//** The mss_i2c_clock_divider_t type is used to specify the divider to be applied to the MSS I2C PCLK or BCLK signal in order to generate the I2C clock. The MSS_I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, all other values select a clock frequency based on division of PCLK. */ typedef enum mss_i2c_clock_divider { MSS_I2C_PCLK_DIV_256 = 0u, MSS_I2C_PCLK_DIV_224, MSS_I2C_PCLK_DIV_192, MSS_I2C_PCLK_DIV_160, MSS_I2C_PCLK_DIV_960, MSS_I2C_PCLK_DIV_120, MSS_I2C_PCLK_DIV_60, MSS_I2C_BCLK_DIV_8 } mss_i2c_clock_divider_t; /*-------------------------------------------------------------------------*//** The MSS_I2C_RELEASE_BUS constant is used to specify the options parameter to functions MSS_I2C_read(), MSS_I2C_write() and MSS_I2C_write_read() to indicate that a STOP bit must be generated at the end of the I2C transaction to release the bus. */ #define MSS_I2C_RELEASE_BUS 0x00u /*-------------------------------------------------------------------------*//** The MSS_I2C_HOLD_BUS constant is used to specify the options parameter to functions MSS_I2C_read(), MSS_I2C_write() and MSS_I2C_write_read() to indicate that a STOP bit must not be generated at the end of the I2C transaction in order to retain the bus ownership. This causes the next transaction to begin with a repeated START bit and no STOP bit between the transactions. */ #define MSS_I2C_HOLD_BUS 0x01u /*-------------------------------------------------------------------------*//** The MSS_I2C_SMBALERT_IRQ constant is used with the MSS_I2C_enable_smbus_irq() and MSS_I2C_disable_smbus_irq() functions to enable or disable the SMBus SMBALERT interrupt. */ #define MSS_I2C_SMBALERT_IRQ 0x01u /*-------------------------------------------------------------------------*//** The MSS_I2C_SMBSUS_IRQ constant is used with the MSS_I2C_enable_smbus_irq() and MSS_I2C_disable_smbus_irq() functions to enable or disable the SMBus SMBSUS interrupt. */ #define MSS_I2C_SMBSUS_IRQ 0x02u /*-------------------------------------------------------------------------*//** The MSS_I2C_NO_TIMEOUT constant is used to specify the timeout_ms parameter to the MSS_I2C_wait_complete() function to indicate that the function must not time out while waiting for the I2C transaction to complete. */ #define MSS_I2C_NO_TIMEOUT 0u /*-------------------------------------------------------------------------*//** The mss_i2c_status_t type is used to report the status of I2C transactions. */ typedef enum mss_i2c_status { MSS_I2C_SUCCESS = 0u, MSS_I2C_IN_PROGRESS, MSS_I2C_FAILED, MSS_I2C_TIMED_OUT } mss_i2c_status_t; /*-------------------------------------------------------------------------*//** The mss_i2c_slave_handler_ret_t type is used by slave write handler functions to indicate whether or not the received data buffer should be released. */ typedef enum mss_i2c_slave_handler_ret { MSS_I2C_REENABLE_SLAVE_RX = 0u, MSS_I2C_PAUSE_SLAVE_RX = 1u } mss_i2c_slave_handler_ret_t; typedef struct mss_i2c_instance mss_i2c_instance_t ; /*-------------------------------------------------------------------------*//** Transfer completion call back handler functions prototype. This defines the function prototype that must be followed by MSS I2C master and slave transfer completion handler functions. These functions are registered with the MSS I2C driver through the MSS_I2C_register_transfer_completion_handler() function. Declaring and Implementing transfer completion call back functions: Transfer complete call back function should follow the following prototype: void i2c0_completion_handler ( mss_i2c_instance_t *instance, mss_i2c_status_t status ) The instance parameter is a pointer to the mss_i2c_instance_t for which this transfer completion callback handler has been declared. The status parameter provides the status information of the current transfer completion such as transfer successful or any error occurred. } */ typedef void (*mss_i2c_transfer_completion_t)( mss_i2c_instance_t *instance, mss_i2c_status_t status); /*-------------------------------------------------------------------------*//** Slave write handler functions prototype. ------------------------------------------------------------------------------ This defines the function prototype that must be followed by MSS I2C slave write handler functions. These functions are registered with the MSS I2C driver through the MSS_I2C_register_write_handler() function. Declaring and Implementing Slave Write Handler Functions: Slave write handler functions should follow the following prototype: mss_i2c_slave_handler_ret_t write_handler ( mss_i2c_instance_t *instance, uint8_t * data, uint16_t size ); The instance parameter is a pointer to the mss_i2c_instance_t for which this slave write handler has been declared. The data parameter is a pointer to a buffer (received data buffer) holding the data written to the MSS I2C slave. Defining the macro MSS_I2C_INCLUDE_SLA_IN_RX_PAYLOAD causes the driver to insert the actual address used to access the slave as the first byte in the buffer. This allows applications tailor their response based on the actual address used to access the slave (primary address or GCA). The size parameter is the number of bytes held in the received data buffer. Handler functions must return one of the following values: MSS_I2C_REENABLE_SLAVE_RX MSS_I2C_PAUSE_SLAVE_RX. If the handler function returns MSS_I2C_REENABLE_SLAVE_RX, the driver releases the received data buffer and allows further I2C write transactions to the MSS I2C slave to take place. If the handler function returns MSS_I2C_PAUSE_SLAVE_RX, the MSS I2C slave responds to subsequent write requests with a non-acknowledge bit (NACK), until the received data buffer content has been processed by some other part of the software application. A call to MSS_I2C_enable_slave() is required at some point after returning MSS_I2C_PAUSE_SLAVE_RX in order to release the received data buffer so it can be used to store data received by subsequent I2C write transactions. */ typedef mss_i2c_slave_handler_ret_t (*mss_i2c_slave_wr_handler_t)( mss_i2c_instance_t *instance, uint8_t * data, uint16_t size); typedef struct { volatile uint8_t CTRL; uint8_t RESERVED0; uint16_t RESERVED1; uint8_t STATUS; uint8_t RESERVED2; uint16_t RESERVED3; volatile uint8_t DATA; uint8_t RESERVED4; uint16_t RESERVED5; volatile uint8_t ADDR; uint8_t RESERVED6; uint16_t RESERVED7; volatile uint8_t SMBUS; uint8_t RESERVED8; uint16_t RESERVED9; volatile uint8_t FREQ; uint8_t RESERVED10; uint16_t RESERVED11; volatile uint8_t GLITCHREG; uint8_t RESERVED12; uint16_t RESERVED13; volatile uint8_t SLAVE1_ADDR; uint8_t RESERVED14; uint16_t RESERVED15; } I2C_TypeDef; /*-------------------------------------------------------------------------*//** mss_i2c_instance_t ------------------------------------------------------------------------------ There is one instance of this structure for each of the MSS I2Cs. Instances of this structure are used to identify a specific MSS I2C. A pointer to an instance of the mss_i2c_instance_t structure is passed as the first parameter to MSS I2C driver functions to identify which MSS I2C should perform the requested operation. */ struct mss_i2c_instance { uint_fast8_t ser_address; /* Transmit related info:*/ uint_fast8_t target_addr; /* Current transaction type (WRITE, READ, RANDOM_READ)*/ uint8_t transaction; uint_fast16_t random_read_addr; uint8_t options; /* I2C hardware instance identification */ PLIC_IRQn_Type irqn; I2C_TypeDef * hw_reg; /* Master TX INFO: */ const uint8_t * master_tx_buffer; uint_fast16_t master_tx_size; uint_fast16_t master_tx_idx; uint_fast8_t dir; /* Master RX INFO: */ uint8_t * master_rx_buffer; uint_fast16_t master_rx_size; uint_fast16_t master_rx_idx; /* Master Status */ volatile mss_i2c_status_t master_status; uint32_t master_timeout_ms; /* Slave TX INFO */ const uint8_t * slave_tx_buffer; uint_fast16_t slave_tx_size; uint_fast16_t slave_tx_idx; /* Slave RX INFO */ uint8_t * slave_rx_buffer; uint_fast16_t slave_rx_size; uint_fast16_t slave_rx_idx; /* Slave Status */ volatile mss_i2c_status_t slave_status; /* Slave data: */ uint_fast8_t slave_mem_offset_length; mss_i2c_slave_wr_handler_t slave_write_handler; uint8_t is_slave_enabled; /* Transfer completion handler. */ mss_i2c_transfer_completion_t transfer_completion_handler; /* User specific data */ void *p_user_data ; /* I2C bus status */ uint8_t bus_status; /* Is transaction pending flag */ uint8_t is_transaction_pending; /* I2C Pending transaction */ uint8_t pending_transaction; }; /*-------------------------------------------------------------------------*//** This instance of mss_i2c_instance_t holds all data related to the operations performed by MSS I2C 0 connected on main APB bus. The MSS_I2C_init()function initializes this structure. A pointer to g_mss_i2c0_lo is passed as the first parameter to MSS I2C driver functions to indicate that MSS I2C 0 should perform the requested operation. */ extern mss_i2c_instance_t g_mss_i2c0_lo; /*-------------------------------------------------------------------------*//** This instance of mss_i2c_instance_t holds all data related to the operations performed by MSS I2C 1 connected on main APB bus. The MSS_I2C_init()function initializes this structure. A pointer to g_mss_i2c1_lo is passed as the first parameter to MSS I2C driver functions to indicate that MSS I2C 1 should perform the requested operation. */ extern mss_i2c_instance_t g_mss_i2c1_lo; /*-------------------------------------------------------------------------*//** This instance of mss_i2c_instance_t holds all data related to the operations performed by MSS I2C 0 connected on main APB bus. The MSS_I2C_init()function initializes this structure. A pointer to g_mss_i2c0_lo is passed as the first parameter to MSS I2C driver functions to indicate that MSS I2C 0 should perform the requested operation. */ extern mss_i2c_instance_t g_mss_i2c0_hi; /*-------------------------------------------------------------------------*//** This instance of mss_i2c_instance_t holds all data related to the operations performed by MSS I2C 1 connected on main APB bus. The MSS_I2C_init()function initializes this structure. A pointer to g_mss_i2c1_lo is passed as the first parameter to MSS I2C driver functions to indicate that MSS I2C 1 should perform the requested operation. */ extern mss_i2c_instance_t g_mss_i2c1_hi; /*-------------------------------------------------------------------------*//** MSS I2C initialization routine. ------------------------------------------------------------------------------ structures of one of the PolarFire SoC MSS I2Cs. ------------------------------------------------------------------------------ The MSS_I2C_init() function initializes and configures hardware and data structures of one of the PolarFire SoC MSS I2Cs. @param this_i2c The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param ser_address This parameter sets the I2C serial address for the MSS I2C peripheral being initialized. It is the I2C bus address to which the MSS I2C instance responds. MSS I2C peripherals can operate in master or slave mode and the serial address is significant only in the case of I2C slave mode. In master mode, MSS I2C does not require a serial address and the value of this parameter is not important. If you do not intend to use the I2C device in slave mode, then any dummy slave address value can be provided to this parameter. However, in systems where the MSS I2C may be expected to switch from master mode to slave mode, it is advisable to initialize the MSS I2C device with a valid serial slave address. You need to call the MSS_I2C_init() function whenever it is required to change the slave address as there is no separate function to set the slave address of an I2C device. @param ser_clock_speed This parameter sets the I2C serial clock frequency. It selects the divider that will be used to generate the serial clock from the APB PCLK or from the BCLK. It can be one of the following: MSS_I2C_PCLK_DIV_256 MSS_I2C_PCLK_DIV_224 MSS_I2C_PCLK_DIV_192 MSS_I2C_PCLK_DIV_160 MSS_I2C_PCLK_DIV_960 MSS_I2C_PCLK_DIV_120 MSS_I2C_PCLK_DIV_60 MSS_I2C_BCLK_DIV_8 Note: serial_clock_speed value is not critical for devices that only operate as slaves and can be set to any of the above values. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR_0 0x10u #define SLAVE_SER_ADDR_1 0x20u void system_init( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR_0, MSS_I2C_PCLK_DIV_256 ); MSS_I2C_init( &g_mss_i2c1_lo, SLAVE_SER_ADDR_1, MSS_I2C_PCLK_DIV_256 ); } @endcode */ void MSS_I2C_init ( mss_i2c_instance_t * this_i2c, uint8_t ser_address, mss_i2c_clock_divider_t ser_clock_speed ); /******************************************************************************* ******************************************************************************* * * Master specific functions * * The following functions are only used within an I2C master's implementation. */ /*-------------------------------------------------------------------------*//** I2C master write function. ------------------------------------------------------------------------------ This function initiates an I2C master write transaction. This function returns immediately after initiating the transaction. The content of the write buffer passed as parameter should not be modified until the write transaction completes. It also means that the memory allocated for the write buffer should not be freed or should not go out of scope before the write completes. You can check for the write transaction completion using the MSS_I2C_status() function. Additionally, driver will notify write transaction completion if callback function is registered. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param serial_addr: This parameter specifies the serial address of the target I2C device. @param write_buffer: This parameter is a pointer to a buffer holding the data to be written to the target I2C device. Care must be taken not to release the memory used by this buffer before the write transaction completes. For example, it is not appropriate to return from a function allocating this buffer as an auto array variable before the write transaction completes as this would result in the buffer's memory being de-allocated from the stack when the function returns. This memory could then be subsequently reused and modified causing unexpected data to be written to the target I2C device. @param write_size: Number of bytes held in the write_buffer to be written to the target I2C device. @param options: The options parameter is used to indicate if the I2C bus should be released on completion of the write transaction. Using the MSS_I2C_RELEASE_BUS constant for the options parameter causes a STOP bit to be generated at the end of the write transaction causing the bus to be released for other I2C devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter prevents a STOP bit from being generated at the end of the write transaction, preventing other I2C devices from initiating a bus transaction. @return This function does not return a value. Example: @code #define I2C_DUMMY_ADDR 0x10u #define DATA_LENGTH 16u uint8_t tx_buffer[DATA_LENGTH]; uint8_t write_length = DATA_LENGTH; void main( void ) { uint8_t target_slave_addr = 0x12; mss_i2c_status_t status; // Initialize MSS I2C peripheral MSS_I2C_init( &g_mss_i2c0_lo, I2C_DUMMY_ADDR, MSS_I2C_PCLK_DIV_256 ); // Write data to slave. MSS_I2C_write( &g_mss_i2c0_lo, target_slave_addr, tx_buffer, write_length, MSS_I2C_RELEASE_BUS ); // Wait for completion and record the outcome status = MSS_I2C_wait_complete( &g_mss_i2c0_lo, MSS_I2C_NO_TIMEOUT ); } @endcode */ void MSS_I2C_write ( mss_i2c_instance_t * this_i2c, uint8_t serial_addr, const uint8_t * write_buffer, uint16_t write_size, uint8_t options ); /*-------------------------------------------------------------------------*//** I2C master read. ------------------------------------------------------------------------------ This function initiates an I2C master read transaction. This function returns immediately after initiating the transaction. The content of the read buffer passed as the parameter should not be modified until the read transaction completes. It also means that the memory allocated for the read buffer should not be freed or should not go out of scope before the read completes. You can check for the read transaction completion using the MSS_I2C_status() function. Additionally, driver will notify read transaction completion, if callback function is registered. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver.. @param serial_addr: This parameter specifies the serial address of the target I2C device. @param read_buffer This is a pointer to a buffer where the data received from the target device will be stored. Care must be taken not to release the memory used by this buffer before the read transaction completes. For example, it is not appropriate to return from a function allocating this buffer as an auto array variable before the read transaction completes as this would result in the buffer's memory being de-allocated from the stack when the function returns. This memory could then be subsequently reallocated resulting in the read transaction corrupting the newly allocated memory. @param read_size: This parameter specifies the number of bytes to read from the target device. This size must not exceed the size of the read_buffer buffer. @param options: The options parameter is used to indicate if the I2C bus should be released on completion of the read transaction. Using the MSS_I2C_RELEASE_BUS constant for the options parameter causes a STOP bit to be generated at the end of the read transaction causing the bus to be released for other I2C devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter prevents a STOP bit from being generated at the end of the read transaction, preventing other I2C devices from initiating a bus transaction. @return This function does not return a value. Example: @code #define I2C_DUMMY_ADDR 0x10u #define DATA_LENGTH 16u uint8_t rx_buffer[DATA_LENGTH]; uint8_t read_length = DATA_LENGTH ; void main( void ) { uint8_t target_slave_addr = 0x12; mss_i2c_status_t status; // Initialize MSS I2C peripheral MSS_I2C_init( &g_mss_i2c0_lo, I2C_DUMMY_ADDR, MSS_I2C_PCLK_DIV_256 ); // Read data from target slave using MSS I2C 0. MSS_I2C_read( &g_mss_i2c0_lo, target_slave_addr, rx_buffer, read_length, MSS_I2C_RELEASE_BUS ); status = MSS_I2C_wait_complete( &g_mss_i2c0_lo, MSS_I2C_NO_TIMEOUT ); } @endcode */ void MSS_I2C_read ( mss_i2c_instance_t * this_i2c, uint8_t serial_addr, uint8_t * read_buffer, uint16_t read_size, uint8_t options ); /*-------------------------------------------------------------------------*//** I2C master write-read ------------------------------------------------------------------------------ This function initiates an I2C write-read transaction where data is first written to the target device before issuing a restart condition and changing the direction of the I2C transaction in order to read from the target device. The same warnings about buffer allocation in MSS_I2C_write() and MSS_I2C_read() apply to this function. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param serial_addr: This parameter specifies the serial address of the target I2C device. @param addr_offset: This parameter is a pointer to the buffer containing the data that will be sent to the slave during the write phase of the write-read transaction. This data is typically used to specify an address offset specifying to the I2C slave device what data it must return during the read phase of the write-read transaction. @param offset_size: This parameter specifies the number of offset bytes to be written during the write phase of the write-read transaction. This is typically the size of the buffer pointed to by the addr_offset parameter. @param read_buffer: This parameter is a pointer to the buffer where the data read from the I2C slave will be stored. @param read_size: This parameter specifies the number of bytes to read from the target I2C slave device. This size must not exceed the size of the buffer pointed to by the read_buffer parameter. @param options: The options parameter is used to indicate if the I2C bus should be released on completion of the write-read transaction. Using the MSS_I2C_RELEASE_BUS constant for the options parameter causes a STOP bit to be generated at the end of the write-read transaction causing the bus to be released for other I2C devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter prevents a STOP bit from being generated at the end of the write-read transaction, preventing other I2C devices from initiating a bus transaction. @return This function does not return a value. Example: @code #define I2C_DUMMY_ADDR 0x10u #define TX_LENGTH 16u #define RX_LENGTH 8u uint8_t rx_buffer[RX_LENGTH]; uint8_t read_length = RX_LENGTH; uint8_t tx_buffer[TX_LENGTH]; uint8_t write_length = TX_LENGTH; void main( void ) { uint8_t target_slave_addr = 0x12; mss_i2c_status_t status; // Initialize MSS I2C peripheral MSS_I2C_init( &g_mss_i2c0_lo, I2C_DUMMY_ADDR, MSS_I2C_PCLK_DIV_256 ); MSS_I2C_write_read( &g_mss_i2c0_lo, target_slave_addr, tx_buffer, write_length, rx_buffer, read_length, MSS_I2C_RELEASE_BUS ); status = MSS_I2C_wait_complete( &g_mss_i2c0_lo, MSS_I2C_NO_TIMEOUT ); } @endcode */ void MSS_I2C_write_read ( mss_i2c_instance_t * this_i2c, uint8_t serial_addr, const uint8_t * addr_offset, uint16_t offset_size, uint8_t * read_buffer, uint16_t read_size, uint8_t options ); /*-------------------------------------------------------------------------*//** I2C status ------------------------------------------------------------------------------ This function indicates the current state of an MSS I2C instance. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return The return value indicates the current state of a MSS I2C instance or the outcome of the previous transaction if no transaction is in progress. Possible return values are: MSS_I2C_SUCCESS The last I2C transaction has completed successfully. MSS_I2C_IN_PROGRESS There is an I2C transaction in progress. MSS_I2C_FAILED The last I2C transaction failed. MSS_I2C_TIMED_OUT The request has failed to complete in the allotted time. Example: @code while( MSS_I2C_IN_PROGRESS == MSS_I2C_get_status( &g_mss_i2c0_lo ) ) { // Do something useful while waiting for I2C operation to complete our_i2c_busy_task(); } if( MSS_I2C_SUCCESS != MSS_I2C_get_status( &g_mss_i2c0_lo ) ) { // Something went wrong... our_i2c_error_recovery( &g_mss_i2c0_lo ); } @endcode */ mss_i2c_status_t MSS_I2C_get_status ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** Wait for I2C transaction completion. ------------------------------------------------------------------------------ This function waits for the current I2C transaction to complete. The return value indicates whether the last I2C transaction was successful or not. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param timeout_ms: The timeout_ms parameter specifies the delay within which the current I2C transaction is expected to complete. The time out delay is given in milliseconds. MSS_I2C_wait_complete() will return MSS_I2C_TIMED_OUT if the current transaction does not complete before the time out delay expires. Alternatively, the timeout_ms parameter can be set to MSS_I2C_NO_TIMEOUT to indicate that the MSS_I2C_wait_complete() function must not time out. Note: If you set the timeout_ms parameter to a value other than MSS_I2C_NO_TIMEOUT, you must call the MSS_I2C_system_tick() function from an implementation of the SysTick timer interrupt service routine SysTick_Handler() in your application. Otherwise the time out will not take effect and the MSS_I2C_wait_complete() function will not time out. @return The return value indicates the outcome of the last I2C transaction. It can be one of the following: MSS_I2C_SUCCESS The last I2C transaction has completed successfully. MSS_I2C_FAILED The last I2C transaction failed. MSS_I2C_TIMED_OUT The last transaction failed to complete within the time out delay specified by the timeout_ms parameter. Example: @code #define I2C_DUMMY_ADDR 0x10u #define DATA_LENGTH 16u uint8_t rx_buffer[DATA_LENGTH]; uint8_t read_length = DATA_LENGTH; void main( void ) { uint8_t target_slave_addr = 0x12; mss_i2c_status_t status; // Initialize MSS I2C peripheral MSS_I2C_init( &g_mss_i2c0_lo, I2C_DUMMY_ADDR, MSS_I2C_PCLK_DIV_256 ); // Read data from slave. MSS_I2C_read( &g_mss_i2c0_lo, target_slave_addr, rx_buffer, read_length, MSS_I2C_RELEASE_BUS ); // Wait for completion and record the outcome status = MSS_I2C_wait_complete( &g_mss_i2c0_lo, MSS_I2C_NO_TIMEOUT ); } @endcode */ mss_i2c_status_t MSS_I2C_wait_complete ( mss_i2c_instance_t * this_i2c, uint32_t timeout_ms ); /*-------------------------------------------------------------------------*//** Time out delay expiration. ------------------------------------------------------------------------------ This function is used to control the expiration of the time out delay specified as a parameter to the MSS_I2C_wait_complete() function. It must be called from the interrupt service routine of a periodic interrupt source such as the SysTick timer interrupt. It takes the period of the interrupt source as its ms_since_last_tick parameter and uses it as the time base for the MSS_I2C_wait_complete() function's time out delay. Note: This function does not need to be called if the MSS_I2C_wait_complete() function is called with a timeout_ms value of MSS_I2C_NO_TIMEOUT. Note: If this function is not called then the MSS_I2C_wait_complete() function will behave as if its timeout_ms was specified as MSS_I2C_NO_TIMEOUT and it will not time out. Note: If this function is being called from an interrupt handler (e.g SysTick) it is important that the calling interrupt have a lower priority than the MSS I2C interrupt(s) to ensure any updates to shared data are protected. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param ms_since_last_tick: The ms_since_last_tick parameter specifies the number of milliseconds that elapsed since the last call to MSS_I2C_system_tick(). This parameter would typically be a constant specifying the interrupt rate of a timer used to generate system ticks. @return This function does not return a value. Example: The example below shows an example of how the MSS_I2C_system_tick() function would be called in a RISC-V based system. MSS_I2C_system_tick() is called for each MSS I2C peripheral from the RISC-V SysTick timer interrupt service routine. The SysTick is configured to generate an interrupt every 10 milliseconds in the example below. @code #define SYSTICK_INTERVAL_MS 10 void SysTick_Handler(void) { MSS_I2C_system_tick(&g_mss_i2c0_lo, SYSTICK_INTERVAL_MS); MSS_I2C_system_tick(&g_mss_i2c1_lo, SYSTICK_INTERVAL_MS); } @endcode */ void MSS_I2C_system_tick ( mss_i2c_instance_t * this_i2c, uint32_t ms_since_last_tick ); /******************************************************************************* ******************************************************************************* * * Slave specific functions * * The following functions are only used within the implementation of an I2C * slave device. */ /*-------------------------------------------------------------------------*//** I2C slave transmit buffer configuration. ------------------------------------------------------------------------------ This function specifies the memory buffer holding the data that will be sent to the I2C master when this MSS I2C instance is the target of an I2C read or write-read transaction. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param tx_buffer: This parameter is a pointer to the memory buffer holding the data to be returned to the I2C master when this MSS I2C instance is the target of an I2C read or write-read transaction. @param tx_size: Size of the transmit buffer pointed to by the tx_buffer parameter. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u #define SLAVE_TX_BUFFER_SIZE 10u uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; void main( void ) { // Initialize the MSS I2C driver with its I2C serial address and serial // clock divider. MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Specify the transmit buffer containing the data that will be // returned to the master during read and write-read transactions. MSS_I2C_set_slave_tx_buffer( &g_mss_i2c0_lo, g_slave_tx_buffer, sizeof(g_slave_tx_buffer) ); } @endcode */ void MSS_I2C_set_slave_tx_buffer ( mss_i2c_instance_t * this_i2c, const uint8_t * tx_buffer, uint16_t tx_size ); /*-------------------------------------------------------------------------*//** I2C slave receive buffer configuration. ------------------------------------------------------------------------------ This function specifies the memory buffer that will be used by the MSS I2C instance to receive data when it is a slave. This buffer is the memory where data will be stored when the MSS I2C is the target of an I2C master write transaction (i.e. when it is the slave). ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param rx_buffer: This parameter is a pointer to the memory buffer allocated by the caller software to be used as a slave receive buffer. @param rx_size: Size of the slave receive buffer. This is the amount of memory that is allocated to the buffer pointed to by rx_buffer. Note: This buffer size indirectly specifies the maximum I2C write transaction length this MSS I2C instance can be the target of. This is because this MSS I2C instance responds to further received bytes with a non-acknowledge bit (NACK) as soon as its receive buffer is full. This causes the write transaction to fail. @return none. Example: @code #define SLAVE_SER_ADDR 0x10u #define SLAVE_RX_BUFFER_SIZE 10u uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; void main( void ) { // Initialize the MSS I2C driver with its I2C serial address and // serial clock divider. MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Specify the buffer used to store the data written by the I2C master. MSS_I2C_set_slave_rx_buffer( &g_mss_i2c0_lo, g_slave_rx_buffer, sizeof(g_slave_rx_buffer) ); } @endcode */ void MSS_I2C_set_slave_rx_buffer ( mss_i2c_instance_t * this_i2c, uint8_t * rx_buffer, uint16_t rx_size ); /*-------------------------------------------------------------------------*//** I2C slave memory offset length configuration. ------------------------------------------------------------------------------ This function is used as part of the configuration of an MSS I2C instance for operation as a slave supporting write-read transactions. It specifies the number of bytes expected as part of the write phase of a write-read transaction. The bytes received during the write phase of a write-read transaction are interpreted as an offset into the slave's transmit buffer. This allows random access into the I2C slave transmit buffer from a remote I2C master. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param offset_length: The offset_length parameter configures the number of bytes to be interpreted by the MSS I2C slave as a memory offset value during the write phase of write-read transactions. The maximum value for the offset_length parameter is two. The value of offset_length has the following effect on the interpretation of the received data. If offset_length is 0, the offset into the transmit buffer is fixed at 0. If offset_length is 1, a single byte of received data is interpreted as an unsigned 8 bit offset value in the range 0 to 255. If offset_length is 2, 2 bytes of received data are interpreted as an unsigned 16 bit offset value in the range 0 to 65535. The first byte received in this case provides the high order bits of the offset and the second byte provides the low order bits. If the number of bytes received does not match the non 0 value of offset_length the transmit buffer offset is set to 0. @return none. Example: @code #define SLAVE_SER_ADDR 0x10u #define SLAVE_TX_BUFFER_SIZE 10u uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; void main( void ) { // Initialize the MSS I2C driver with its I2C serial address and serial // clock divider. MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); MSS_I2C_set_slave_tx_buffer( &g_mss_i2c0_lo, g_slave_tx_buffer, sizeof(g_slave_tx_buffer) ); MSS_I2C_set_slave_mem_offset_length( &g_mss_i2c0_lo, 1 ); } @endcode */ void MSS_I2C_set_slave_mem_offset_length ( mss_i2c_instance_t * this_i2c, uint8_t offset_length ); /*-------------------------------------------------------------------------*//** I2C write handler registration. ------------------------------------------------------------------------------ Register the function that is called to process the data written to this MSS I2C instance when it is the slave in an I2C write transaction. Note: If a write handler is registered, it is called on completion of the write phase of a write-read transaction and responsible for processing the received data in the slave receive buffer and populating the slave transmit buffer with the data that will be transmitted to the I2C master as part of the read phase of the write-read transaction. If a write handler is not registered, the write data of a write read transaction is interpreted as an offset into the slaves transmit buffer and handled by the driver. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param handler: Pointer to the function that will process the I2C write request. @return none. Example: @code #define SLAVE_SER_ADDR 0x10u #define SLAVE_TX_BUFFER_SIZE 10u uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; local function prototype void slave_write_handler ( mss_i2c_instance_t * this_i2c, uint8_t * p_rx_data, uint16_t rx_size ); void main( void ) { // Initialize the MSS I2C driver with its I2C serial address and serial // clock divider. MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); MSS_I2C_set_slave_tx_buffer( &g_mss_i2c0_lo, g_slave_tx_buffer, sizeof(g_slave_tx_buffer) ); MSS_I2C_set_slave_mem_offset_length( &g_mss_i2c0_lo, 1 ); MSS_I2C_register_write_handler( &g_mss_i2c0_lo, slave_write_handler ); } @endcode */ void MSS_I2C_register_write_handler ( mss_i2c_instance_t * this_i2c, mss_i2c_slave_wr_handler_t handler ); /*-------------------------------------------------------------------------*//** I2C slave enable. ------------------------------------------------------------------------------ This function enables slave mode operation for an MSS I2C peripheral. It enables the MSS I2C slave to receive data when it is the target of an I2C read, write or write-read transaction. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return none. Example: @code // Enable I2C slave. MSS_I2C_enable_slave( &g_mss_i2c0_lo ); @endcode */ void MSS_I2C_enable_slave ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** I2C slave disable. ------------------------------------------------------------------------------ This function disables slave mode operation for an MSS I2C peripheral. It stops the MSS I2C slave acknowledging I2C read, write or write-read transactions targeted at it. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code // Disable I2C slave. MSS_I2C_disable_slave( &g_mss_i2c0_lo ); @endcode */ void MSS_I2C_disable_slave ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_set_gca() function is used to set the general call acknowledgment bit of an MSS I2C slave device. This allows the slave device respond to a general call or broadcast message from an I2C master. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code // Enable recognition of the General Call Address MSS_I2C_set_gca( &g_mss_i2c0_lo ); @endcode */ void MSS_I2C_set_gca ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_clear_gca() function is used to clear the general call acknowledgment bit of an MSS I2C slave device. This will stop the I2C slave device responding to any general call or broadcast message from the master. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code // Disable recognition of the General Call Address MSS_I2C_clear_gca( &g_mss_i2c0_lo ); @endcode */ void MSS_I2C_clear_gca ( mss_i2c_instance_t * this_i2c ); /*------------------------------------------------------------------------------ I2C SMBUS specific APIs ----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_I2C_smbus_init() function enables SMBus timeouts and status logic. Set the frequency parameter to the MSS I2Cs PCLK frequency for 25ms SMBus timeouts, or to any frequency between 1 MHz and 255 MHz for to adjust the timeout. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param frequency The frequency parameter specifies a frequency in MHz from 1 to 255. It can be the MSS I2Cs PCLK frequency to specify 25ms SMBus timeouts, or a higher or lower frequency than the PCLK for increased or decreased timeouts. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void system_init( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); } @endcode */ void MSS_I2C_smbus_init ( mss_i2c_instance_t * this_i2c, uint8_t frequency ); /*-------------------------------------------------------------------------*//** The MSS_I2C_enable_smbus_irq() function is used to enable the MSS I2Cs SMBSUS and SMBALERT SMBus interrupts. If this function is used to enable an MSS I2C SMBus interrupt source, the appropriate interrupt handler must be implemented in the application to override the weak stub function implemented in the CMSIS-HAL startup code: - MSS I2C 0 SMBALERT - I2C0_SMBAlert_IRQHandler( ). - MSS I2C 0 SMBSUS - I2C0_SMBust_IRQHandler( ). - MSS I2C 1 SMBALERT - I2C1_SMBAlert_IRQHandler( ). - MSS I2C 1 SMBSUS - I2C1_SMBus_IRQHandler( ). ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param irq_type The irq_type parameter specifies which SMBus interrupt(s) to enable. The two possible interrupts are: MSS_I2C_SMBALERT_IRQ MSS_I2C_SMBSUS_IRQ To enable both ints in one call, use MSS_I2C_SMBALERT_IRQ | MSS_I2C_SMBSUS_IRQ. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void I2C0_SMBAlert_IRQHandler( void ) { // MSS I2C 0 application specific SMBALERT code goes here ... } void I2C0_SMBus_IRQHandler( void ) { // MSS I2C 0 application specific SMBus code goes here ... } void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // Enable both SMBALERT & SMBSUS interrupts MSS_I2C_enable_smbus_irq( &g_mss_i2c0_lo, (uint8_t)(MSS_I2C_SMBALERT_IRQ | MSS_I2C_SMBSUS_IRQ)); } @endcode */ void MSS_I2C_enable_smbus_irq ( mss_i2c_instance_t * this_i2c, uint8_t irq_type ); /*-------------------------------------------------------------------------*//** The MSS_I2C_disable_smbus_irq() function is used to disable the MSS I2C's SMBSUS and SMBALERT SMBus interrupts. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param irq_type The irq_type parameter specifies the SMBUS interrupt to be disabled. The two possible interrupts are: MSS_I2C_SMBALERT_IRQ MSS_I2C_SMBSUS_IRQ To disable both interrupts in one call, use MSS_I2C_SMBALERT_IRQ | MSS_I2C_SMBSUS_IRQ. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void I2C0_SMBAlert_IRQHandler( void ) { // MSS I2C 0 application specific SMBALERT code goes here ... } void I2C0_SMBus_IRQHandler( void ) { // MSS I2C 0 application specific SMBus code goes here ... } void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // Enable both SMBALERT & SMBSUS interrupts MSS_I2C_enable_smbus_irq( &g_mss_i2c0_lo, (uint8_t)(MSS_I2C_SMBALERT_IRQ | MSS_I2C_SMBSUS_IRQ)); ... // Disable the SMBALERT interrupt MSS_I2C_disable_smbus_irq( &g_mss_i2c0_lo, MSS_I2C_SMBALERT_IRQ ); } @endcode */ void MSS_I2C_disable_smbus_irq ( mss_i2c_instance_t * this_i2c, uint8_t irq_type ); /*-------------------------------------------------------------------------*//** The MSS_I2C_suspend_smbus_slave() function forces any SMBUS slave devices connected to an MSS I2C peripheral into power down or suspend mode by asserting the MSS I2Cs I2C_X_SMBSUS_NO output signal. The MSS I2C is the SMBus master in this case. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // suspend SMBus slaves MSS_I2C_suspend_smbus_slave( &g_mss_i2c0_lo ); ... // Re-enable SMBus slaves MSS_I2C_resume_smbus_slave( &g_mss_i2c0_lo ); } @endcode */ void MSS_I2C_suspend_smbus_slave ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_resume_smbus_slave() function de-asserts the MSS I2C's I2C_X_SMBSUS_NO output signal to take any connected slave devices out of suspend mode. The MSS I2C is the SMBus master in this case. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // suspend SMBus slaves MSS_I2C_suspend_smbus_slave( &g_mss_i2c0_lo ); ... // Re-enable SMBus slaves MSS_I2C_resume_smbus_slave( &g_mss_i2c0_lo ); } @endcode */ void MSS_I2C_resume_smbus_slave ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_reset_smbus() function resets the MSS I2C's SMBus connection by forcing SCLK low for 35mS. The reset is automatically cleared after 35ms have elapsed. The MSS I2C is the SMBus master in this case. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // Make sure the SMBus channel is in a known state by resetting it MSS_I2C_reset_smbus( &g_mss_i2c0_lo ); } @endcode */ void MSS_I2C_reset_smbus ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_set_smbus_alert() function is used to force master communication with an I2C slave device by asserting the MSS I2C's I2C_X_SMBALERT_NO signal. The MSS I2C is the SMBus master in this case. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // Get the SMBus masters attention MSS_I2C_set_smbus_alert( &g_mss_i2c0_lo ); ... // Once we are happy, drop the alert MSS_I2C_clear_smbus_alert( &g_mss_i2c0_lo ); } @endcode */ void MSS_I2C_set_smbus_alert ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_clear_smbus_alert() function is used de-assert the MSS I2Cs I2C_X_SMBALERT_NO signal once a slave device has had a response from the master. The MSS I2C is the SMBus slave in this case. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function does not return a value. Example: @code #define SLAVE_SER_ADDR 0x10u void main( void ) { MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Initialize SMBus feature MSS_I2C_smbus_init( &g_mss_i2c0_lo, 100 ); // Get the SMBus masters attention MSS_I2C_set_smbus_alert( &g_mss_i2c0_lo ); ... // Once we are happy, drop the alert MSS_I2C_clear_smbus_alert( &g_mss_i2c0_lo ); } @endcode */ void MSS_I2C_clear_smbus_alert ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_set_user_data() function is used to allow the association of a block of application specific data with an MDD I2C peripheral. The composition of the data block is an application matter and the driver simply provides the means for the application to set and retrieve the pointer. This may for example be used to provide additional channel specific information to the slave write handler. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param p_user_data The p_user_data parameter is a pointer to the user specific data block for this MSS I2C peripheral. It is defined as void * as the driver does not know the actual type of data being pointed to and simply stores the pointer for later retrieval by the application. @return This function does not return a value. Example @code #define SLAVE_SER_ADDR 0x10u app_data_t channel_xdata; void main( void ) { app_data_t *p_xdata; MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Store location of user data in instance structure MSS_I2C_set_user_data( &g_mss_i2c0_lo, (void *)&channel_xdata ); ... // Retrieve location of user data and do some work on it p_xdata = (app_data_t *)MSS_I2C_get_user_data( &g_mss_i2c0_lo ); if( NULL != p_xdata ) { p_xdata->foo = 123; } } @endcode */ void MSS_I2C_set_user_data ( mss_i2c_instance_t * this_i2c, void * p_user_data ); /*-------------------------------------------------------------------------*//** The MSS_I2C_get_user_data() function is used to allow the retrieval of the address of a block of application specific data associated with an MSS I2C peripheral. The composition of the data block is an application matter and the driver simply provides the means for the application to set and retrieve the pointer. This may for example be used to provide additional channel specific information to the slave write handler. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @return This function returns a pointer to the user specific data block for this MSS I2C peripheral. It is defined as void * as the driver does not know the actual type of data being pointed to. If no user data has been registered for this channel a NULL pointer is returned. Example @code #define SLAVE_SER_ADDR 0x10u app_data_t channel_xdata; void main( void ) { app_data_t *p_xdata; MSS_I2C_init( &g_mss_i2c0_lo, SLAVE_SER_ADDR, MSS_I2C_PCLK_DIV_256 ); // Store location of user data in instance structure MSS_I2C_set_user_data( &g_mss_i2c0_lo, (void *)&channel_xdata ); ... // Retrieve location of user data and do some work on it p_xdata = (app_data_t *)MSS_I2C_get_user_data( &g_mss_i2c0_lo ); if( NULL != p_xdata ) { p_xdata->foo = 123; } } @endcode */ void * MSS_I2C_get_user_data ( mss_i2c_instance_t * this_i2c ); /*-------------------------------------------------------------------------*//** The MSS_I2C_register_transfer_completion_handler() function is used register transfer completion call back function. This mechanism is used to notify the completion of the previously initiated I2C transfer when MSS I2C instance is operating as I2C Master. This call back function will be called when the transfer is completed. It will also inform the transfer status as a parameter of the completion handler function. This function must be called after I2C initialization and before starting any transmit or receive operations. ------------------------------------------------------------------------------ @param this_i2c: The this_i2c parameter is a pointer to an mss_i2c_instance_t structure identifying the MSS I2C hardware block to be initialized. There are four such data structures, g_mss_i2c0_lo and g_mss_i2c1_lo, associated with MSS I2C 0 and MSS I2C 1 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_i2c0_hi and g_mss_i2c1_hi, associated with MSS I2C 0 to MSS I2C 1 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these four global data structure defined within I2C driver. @param completion_handler: The completion_handler parameter pointers to the function that informs to application previously initiated I2C transfer is completed along with transfer status. @return This function does not return a value. Example @code void i2c0_completion_handler(mss_i2c_instance_t * instance, mss_i2c_status_t status) { if (status == MSS_I2C_SUCCESS) { MSS_UART_polled_tx_string(gp_my_uart, (const uint8_t*)"\rI2C0 Transfer completed.\n\r"); } } void main() { MSS_I2C_init(I2C_MASTER, MASTER_SER_ADDR, MSS_I2C_BCLK_DIV_8); MSS_I2C_register_transfer_completion_handler(I2C_MASTER, i2c0_completion_handler); } @endcode */ void MSS_I2C_register_transfer_completion_handler ( mss_i2c_instance_t * this_i2c, mss_i2c_transfer_completion_t completion_handler ); #ifdef __cplusplus } #endif #endif /*MSS_I2C_H_*/ mss_i2c_regs.h000066400000000000000000000045161432224323300373500ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_i2c/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC(PSE) MSS I2C. * * SVN $Revision$ * SVN $Date$ */ #ifndef MSS_I2C_REGS_H_ #define MSS_I2C_REGS_H_ #ifdef __cplusplus extern "C" { #endif /******************************************************************************* Register Bit definitions */ #define CR0 (uint8_t)0u #define CR1 (uint8_t)1u #define AA (uint8_t)2u #define SI (uint8_t)3u #define STO (uint8_t)4u #define STA (uint8_t)5u #define ENS1 (uint8_t)6u #define CR2 (uint8_t)7u #define CR0_MASK (uint8_t)(0x01) #define CR1_MASK (uint8_t)(0x02) #define AA_MASK (uint8_t)(0x04) #define SI_MASK (uint8_t)(0x08) #define STO_MASK (uint8_t)(0x10) #define STA_MASK (uint8_t)(0x20) #define ENS1_MASK (uint8_t)(0x40) #define CR2_MASK (uint8_t)(0x80) #define DATA_DIR (uint8_t)0u #define DATA_DIR_MASK (uint8_t)(0x01) #define ADDR_GC (uint8_t)0u #define ADDR_GC_MASK (uint8_t)0x01 #define SMBALERT_IE (uint8_t)0u #define SMBSUS_IE (uint8_t)1u #define SMB_IPMI_EN (uint8_t)2u #define SMBALERT_NI (uint8_t)3u #define SMBALERT_NO (uint8_t)4u #define SMBSUS_NI (uint8_t)5u #define SMBSUS_NO (uint8_t)6u #define SMBUS_RESET (uint8_t)7u #define SMBALERT_IE_MASK (uint8_t)(0x01) #define SMBSUS_IE_MASK (uint8_t)(0x02) #define SMB_IPMI_EN_MASK (0x01 << SMB_IPMI_EN) #define SMBALERT_NI_MASK (0x01 << SMBALERT_NI) #define SMBALERT_NO_MASK (uint8_t)(0x10) #define SMBSUS_NI_MASK (0x01 << SMBSUS_NI) #define SMBSUS_NO_MASK (uint8_t)(0x40) #define SMBUS_RESET_MASK (uint8_t)(0x80) #ifdef __cplusplus } #endif #endif /* MSS_I2C_REGS_H_ */ mss_mmc/000077500000000000000000000000001432224323300347115ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_mmc.c000066400000000000000000003663121432224323300365260ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS eMMC SD bare metal driver implementation. * * ICICLE KIT test - v7 * */ #include "mss_hal.h" #include "mss_mmc_if.h" #include "mss_mmc_regs.h" #include "mss_mmc_types.h" #include "mss_mmc.h" #ifdef MSS_MMC_INTERNAL_APIS #include "mss_mmc_internal_api.h" #endif #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * Macros */ #define WORD_SIZE 4u #define BYTE_MASK 0xFFu #define BLK_SIZE 512u #define BLOCK_COUNT_ENABLE_SHIFT 16u #define BUFF_EMPTY 0u #define RCA_VALUE 0x0001u #define STUFF_BITS 0x0u #define BUSY_BIT_MASK 0x80000000u #define SECT_SIZE_CSD_MASK 0x03C000u #define SECT_SIZE_CSD_SHIFT 14u #define SECTOR_ACCESS_MODE_MASK 0x60000000u #define SECTOR_SHIFT 29u #define RESET_ARG 0x00000000u #define MMC_DW_CSD 0x03B70000u #define MMC_LEGACY_MODE 0x03B90000u #define MMC_HS_MODE 0x03B90100u #define MMC_HS200_MODE 0x03B90200u #define MMC_HS400_MODE 0x03B90300u #define MMC_HS_MODE_DEFAULT 0x03B90000u #define MMC_HPI_ENABLE 0x03A10100u #define MMC_CQ_ENABLE 0x030F0100u #define CQ_IDLE_TIME 0x1000u #define MMC_DEVICE_LOW_POWER 0x80u #define MMC_DEVICE_LOW_VOLT_SET 0x40000080u #define MMC_DEVICE_3_3V_VOLT_SET 0x40300000u #define MMC_CLEAR 0x0u #define MMC_SET 0x1u #define MMC_STATUS_CLEAR 0xFFFFFFFFu #define MMC_64BIT_UPPER_ADDR_SHIFT 32u #define MMC_SRS03_COMMAND_SHIFT 24u #define DELAY_COUNT 0xFFFFu #define DATA_TIMEOUT_VALUE 500000u #define HRS0_SOFTWARE_RESET 0x00000001u #define MMC_SOFTWARE_RESET_SHIFT 0x3u #define DEBOUNCING_TIME 0x300000u #define MMC_RESET_DATA_CMD_LINE 0x06000000u /* SDMA boundary is 512k */ #define SIZE_32MB 0x02000000u #define SIZE_64KB 0x00010000u #define SIZE_1GB 0x40000000u #define EXT_CSD_SECTOR_COUNT_OFFSET 212u #define EXT_CSD_CARD_TYPE_OFFSET 196u #define EXT_CSD_REVISION_OFFSET 192u #define EXT_CSD_HS_TIMING_OFFSET 185u #define EXT_CSD_ES_SUPPORT_OFFSET 184u #define EXT_CSD_CQ_SUPPORT_OFFSET 308u /* CMD Queuing Depth */ #define EXT_CSD_CQ_DEPTH_OFFSET 307u #define EXT_CSD_CQ_MODE_EN_OFFSET 15u #define READ_SEND_SCR 0xFFFFFFFEu #define SCR_REG_DATA_SIZE 8u #define IF_COND_27V_33V (1u << 8u) #define RCA_SHIFT_BIT 16u #define SIZE_4KB 4096u #define COMMANDS_TIMEOUT 3000u /* HS200/400 1.8v support */ #define DEVICE_SUPPORT_HS400 0x40u #define DEVICE_SUPPORT_HS200 0x10u #define DEVICE_SUPPORT_DDR 0x04u #define DEVICE_SUPPORT_SDR 0x03u #define DEVICE_SUPPORT_SDR_50MHZ 0x02u #define DEVICE_SUPPORT_SDR_25MHZ 0x01u #define DEVICE_SUPPORT_LEGACY 0x00u #define DEVICE_STATE_MASK 0xF00u #define DEVICE_STATE_TRANS 0x900u #define MMC_ES_DUAL_DATA_WIDTH_8BIT 0x86u #define MMC_DUAL_DATA_WIDTH_8BIT 0x6u #define MMC_DUAL_DATA_WIDTH_4BIT 0x5u #define MAX_CURRENT_MA 150u #define SHIFT_2BIT 0x2u #define SHIFT_4BIT 0x4u #define SHIFT_8BIT 0x8u #define SHIFT_9BIT 9u #define SHIFT_16BIT 16u #define SHIFT_24BIT 24u #define SHIFT_27BIT 27u #define SHIFT_28BIT 28u #define SHIFT_30BIT 30u #define SHIFT_31BIT 31u #define SHIFT_32BIT 32u #define MASK_32BIT 0xFFFFFFFFu #define MASK_24BIT 0xFFFFFFu #define MASK_16BIT 0xFFFFu #define MASK_12BIT 0xFFFu #define MASK_8BIT 0xFFu #define MASK_4BIT 0xFu #define BYTES_128 128u #define BYTES_64 64u #define BYTES_40 40u #define BYTES_20 20u #define BYTES_7 7u #define BYTES_6 6u #define BYTES_5 5u #define BYTES_4 4u #define BYTES_3 3u #define BYTES_2 2u #define BYTES_1 1u #define BYTE_3_MASK 0xFF0000u #define CQ_TDLBA_ALIGN_MASK ((1u << 10u) - 1u) #define CARD_INT_STATUS_MASK 0xFEu #define SDCARD_BUSWIDTH_MASK 0xFCu #define DEVICE_HPI_SUPPORT 0x01u #define HPI_WITH_CMD12_SUPPORT 0x02u /* Number outside of normal range- used to tell read block routine to read extended CSD register */ #define READ_SEND_EXT_CSD 0xFFFFFFFFu /* Number of temporary sub-buffers, used by to split data bigger than 64KB for smaller parts. Split is made by ADMA module. */ #define SDIO_CFG_SDIO_BUFFERS_COUNT 0x4000u #define NULL_POINTER ((void *)0u) /******************************************************************************* * Global variable file scope */ /* Relative card address (eMMC/SD) */ static uint32_t sdcard_RCA; static uint8_t g_mmc_init_complete; static uint8_t g_mmc_is_multi_blk = MMC_CLEAR; static uint8_t g_device_hpi_suport; static uint32_t g_hw_sec_count; static uint16_t g_sector_size; #ifdef MSS_MMC_INTERNAL_APIS static uint8_t g_device_hpi_set = MMC_CLEAR; static uint32_t g_trans_remain_size = MMC_CLEAR; static uint8_t * g_trans_src_addr = MMC_CLEAR; static uint32_t g_trans_dest_addr = MMC_CLEAR; #endif /* MSS_MMC_INTERNAL_APIS */ static uint8_t g_cq_task_id = MMC_CLEAR; /******************************************************************************/ struct mmc_trans { volatile mss_mmc_status_t state; }; static struct mmc_trans g_mmc_trs_status; /******************************************************************************/ struct phydelayaddresses { uint8_t address; MSS_MMC_phydelay phydelaytype; }; /******************************************************************************* * Private functions */ static mss_mmc_status_t mmccard_oper_config(const mss_mmc_cfg_t * cfg); static mss_mmc_status_t sdcard_oper_config(const mss_mmc_cfg_t * cfg); static uint8_t set_host_sdclk(uint32_t frequencyKHz); static mss_mmc_status_t set_data_timeout(uint32_t timeout_val_us); static mss_mmc_status_t set_sdhost_power(uint32_t voltage); static void get_phy_addr(MSS_MMC_phydelay phydelaytype, uint8_t *phySetAddr); static mss_mmc_status_t phy_training_mmc(uint8_t delay_type, uint32_t clk_rate); static void phy_write_set(uint8_t delay_type, uint8_t delay_value); static mss_mmc_status_t device_set_hs_timing ( uint32_t hs_mode, const mss_mmc_cfg_t * cfg ); static mss_mmc_status_t set_device_hs400_mode(const mss_mmc_cfg_t *cfg); static void mmc_delay(uint32_t value); static uint8_t is_uhsi_supported(void); static mss_mmc_status_t cmd6_single_block_read ( uint32_t src_addr, uint32_t * dst_addr, uint32_t size ); static mss_mmc_status_t set_sd_host_device_bus_mode(const mss_mmc_cfg_t * cfg); static mss_mmc_status_t set_host_uhsi_mode ( uint8_t access_mode, uint8_t driver_strengh ); static mss_mmc_status_t sd_host_process_switch_function ( uint8_t function_num, uint8_t group_num ); static mss_mmc_status_t sd_host_exec_cmd6_command ( uint32_t argument, uint8_t *buffer, uint8_t function_num, uint8_t group_num ); static mss_mmc_status_t sd_card_uhsi_supported(void); static const uint32_t* calc_write_pattern(const uint8_t bus_width); static void host_mmc_tune(uint8_t value); static mss_mmc_status_t sd_tuning(void); static uint8_t calc_longest_valid_delay_chain_val(const uint8_t* pattern_ok); static mss_mmc_status_t read_tune_block ( uint32_t *read_data, uint32_t size, uint8_t cmd ); static mss_mmc_status_t execute_tunning_mmc(uint8_t data_width); static cif_response_t check_device_status(cif_response_t rsp_status); static uint32_t get_srs_bits(int from, int count); static mss_mmc_handler_t g_transfer_complete_handler_t; /*****************************************************************************/ /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ mss_mmc_status_t MSS_MMC_init(const mss_mmc_cfg_t * cfg) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; cif_response_t response_status; uint32_t reg, cap, srs10, hrs6; uint32_t csd_reg[BLK_SIZE/WORD_SIZE]; uint8_t *pcsd_reg = NULL_POINTER; uint8_t hw_ext_csd_rev; uint8_t hw_device_type; uint8_t hw_strobe_suport; uint8_t hw_hs_timing; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); /* Reset MMC */ SYSREG->SOFT_RESET_CR &= ~(MMC_SET << MMC_SOFTWARE_RESET_SHIFT); /* Disable MMC interrupt */ PLIC_DisableIRQ(MMC_main_PLIC); g_transfer_complete_handler_t = NULL_POINTER; g_mmc_init_complete = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_NOT_INITIALISED; /* Set RCA default value */ sdcard_RCA = RCA_VALUE; /* Reset host controller*/ MMC->HRS00 |= HRS0_SOFTWARE_RESET; mmc_delay(DELAY_COUNT); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { reg = MMC->HRS00; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((reg & HRS0_SOFTWARE_RESET) != MMC_CLEAR); /* Set de-bounce time */ MMC->HRS01 = DEBOUNCING_TIME; /* eMMC Mode select in Host controller */ hrs6 = MMC->HRS06; hrs6 &= ~MSS_MMC_MODE_MASK; /* Check card type SD or MMC */ if (MSS_MMC_CARD_TYPE_MMC == cfg->card_type) { hrs6 |= MSS_MMC_MODE_LEGACY; } else { hrs6 |= MSS_MMC_MODE_SDCARD; } MMC->HRS06 = hrs6; /* Clear error/interrupt status */ MMC->SRS12 = MMC_STATUS_CLEAR; reg = MMC->SRS15; cap = MMC->SRS16; /* Check DMA 64 bit support */ if ((cap & SRS16_64BIT_SUPPORT) != MMC_CLEAR) { reg |= SRS15_64_BIT_ADDRESSING; reg |= SRS15_HOST_4_ENABLE; MMC->SRS15 = reg; } /* Enable error/interrupt status */ MMC->SRS13 = SRS13_STATUS_EN; /* Disable error/interrupt */ MMC->SRS14 = MMC_CLEAR; /* Set 500ms data timeout */ ret_status = set_data_timeout(DATA_TIMEOUT_VALUE); if (MSS_MMC_NO_ERROR != ret_status) { ret_status = MSS_MMC_NOT_INITIALISED; } /* Turn-off Host Controller Power */ ret_status = set_sdhost_power(MMC_CLEAR); if (MSS_MMC_NO_ERROR != ret_status) { ret_status = MSS_MMC_NOT_INITIALISED; } reg = MMC->SRS09; /* If card stable is not set it means that something is wrong */ if (((reg & SRS9_CARD_STATE_STABLE) == MMC_CLEAR) && (MSS_MMC_NO_ERROR == ret_status)) { ret_status = MSS_MMC_CARD_STATE_STABLE_ERR; } /* if card is not inserted to SD socked */ if (MSS_MMC_CARD_TYPE_SD == cfg->card_type) { if (((reg & SRS9_CARD_INSERTED) == MMC_CLEAR) && (MSS_MMC_NO_ERROR == ret_status)) { ret_status = MSS_MMC_CARD_INSERTED_ERR; } } /* Set 1-bit bus mode */ srs10 = MMC->SRS10; srs10 &= ~SRS10_DATA_WIDTH_4BIT; srs10 &= ~SRS10_EXTENDED_DATA_TRANSFER_WIDTH; MMC->SRS10 = srs10; if ((MSS_MMC_CARD_TYPE_MMC == cfg->card_type) && (MSS_MMC_NO_ERROR == ret_status)) { switch (cfg->bus_voltage) { case MSS_MMC_1_8V_BUS_VOLTAGE: /* Set Host Controller power to 1.8v */ ret_status = set_sdhost_power(SRS10_SET_1_8V_BUS_VOLTAGE); if (ret_status != MSS_MMC_NO_ERROR) { ret_status = MSS_MMC_NOT_INITIALISED; } break; case MSS_MMC_3_3V_BUS_VOLTAGE: if (((MSS_MMC_MODE_HS200 == cfg->bus_speed_mode) || (MSS_MMC_MODE_HS400_ES == cfg->bus_speed_mode) || (MSS_MMC_MODE_HS400 == cfg->bus_speed_mode))) { ret_status = MSS_MMC_NOT_INITIALISED; } else { /* Set Host Controller power to 3.3v */ ret_status = set_sdhost_power(SRS10_SET_3_3V_BUS_VOLTAGE); if (ret_status != MSS_MMC_NO_ERROR) { ret_status = MSS_MMC_NOT_INITIALISED; } } break; default: ret_status = MSS_MMC_NOT_INITIALISED; } } else { if (MSS_MMC_NO_ERROR == ret_status) { /* Set Host Controller power to 3.3v */ ret_status = set_sdhost_power(SRS10_SET_3_3V_BUS_VOLTAGE); if (ret_status != MSS_MMC_NO_ERROR) { ret_status = MSS_MMC_NOT_INITIALISED; } } } if (MSS_MMC_NO_ERROR == ret_status) { /* Set 400khz clock */ set_host_sdclk(MSS_MMC_CLOCK_400KHZ); } mmc_delay(DELAY_COUNT); /* MMC memory */ if ((MSS_MMC_CARD_TYPE_MMC == cfg->card_type) && (MSS_MMC_NO_ERROR == ret_status)) { response_status = cif_send_cmd(RESET_ARG, MMC_CMD_0_GO_IDLE_STATE, MSS_MMC_RESPONSE_NO_RESP); mmc_delay(DELAY_COUNT); /* Reset CMD is success */ if (TRANSFER_IF_SUCCESS == response_status) { ret_status = mmccard_oper_config(cfg); if (MSS_MMC_CARD_SELECT_SUCCESS == ret_status) { /* mmc init success */ g_mmc_init_complete = MMC_SET; /* Set Block length in device */ response_status = cif_send_cmd(BLK_SIZE, SD_CMD_16, MSS_MMC_RESPONSE_R1); if (TRANSFER_IF_SUCCESS == response_status) { /* Read EXT_CSD */ ret_status = MSS_MMC_single_block_read(READ_SEND_EXT_CSD, csd_reg); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { pcsd_reg = ((uint8_t *)csd_reg); hw_device_type = pcsd_reg[EXT_CSD_CARD_TYPE_OFFSET]; hw_hs_timing = pcsd_reg[EXT_CSD_HS_TIMING_OFFSET]; hw_strobe_suport = pcsd_reg [EXT_CSD_ES_SUPPORT_OFFSET]; g_device_hpi_suport = pcsd_reg[EXT_CSD_ES_SUPPORT_OFFSET]; if ((g_device_hpi_suport & DEVICE_HPI_SUPPORT) == DEVICE_HPI_SUPPORT) { /* enable HPI in device */ response_status = cif_send_cmd(MMC_HPI_ENABLE, MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } } switch (cfg->bus_speed_mode) { case MSS_MMC_MODE_HS400_ES: if (((hw_device_type & DEVICE_SUPPORT_HS400) == DEVICE_SUPPORT_HS400) && (hw_strobe_suport == MMC_SET)) { ret_status = set_device_hs400_mode(cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_HS400_MODE_SETUP_FAILURE; } } else { ret_status = MSS_MMC_DEVICE_NOT_SUPPORT_HS400; } break; case MSS_MMC_MODE_HS400: if ((hw_device_type & DEVICE_SUPPORT_HS400) == DEVICE_SUPPORT_HS400) { ret_status = set_device_hs400_mode(cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_HS400_MODE_SETUP_FAILURE; } } else { ret_status = MSS_MMC_DEVICE_NOT_SUPPORT_HS400; } break; case MSS_MMC_MODE_HS200: if ((hw_device_type & DEVICE_SUPPORT_HS200) == DEVICE_SUPPORT_HS200) { ret_status = device_set_hs_timing(DEVICE_SUPPORT_HS200, cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_MODE_NOT_SUPPORT_DATAWIDTH; } else { ret_status = execute_tunning_mmc(cfg->data_bus_width); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_TRANSFER_FAIL; } } } else { ret_status = MSS_MMC_DEVICE_NOT_SUPPORT_HS200; } break; case MSS_MMC_MODE_DDR: if ((hw_device_type & DEVICE_SUPPORT_DDR) == DEVICE_SUPPORT_DDR) { ret_status = device_set_hs_timing(DEVICE_SUPPORT_DDR, cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_MODE_NOT_SUPPORT_DATAWIDTH; } /* Enable Host High Speed */ MMC->SRS10 |= (MMC_SET << SHIFT_2BIT); } else { ret_status = MSS_MMC_DEVICE_NOT_SUPPORT_DDR; } break; case MSS_MMC_MODE_SDR: if ((hw_device_type & DEVICE_SUPPORT_SDR_50MHZ) == DEVICE_SUPPORT_SDR_50MHZ) { ret_status = device_set_hs_timing(DEVICE_SUPPORT_SDR, cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_DWIDTH_ERR; } /* Enable Host High Speed */ MMC->SRS10 |= (MMC_SET << SHIFT_2BIT); } else if ((hw_device_type & DEVICE_SUPPORT_SDR_25MHZ) == DEVICE_SUPPORT_SDR_25MHZ) { ret_status = device_set_hs_timing(DEVICE_SUPPORT_SDR, cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_DWIDTH_ERR; } } else { ret_status = MSS_MMC_DEVICE_NOT_SUPPORT_SDR; } break; case MSS_MMC_MODE_LEGACY: ret_status = device_set_hs_timing(DEVICE_SUPPORT_LEGACY, cfg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_CLK_DIV_ERR; } break; default: ret_status = MSS_MMC_INIT_FAILURE; break; } if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { ret_status = MSS_MMC_single_block_read(READ_SEND_EXT_CSD, csd_reg); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { pcsd_reg = (uint8_t *)csd_reg; /* offsets defined in JESD84-B51 extended CSD */ g_hw_sec_count = csd_reg[EXT_CSD_SECTOR_COUNT_OFFSET/WORD_SIZE]; hw_ext_csd_rev = pcsd_reg[EXT_CSD_REVISION_OFFSET] & BYTE_MASK; hw_hs_timing = pcsd_reg[EXT_CSD_HS_TIMING_OFFSET]; if ((MMC_CLEAR == hw_hs_timing) && (cfg->bus_speed_mode != MSS_MMC_MODE_LEGACY)) { ret_status = MSS_MMC_CLK_DIV_ERR; } } } if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { ret_status = MSS_MMC_INIT_SUCCESS; g_mmc_trs_status.state = MSS_MMC_INIT_SUCCESS; } else { g_mmc_init_complete = MMC_CLEAR; ret_status = MSS_MMC_INIT_FAILURE; g_mmc_trs_status.state = MSS_MMC_INIT_FAILURE; } } else { g_mmc_init_complete = MMC_CLEAR; ret_status = MSS_MMC_INIT_FAILURE; g_mmc_trs_status.state = MSS_MMC_INIT_FAILURE; } } else { g_mmc_init_complete = MMC_CLEAR; ret_status = MSS_MMC_INIT_FAILURE; g_mmc_trs_status.state = MSS_MMC_INIT_FAILURE; } } } else { ret_status = MSS_MMC_RESET_ERR; } } /* SD Memory card */ else if ((MSS_MMC_CARD_TYPE_SD == cfg->card_type) && (MSS_MMC_NO_ERROR == ret_status)) { response_status = cif_send_cmd(RESET_ARG, MMC_CMD_0_GO_IDLE_STATE, MSS_MMC_RESPONSE_NO_RESP); mmc_delay(DELAY_COUNT); if (TRANSFER_IF_SUCCESS == response_status) { /* Specify the operating conditions to the device */ ret_status = sdcard_oper_config(cfg); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { ret_status = MSS_MMC_INIT_SUCCESS; g_mmc_trs_status.state = MSS_MMC_INIT_SUCCESS; } else { g_mmc_init_complete = MMC_CLEAR; ret_status = MSS_MMC_INIT_FAILURE; g_mmc_trs_status.state = MSS_MMC_INIT_FAILURE; } } else { g_mmc_init_complete = MMC_CLEAR; ret_status = MSS_MMC_INIT_FAILURE; g_mmc_trs_status.state = MSS_MMC_INIT_FAILURE; } } else { ret_status = MSS_MMC_NOT_INITIALISED; g_mmc_init_complete = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_NOT_INITIALISED; } /* Clear interrupts */ MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR | SRS12_CARD_INTERRUPT | SRS12_CARD_REMOVAL | SRS12_CARD_INSERTION); /* variable set but not used, so referencing to avoid compiler warning */ (void)hw_ext_csd_rev; return (ret_status); } /******************************************************************************* *************************** READ APIs ***************************************** *******************************************************************************/ /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ void MSS_MMC_get_info ( uint16_t *sector_size, uint32_t *sector_count ) { *sector_size = g_sector_size; *sector_count = g_hw_sec_count; } mss_mmc_status_t MSS_MMC_single_block_read(uint32_t src_addr, uint32_t * dst_addr) { uint32_t isr_errors; uint32_t blk_read, srs03_data, srs9; uint16_t word_cnt = (BLK_SIZE/WORD_SIZE); uint32_t idx_cnt; cif_response_t response_status; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); if (g_mmc_init_complete == MMC_SET) { /* check eMMC/SD device is busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (DEVICE_BUSY == response_status); /* device is ready */ if (TRANSFER_IF_SUCCESS == response_status) { /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; mmc_delay(MASK_8BIT); /* Block length and count*/ MMC->SRS01 = (BLK_SIZE | (MMC_SET << BLOCK_COUNT_ENABLE_SHIFT)); /* DPS, Data transfer direction - read */ srs03_data = (uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_READ |SRS3_BLOCK_COUNT_ENABLE | SRS3_RESP_ERR_CHECK_EN | SRS3_RESP_INTER_DISABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN); /* Check cmd and data line busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((srs9 & (SRS9_CMD_INHIBIT_CMD | SRS9_CMD_INHIBIT_DAT)) != MMC_CLEAR); if (READ_SEND_EXT_CSD == src_addr) /* eMMC EXT_CSD read */ { /* Command argument */ MMC->SRS02 = MMC_CLEAR; /* execute command */ MMC->SRS03 = (uint32_t)((MMC_CMD_8_SEND_EXT_CSD << MMC_SRS03_COMMAND_SHIFT) | srs03_data); } else if (READ_SEND_SCR == src_addr) /* SD card ACMD51 read */ { MMC->SRS01 = (SCR_REG_DATA_SIZE | (MMC_SET << BLOCK_COUNT_ENABLE_SHIFT)); word_cnt = SHIFT_2BIT; response_status = cif_send_cmd(SCR_REG_DATA_SIZE, SD_CMD_16, MSS_MMC_RESPONSE_R1); response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, SD_CMD_55, MSS_MMC_RESPONSE_R1); /* Command argument */ MMC->SRS02 = MMC_CLEAR; /* execute command */ MMC->SRS03 = (uint32_t)((SD_ACMD_51 << MMC_SRS03_COMMAND_SHIFT) | srs03_data); } else { /* Command argument */ MMC->SRS02 = src_addr; /* execute command */ MMC->SRS03 = (uint32_t)((MMC_CMD_17_READ_SINGLE_BLOCK << MMC_SRS03_COMMAND_SHIFT) | srs03_data); } idx_cnt = MMC_CLEAR; mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { blk_read = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (MMC_CLEAR == (blk_read & (SRS12_BUFFER_READ_READY | SRS12_ERROR_INTERRUPT))); /* Read in the contents of the Buffer */ if ((blk_read & SRS12_BUFFER_READ_READY) != MMC_CLEAR) { while (word_cnt > (BUFF_EMPTY)) { dst_addr[idx_cnt] = MMC->SRS08; ++idx_cnt; --word_cnt; } } isr_errors = MMC->SRS12; /* Abort if any errors*/ if ((SRS12_ERROR_STATUS_MASK & isr_errors) == MMC_CLEAR) { /* * Ensure no error fields in Card Status register are set and that * the device is idle before this function returns. */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (DEVICE_BUSY == response_status); if (TRANSFER_IF_SUCCESS == response_status) { ret_status = MSS_MMC_TRANSFER_SUCCESS; } else { ret_status = MSS_MMC_DEVICE_ERROR; } } else { ret_status = MSS_MMC_ERR_INTERRUPT; } /* Clear all status interrupts except: * current limit error, card interrupt, card removal, card insertion */ MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR | SRS12_CARD_INTERRUPT | SRS12_CARD_REMOVAL | SRS12_CARD_INSERTION); } else { ret_status = MSS_MMC_DEVICE_ERROR; } } else { ret_status = MSS_MMC_NOT_INITIALISED; } return (ret_status); } /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ mss_mmc_status_t MSS_MMC_sdma_read(uint32_t src, uint8_t *dest, uint32_t size) { uint32_t blockcount; uint32_t argument; uint32_t blocklen; uint32_t tmp, srs03_data, srs9; cif_response_t response_status; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); blocklen = BLK_SIZE; argument = src; if (g_mmc_init_complete == MMC_SET) { if (MSS_MMC_TRANSFER_IN_PROGRESS == g_mmc_trs_status.state) { ret_status = MSS_MMC_TRANSFER_IN_PROGRESS; } else { /* Size should be divided by 512, not greater than (32MB - 512) */ if (((size % blocklen) != MMC_CLEAR) || (size > (SIZE_32MB - BLK_SIZE)) || (size == MMC_CLEAR) || (dest == NULL_POINTER)) { ret_status = MSS_MMC_INVALID_PARAMETER; g_mmc_trs_status.state = MSS_MMC_INVALID_PARAMETER; } else { /* Disable PLIC interrupt for MMC */ PLIC_DisableIRQ(MMC_main_PLIC); /* Disable error/interrupt */ MMC->SRS14 = MMC_CLEAR; /* check eMMC/SD device is busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (DEVICE_BUSY == response_status); if (TRANSFER_IF_SUCCESS == response_status) { /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; mmc_delay(MASK_8BIT); /* Calculate block count */ blockcount = ((size - MMC_SET) / blocklen) + MMC_SET; /* select SDMA */ tmp = MMC->SRS10; tmp = (tmp & (~SRS10_DMA_SELECT_MASK)); MMC->SRS10 = (tmp | SRS10_DMA_SELECT_SDMA); /* SDMA setup */ MMC->SRS22 = ((uint32_t)((uintptr_t)dest)); MMC->SRS23 = ((uint32_t)(((uint64_t)((uintptr_t)dest)) >> MMC_64BIT_UPPER_ADDR_SHIFT)); /* Block length and count SDMA buffer boundary */ MMC->SRS01 = (blocklen | (blockcount << BLOCK_COUNT_ENABLE_SHIFT) | SRS1_DMA_BUFF_SIZE_512KB); /* Enable interrupts */ MMC->SRS14 = (SRS14_COMMAND_COMPLETE_SIG_EN | SRS14_TRANSFER_COMPLETE_SIG_EN | SRS14_DMA_INTERRUPT_SIG_EN | SRS14_DATA_TIMEOUT_ERR_SIG_EN); PLIC_EnableIRQ(MMC_main_PLIC); /* Check cmd and data line busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((srs9 & (SRS9_CMD_INHIBIT_CMD | SRS9_CMD_INHIBIT_DAT)) != MMC_CLEAR); if (blockcount > MMC_SET) /* Multi Block read */ { /* DPS, Data transfer direction - read */ srs03_data = ((uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_READ | SRS3_MULTI_BLOCK_SEL | SRS3_BLOCK_COUNT_ENABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN | SRS3_DMA_ENABLE)); /* multi block transfer */ g_mmc_is_multi_blk = MMC_SET; /* Command argument */ MMC->SRS02 = argument; /* execute command */ MMC->SRS03 = ((uint32_t)((MMC_CMD_18_READ_MULTIPLE_BLOCK << MMC_SRS03_COMMAND_SHIFT) | srs03_data)); } else /* single block read */ { /* DPS, Data transfer direction - read */ srs03_data = ((uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_READ | SRS3_BLOCK_COUNT_ENABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN | SRS3_DMA_ENABLE)); /* single block transfer */ g_mmc_is_multi_blk = MMC_CLEAR; /* Command argument */ MMC->SRS02 = argument; /* execute command */ MMC->SRS03 = ((uint32_t)((MMC_CMD_17_READ_SINGLE_BLOCK << MMC_SRS03_COMMAND_SHIFT) | srs03_data)); } g_mmc_trs_status.state = MSS_MMC_TRANSFER_IN_PROGRESS; ret_status = MSS_MMC_TRANSFER_IN_PROGRESS; } else { g_mmc_trs_status.state = MSS_MMC_DEVICE_ERROR; ret_status = MSS_MMC_DEVICE_ERROR; } } } } else { ret_status = MSS_MMC_NOT_INITIALISED; } return (ret_status); } /******************************************************************************* *************************** WRITE APIs ***************************************** *******************************************************************************/ /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ mss_mmc_status_t MSS_MMC_single_block_write(const uint32_t * src_addr, uint32_t dst_addr) { cif_response_t response_status; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint16_t word_cnt = MMC_CLEAR; uint32_t blk_tran_err; uint32_t blk_write; uint32_t srs03_data, srs9; if (g_mmc_init_complete == MMC_SET) { /* check eMMC/SD device is busy */ mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (DEVICE_BUSY == response_status); /* device ready */ if (TRANSFER_IF_SUCCESS == response_status) { /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; mmc_delay(MASK_8BIT); /* Block length and count*/ MMC->SRS01 = (BLK_SIZE | (MMC_SET << BLOCK_COUNT_ENABLE_SHIFT)); /* DPS, Data transfer direction - read */ srs03_data = (uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_WRITE |SRS3_BLOCK_COUNT_ENABLE | SRS3_RESP_ERR_CHECK_EN | SRS3_RESP_INTER_DISABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do /* Check cmd and data line busy */ { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((srs9 & (SRS9_CMD_INHIBIT_CMD | SRS9_CMD_INHIBIT_DAT)) != MMC_CLEAR); /* Command argument */ MMC->SRS02 = dst_addr; /* execute command */ MMC->SRS03 = (uint32_t)((MMC_CMD_24_WRITE_SINGLE_BLOCK << MMC_SRS03_COMMAND_SHIFT) | srs03_data); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { blk_write = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (MMC_CLEAR == (blk_write & (SRS12_BUFFER_WRITE_READY | SRS12_ERROR_INTERRUPT))); /* * Load the block of data into the * buffer, four bytes at a time through the Buffer Data Register. */ if((blk_write & SRS12_BUFFER_WRITE_READY) != MMC_CLEAR) { while((BLK_SIZE/WORD_SIZE) > word_cnt) { MMC->SRS08 = src_addr[word_cnt]; ++word_cnt; } /* Check is block write complete */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { blk_write = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (MMC_CLEAR == (blk_write & SRS12_TRANSFER_COMPLETE)); } blk_tran_err = MMC->SRS12; /* Abort if any errors*/ if ((SRS12_ERROR_STATUS_MASK & blk_tran_err) == MMC_CLEAR) { /* * Ensure no error fields in Card Status register are set and that * the device is idle before this function returns. */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (DEVICE_BUSY == response_status); if (TRANSFER_IF_SUCCESS == response_status) { ret_status = MSS_MMC_TRANSFER_SUCCESS; } else { ret_status = MSS_MMC_DEVICE_ERROR; } } else { ret_status = MSS_MMC_ERR_INTERRUPT; } /* Clear all status interrupts except: * current limit error, card interrupt, card removal, card insertion */ MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR | SRS12_CARD_INTERRUPT | SRS12_CARD_REMOVAL | SRS12_CARD_INSERTION); } else { ret_status = MSS_MMC_DEVICE_ERROR; } } else { ret_status = MSS_MMC_NOT_INITIALISED; } return (ret_status); } /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ mss_mmc_status_t MSS_MMC_sdma_write(const uint8_t *src, uint32_t dest, uint32_t size) { uint32_t blockcount; uint32_t argument; uint32_t blocklen; uint32_t tmp, srs03_data, srs9; cif_response_t response_status; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); blocklen = BLK_SIZE; argument = dest; if (g_mmc_init_complete == MMC_SET) { if (MSS_MMC_TRANSFER_IN_PROGRESS == g_mmc_trs_status.state) { ret_status = MSS_MMC_TRANSFER_IN_PROGRESS; } else { /* Size should be divided by 512, not greater than (32MB - 512) */ if (((size % blocklen) != MMC_CLEAR) || (size > (SIZE_32MB - BLK_SIZE)) || (size == MMC_CLEAR) || (src == NULL_POINTER)) { ret_status = MSS_MMC_INVALID_PARAMETER; } else { /* Disable PLIC interrupt for MMC */ PLIC_DisableIRQ(MMC_main_PLIC); /* Disable error/interrupt */ MMC->SRS14 = MMC_CLEAR; /* check eMMC/SD device is busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (DEVICE_BUSY == response_status); if (TRANSFER_IF_SUCCESS == response_status) { /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; mmc_delay(MASK_8BIT); /* Calculate block count */ blockcount = ((size - MMC_SET) / blocklen) + MMC_SET; /* Enable SDMA */ tmp = MMC->SRS10; tmp = (tmp & (~SRS10_DMA_SELECT_MASK)); MMC->SRS10 = (tmp | SRS10_DMA_SELECT_SDMA); /* SDMA setup */ MMC->SRS22 = (uint32_t)(uintptr_t)src; MMC->SRS23 = (uint32_t)(((uint64_t)(uintptr_t)src) >> MMC_64BIT_UPPER_ADDR_SHIFT); /* Block length and count SDMA buffer boundary */ MMC->SRS01 = (blocklen | (blockcount << BLOCK_COUNT_ENABLE_SHIFT) | SRS1_DMA_BUFF_SIZE_512KB); /* enable interrupts */ MMC->SRS14 = (SRS14_COMMAND_COMPLETE_SIG_EN | SRS14_TRANSFER_COMPLETE_SIG_EN | SRS14_DMA_INTERRUPT_SIG_EN | SRS14_DATA_TIMEOUT_ERR_SIG_EN); /* Enable PLIC MMC interrupt */ PLIC_EnableIRQ(MMC_main_PLIC); /* check data line busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((srs9 & (SRS9_CMD_INHIBIT_CMD | SRS9_CMD_INHIBIT_DAT)) != MMC_CLEAR); if (blockcount > MMC_SET) /* Multi Block write */ { /* DPS, Data transfer direction - write */ srs03_data = (uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_WRITE | SRS3_MULTI_BLOCK_SEL | SRS3_BLOCK_COUNT_ENABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN | SRS3_DMA_ENABLE); /* multi block transfer */ g_mmc_is_multi_blk = MMC_SET; MMC->SRS02 = argument; /* execute command */ MMC->SRS03 = (uint32_t)((MMC_CMD_25_WRITE_MULTI_BLOCK << MMC_SRS03_COMMAND_SHIFT) | srs03_data); } else /* single block write */ { /* DPS, Data transfer direction - write */ srs03_data = (uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_WRITE | SRS3_BLOCK_COUNT_ENABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN | SRS3_DMA_ENABLE); /* single block transfer */ g_mmc_is_multi_blk = MMC_CLEAR; /* execute command */ MMC->SRS02 = argument; MMC->SRS03 = (uint32_t)((MMC_CMD_24_WRITE_SINGLE_BLOCK << MMC_SRS03_COMMAND_SHIFT) | srs03_data); } g_mmc_trs_status.state = MSS_MMC_TRANSFER_IN_PROGRESS; ret_status = MSS_MMC_TRANSFER_IN_PROGRESS; } else { g_mmc_trs_status.state = MSS_MMC_DEVICE_ERROR; ret_status = MSS_MMC_DEVICE_ERROR; } } } } else { ret_status = MSS_MMC_NOT_INITIALISED; } return (ret_status); } /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ mss_mmc_status_t MSS_MMC_get_transfer_status(void) { return g_mmc_trs_status.state; } /*-------------------------------------------------------------------------*//** * See "mss_mmc.h" for details of how to use this function. */ void MSS_MMC_set_handler( mss_mmc_handler_t handler) { g_transfer_complete_handler_t = handler; } /****************************************************************************** MMC ISR *******************************************************************************/ uint8_t PLIC_mmc_main_IRQHandler(void) { uint32_t trans_status_isr; uint32_t response_reg, inttoclear; uintptr_t address; uintptr_t highaddr; uint64_t address64; static uint8_t transfer_complete = MMC_CLEAR; trans_status_isr = MMC->SRS12; /* Error interrupt */ if ((trans_status_isr & SRS12_ERROR_INTERRUPT) != MMC_CLEAR) { MMC->SRS12 = trans_status_isr; MMC->SRS14 = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_TRANSFER_FAIL; if (g_transfer_complete_handler_t != NULL_POINTER) { g_transfer_complete_handler_t(trans_status_isr); } } /* Command completion */ else if ((trans_status_isr & SRS12_COMMAND_COMPLETE) != MMC_CLEAR) { MMC->SRS12 = SRS12_COMMAND_COMPLETE; response_reg = MMC->SRS04; if ((response_reg & CARD_STATUS_ALL_ERRORS_MASK) != MMC_CLEAR) { /* Disable interrupts */ MMC->SRS14 = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_RESPONSE_ERROR; } /* stop command success */ if (transfer_complete == MMC_SET) { /* Disable interrupts */ MMC->SRS14 = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_TRANSFER_SUCCESS; transfer_complete = MMC_CLEAR; if (g_transfer_complete_handler_t != NULL_POINTER) { g_transfer_complete_handler_t(trans_status_isr); } } } /* Transfer Completion */ else if ((trans_status_isr & SRS12_TRANSFER_COMPLETE) != MMC_CLEAR) { MMC->SRS12 = trans_status_isr; if (g_mmc_is_multi_blk == MMC_CLEAR) { /* Disable interrupts */ MMC->SRS14 = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_TRANSFER_SUCCESS; transfer_complete = MMC_CLEAR; if (g_transfer_complete_handler_t != NULL_POINTER) { g_transfer_complete_handler_t(trans_status_isr); } } else { /* multi block transfer */ transfer_complete = MMC_SET; send_mmc_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_12_STOP_TRANSMISSION, MSS_MMC_RESPONSE_R1, CHECK_IF_CMD_SENT_INT); } } /* DMA interrupt */ else if ((trans_status_isr & SRS12_DMA_INTERRUPT) != MMC_CLEAR) { address = MMC->SRS22; highaddr = MMC->SRS23; address64 = address | ((uint64_t)highaddr << MMC_64BIT_UPPER_ADDR_SHIFT); /* Increase address(512kb) and re-write new address in DMA buffer */ address = (uint32_t)address64; highaddr = (uint32_t)(address64 >> MMC_64BIT_UPPER_ADDR_SHIFT); /** * Clear interrupt flag here, in order to prevent masking the next * interrupt that might be triggered when the SDMA is restarting (by * writing in address register) */ MMC->SRS12 = SRS12_DMA_INTERRUPT; MMC->SRS22 = address; MMC->SRS23 = highaddr; } else if ((trans_status_isr & SRS12_CMD_QUEUING_INT) != MMC_CLEAR) { MMC->SRS12 = trans_status_isr; inttoclear = MMC->CQRS04; MMC->CQRS04 = inttoclear; if ((inttoclear & CQRS04_RESP_ERR_INT) != MMC_CLEAR) { /* Disable interrupts */ MMC->SRS14 = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_TRANSFER_FAIL; } if ((inttoclear & CQRS04_TASK_COMPLETE_INT) != MMC_CLEAR) { inttoclear = MMC->CQRS11; /* clear all caught notifications */ MMC->CQRS11 = inttoclear; --g_cq_task_id; if (g_cq_task_id == MMC_CLEAR) { /* Disable interrupts */ MMC->SRS14 = MMC_CLEAR; g_mmc_trs_status.state = MSS_MMC_TRANSFER_SUCCESS; if (g_transfer_complete_handler_t != NULL_POINTER) { g_transfer_complete_handler_t(trans_status_isr); } } } } else { ; } return g_mmc_trs_status.state; } /******************************************************************************* ****************************** Private Functions ******************************* *******************************************************************************/ static mss_mmc_status_t phy_training_mmc(uint8_t delay_type, uint32_t clk_rate) { uint8_t delay; uint8_t max_delay; uint8_t new_delay; uint8_t pos, length, curr_length; uint8_t rx_buff[BLK_SIZE]; uint32_t read_srs11; uint32_t cmd_response; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; cif_response_t response_status = TRANSFER_IF_FAIL; if (clk_rate <= MSS_MMC_CLOCK_12_5MHZ) { max_delay = BYTES_20; } else { max_delay = (MSS_MMC_CLOCK_200MHZ / clk_rate) * BYTES_2; } pos = length = curr_length = MMC_CLEAR; /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; for (delay = MMC_CLEAR; delay < max_delay; delay++) { phy_write_set(delay_type, delay); ret_status = read_tune_block((uint32_t *)rx_buff, BLK_SIZE, MMC_CMD_17_READ_SINGLE_BLOCK); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { curr_length++; if (curr_length > length) { pos = delay - length; length++; /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; } } else { mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { if (TRANSFER_IF_FAIL == response_status) { /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout2); mMMC_ARM_TIMEOUT(mmc_spin_timeout2); do { read_srs11 = MMC->SRS11; mMMC_CHECK_TIMEOUT(mmc_spin_timeout2, MSS_MMC_NOT_INITIALISED); } while ((read_srs11 & MMC_RESET_DATA_CMD_LINE) != MMC_CLEAR); } response_status = cif_send_cmd(sdcard_RCA << RCA_SHIFT_BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); cmd_response = MMC->SRS04; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((TRANSFER_IF_SUCCESS != response_status) || ((cmd_response & DEVICE_STATE_MASK) != DEVICE_STATE_TRANS)); curr_length = MMC_CLEAR; response_status = TRANSFER_IF_FAIL; } } new_delay = pos + (length / BYTES_2); phy_write_set(delay_type, new_delay); ret_status = read_tune_block((uint32_t *)rx_buff, BLK_SIZE, MMC_CMD_17_READ_SINGLE_BLOCK); /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; return (ret_status); } /******************************************************************************/ static void phy_write_set(uint8_t delay_type, uint8_t delay_value) { uint8_t phyaddr = MMC_CLEAR; uint32_t reg = MMC_CLEAR; uint32_t phycfg = MMC_CLEAR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); /* Phy delay set for eMMC modes */ get_phy_addr(delay_type, &phyaddr); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { reg = MMC->HRS04; mMMC_CHECK_TIMEOUT(mmc_spin_timeout); } while ((reg & HRS_PHY_ACKNOWLEDGE_REQUEST) != MMC_CLEAR); phycfg = ((uint32_t)phyaddr | (delay_value << SHIFT_8BIT)); /* set data and address */ MMC->HRS04 = phycfg; /* send write request */ MMC->HRS04 |= (uint32_t)HRS_PHY_WRITE_REQUEST; /* wait for acknowledge */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { reg = MMC->HRS04; mMMC_CHECK_TIMEOUT(mmc_spin_timeout); } while ((reg & HRS_PHY_ACKNOWLEDGE_REQUEST) == MMC_CLEAR); phycfg &= ~(uint32_t)HRS_PHY_WRITE_REQUEST; /* clear write request */ MMC->HRS04 = phycfg; MMC->HRS04 = MMC_CLEAR; } /******************************************************************************/ static void get_phy_addr(MSS_MMC_phydelay phydelaytype, uint8_t *phySetAddr) { uint8_t i; static const struct phydelayaddresses phydelayaddr[] = { { UIS_ADDR_DEFAULT_SPEED, MSS_MMC_PHY_DELAY_INPUT_DEFAULT_SPEED}, { UIS_ADDR_HIGH_SPEED, MSS_MMC_PHY_DELAY_INPUT_HIGH_SPEED}, { UIS_ADDR_UHSI_SDR12, MSS_MMC_PHY_DELAY_INPUT_SDR12}, { UIS_ADDR_UHSI_SDR25, MSS_MMC_PHY_DELAY_INPUT_SDR25}, { UIS_ADDR_UHSI_SDR50, MSS_MMC_PHY_DELAY_INPUT_SDR50}, { UIS_ADDR_UHSI_DDR50, MSS_MMC_PHY_DELAY_INPUT_DDR50}, { UIS_ADDR_MMC_LEGACY, MSS_MMC_PHY_DELAY_INPUT_MMC_LEGACY}, { UIS_ADDR_MMC_SDR, MSS_MMC_PHY_DELAY_INPUT_MMC_SDR}, { UIS_ADDR_MMC_DDR, MSS_MMC_PHY_DELAY_INPUT_MMC_DDR}, { UIS_ADDR_SDCLK, MSS_MMC_PHY_DELAY_DLL_SDCLK}, { UIS_ADDR_HS_SDCLK, MSS_MMC_PHY_DELAY_DLL_HS_SDCLK}, { UIS_ADDR_DAT_STROBE, MSS_MMC_PHY_DELAY_DLL_DAT_STROBE}, }; for (i = MMC_CLEAR; i < (sizeof(phydelayaddr) / sizeof(phydelayaddr[MMC_CLEAR])); i++) { if (phydelayaddr[i].phydelaytype == phydelaytype) { *phySetAddr = phydelayaddr[i].address; break; } } } /******************************************************************************/ static mss_mmc_status_t mmccard_oper_config(const mss_mmc_cfg_t * cfg) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; cif_response_t response_status; uint32_t response_reg; uint32_t power_up_status; uint32_t access_mode; uint32_t csd_max_sector_lwr; uint32_t max_sector_len; uint32_t oper_cond = MMC_CLEAR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); response_status = cif_send_cmd(STUFF_BITS, MMC_CMD_1_SEND_OP_COND, MSS_MMC_RESPONSE_R3); if (TRANSFER_IF_SUCCESS == response_status) { response_reg = MMC->SRS04; if (cfg->bus_voltage == MSS_MMC_1_8V_BUS_VOLTAGE) { if ((response_reg & MMC_DEVICE_LOW_POWER) == MMC_DEVICE_LOW_POWER) { oper_cond = MMC_DEVICE_LOW_VOLT_SET; } else { ret_status = MSS_MMC_DEVICE_NOT_SUPPORT_LOW_POWER; } } else { oper_cond = MMC_DEVICE_3_3V_VOLT_SET; } if (ret_status == MSS_MMC_NO_ERROR) { mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { response_status = cif_send_cmd(oper_cond, MMC_CMD_1_SEND_OP_COND, MSS_MMC_RESPONSE_R3); response_reg = MMC->SRS04; power_up_status = BUSY_BIT_MASK & response_reg; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((BUSY_BIT_MASK != power_up_status) && (TRANSFER_IF_FAIL != response_status)); } else { response_status = TRANSFER_IF_FAIL; } } if (TRANSFER_IF_SUCCESS == response_status) { mmc_delay(DELAY_COUNT); response_reg = MMC->SRS04;; /* If access_mode = 2 then sector address, if access = 0 then byte mode */ access_mode = ((SECTOR_ACCESS_MODE_MASK & response_reg) >> SECTOR_SHIFT); /* read CID register from device */ response_status = cif_send_cmd(STUFF_BITS, MMC_CMD_2_ALL_SEND_CID, MSS_MMC_RESPONSE_R2); if (TRANSFER_IF_SUCCESS == response_status) { mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { /* Assign a RCA to the device */ response_status = cif_send_cmd(sdcard_RCA << RCA_SHIFT_BIT, MMC_CMD_3_SET_RELATIVE_ADDR, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (TRANSFER_IF_SUCCESS != response_status); } if (TRANSFER_IF_SUCCESS == response_status) { /* Read CSD register from device */ response_status = cif_send_cmd(sdcard_RCA << RCA_SHIFT_BIT, MMC_CMD_9_SEND_CSD, MSS_MMC_RESPONSE_R2); if (TRANSFER_IF_SUCCESS == response_status) { /* Sector size from "Max. write data block length" of CSD[25:22]*/ csd_max_sector_lwr = MMC->SRS04 & SECT_SIZE_CSD_MASK; max_sector_len = csd_max_sector_lwr >> SECT_SIZE_CSD_SHIFT; g_sector_size = (uint16_t)((uint32_t)MMC_SET << max_sector_len); /* Select device */ response_status = cif_send_cmd(sdcard_RCA << RCA_SHIFT_BIT, MMC_CMD_7_SELECT_DESELECT_CARD, MSS_MMC_RESPONSE_R1); } if (TRANSFER_IF_SUCCESS == response_status) { /* Set MMC data bus width 1-bit */ response_status = cif_send_cmd( MMC_DW_CSD |(MSS_MMC_DATA_WIDTH_1BIT << SHIFT_8BIT), MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } if (TRANSFER_IF_SUCCESS == response_status) { /* Set Phy delay for select MMC mode */ ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_MMC_LEGACY, MSS_MMC_CLOCK_400KHZ); if (ret_status == MSS_MMC_TRANSFER_SUCCESS) { /* Data timeout 500ms */ ret_status = set_data_timeout(DATA_TIMEOUT_VALUE); if (ret_status == MSS_MMC_NO_ERROR) { g_mmc_init_complete = MMC_SET; ret_status = MSS_MMC_CARD_SELECT_SUCCESS; } } } } else { ret_status = MSS_MMC_CARD_SELECT_ERROR; } } else { ret_status = MSS_MMC_RCA_ERROR; } } else { ret_status = MSS_MMC_OP_COND_ERR; } /* variable set but unused, so referencing to avoid compiler warning */ (void)access_mode; return (ret_status); } /******************************************************************************/ static mss_mmc_status_t sdcard_oper_config(const mss_mmc_cfg_t * cfg) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; cif_response_t response_status; uint32_t temp; uint32_t scr_reg[SHIFT_2BIT]; uint32_t bus_width; uint32_t argument; uint32_t S18A = MMC_CLEAR; uint8_t S18R = MMC_CLEAR; uint8_t XPC = MMC_CLEAR; uint32_t tmp, CCS; uint32_t max_current_3_3V; uint32_t max_current_1_8V; uint32_t card_ocr_reg = MASK_24BIT; uint32_t card_volt = MMC_CLEAR; uint32_t controller_volt = MMC_CLEAR; uint32_t csd_max_sector_lwr; uint32_t max_sector_len; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); response_status = cif_send_cmd(IF_COND_27V_33V, SD_CMD_8_SEND_IF_COND, MSS_MMC_RESPONSE_R7); if (TRANSFER_IF_SUCCESS == response_status) { tmp = MMC->SRS18; max_current_3_3V = ((tmp & MASK_8BIT) * SHIFT_4BIT); max_current_1_8V = (((tmp & BYTE_3_MASK) >> SHIFT_16BIT) * SHIFT_4BIT); /* flag used for SDXC cards if card is initialized with XPC=1 then it is operating less than 150mA */ XPC = ((max_current_1_8V >= MAX_CURRENT_MA) && (max_current_3_3V >= MAX_CURRENT_MA)) ? MMC_SET : MMC_CLEAR; /* check if UHS-I is supported by SDIO host controller, then set to 1 */ S18R = (is_uhsi_supported() != MMC_CLEAR) ? MMC_SET : MMC_CLEAR; response_status = cif_send_cmd(MMC_CLEAR, SD_CMD_55, MSS_MMC_RESPONSE_R1); if (TRANSFER_IF_SUCCESS == response_status) { response_status = cif_send_cmd(MMC_CLEAR, SD_ACMD_41_SEND_OP_COND, MSS_MMC_RESPONSE_R3); if (TRANSFER_IF_SUCCESS == response_status) { /* Read OCR register */ card_ocr_reg = MMC->SRS04; if ((cfg->bus_speed_mode == MSS_SDCARD_MODE_DEFAULT_SPEED) || (cfg->bus_speed_mode == MSS_SDCARD_MODE_HIGH_SPEED)) { S18R = MMC_CLEAR; } /* check the voltage capabilities of the SDIO host controller and a card to set appropriate voltage */ if ((card_ocr_reg & SDCARD_REG_OCR_3_3_3_4) != MMC_CLEAR) { card_volt = (uint32_t)SDCARD_REG_OCR_3_3_3_4; controller_volt = SRS10_SET_3_3V_BUS_VOLTAGE; } else if ((card_ocr_reg & SDCARD_REG_OCR_3_2_3_3) != MMC_CLEAR) { card_volt = (uint32_t)SDCARD_REG_OCR_3_2_3_3; controller_volt = SRS10_SET_3_3V_BUS_VOLTAGE; } else if ((card_ocr_reg & SDCARD_REG_OCR_3_0_3_1) != MMC_CLEAR) { card_volt = (uint32_t)SDCARD_REG_OCR_3_0_3_1; controller_volt = SRS10_SET_3_0V_BUS_VOLTAGE; } else if ((card_ocr_reg & SDCARD_REG_OCR_2_9_3_0) != MMC_CLEAR) { card_volt = (uint32_t)SDCARD_REG_OCR_2_9_3_0; controller_volt = SRS10_SET_3_0V_BUS_VOLTAGE; } else { /* default values */ card_volt = (uint32_t)SDCARD_REG_OCR_3_3_3_4; controller_volt = SRS10_SET_3_3V_BUS_VOLTAGE; } /* if the voltage is different to 3.3v */ if (controller_volt != SRS10_SET_3_3V_BUS_VOLTAGE) { set_sdhost_power(controller_volt); response_status = cif_send_cmd(RESET_ARG, MMC_CMD_0_GO_IDLE_STATE, MSS_MMC_RESPONSE_NO_RESP); if (TRANSFER_IF_SUCCESS == response_status) { mmc_delay(DELAY_COUNT); response_status = cif_send_cmd(IF_COND_27V_33V, SD_CMD_8_SEND_IF_COND, MSS_MMC_RESPONSE_R7); if (TRANSFER_IF_SUCCESS == response_status) { temp = MMC->SRS04; } else { return MSS_MMC_SDCARD_NOT_SUPPORT_VOLTAGE; } } } argument = card_volt; /* if card sent response on CMD8 command set host high capacity flag to 1 */ argument |= (uint32_t)SDCARD_ACMD41_HCS; if (S18R != MMC_CLEAR) { argument |= (uint32_t)SDCARD_REG_OCR_S18R; } if (XPC != MMC_CLEAR) { argument |= (uint32_t)SDCARD_REG_OCR_XPC; } ret_status = MSS_MMC_TRANSFER_SUCCESS; /* Read OCR register from SD card*/ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { mmc_delay(DELAY_COUNT); response_status = cif_send_cmd(MMC_CLEAR, SD_CMD_55, MSS_MMC_RESPONSE_R1); if (TRANSFER_IF_SUCCESS == response_status) { mmc_delay(DELAY_COUNT); response_status = cif_send_cmd(argument, SD_ACMD_41_SEND_OP_COND, MSS_MMC_RESPONSE_R3); } else { break; } tmp = MMC->SRS04; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((tmp & SDCARD_REG_OCR_READY) == MMC_CLEAR); /* If CCS = 0, SDSC card < 2gb. If CCS = 1, SDHC/XC >2gb */ CCS = MMC->SRS04 & SDCARD_REG_OCR_CCS; S18A = MMC->SRS04 & SDCARD_REG_OCR_S18A; /* UHI -I Support */ if ((S18A != MMC_CLEAR) && (TRANSFER_IF_SUCCESS == response_status)) { if (cfg->data_bus_width == MSS_MMC_DATA_WIDTH_4BIT) { MMC->SRS10 |= SRS10_DATA_WIDTH_4BIT; } else { return MSS_MMC_MODE_NOT_SUPPORT_DATAWIDTH; } const uint32_t dat_level = (SRS9_DAT0_SIGNAL_LEVEL | SRS9_DAT1_SIGNAL_LEVEL | SRS9_DAT2_SIGNAL_LEVEL | SRS9_DAT3_SIGNAL_LEVEL); response_status = cif_send_cmd(MMC_CLEAR, SD_CMD_11_VOLAGE_SWITCH, MSS_MMC_RESPONSE_R1); if (TRANSFER_IF_SUCCESS == response_status) { /* disable sd clock */ temp = MMC->SRS11; temp &= ~(uint32_t)SRS11_SD_CLOCK_ENABLE; MMC->SRS11 = temp; /* if dat line is not 0000b return error */ tmp = MMC->SRS09; if ((tmp & dat_level) != MMC_CLEAR) { ret_status = MSS_MMC_ERR_SWITCH_VOLTAGE_FAILED; } else { /* 1.8V signal enable */ tmp = MMC->SRS15; tmp |= SRS15_18V_ENABLE; MMC->SRS15 = tmp; /* wait 5ms */ mmc_delay(DELAY_COUNT); mmc_delay(DELAY_COUNT); /* if 1.8V signal enable is cleared by host return with error */ tmp = MMC->SRS15; if ((tmp & SRS15_18V_ENABLE) == MMC_CLEAR) { ret_status = MSS_MMC_ERR_SWITCH_VOLTAGE_FAILED; } else { /* internal clock enable */ tmp = MMC->SRS11; tmp |= (uint32_t)SRS11_INT_CLOCK_ENABLE; MMC->SRS11 = tmp; while (MMC_CLEAR == (MMC->SRS11 & SRS11_INT_CLOCK_STABLE)); /* enable sd clock */ temp = MMC->SRS11; temp |= (uint32_t)SRS11_SD_CLOCK_ENABLE; MMC->SRS11 = temp; /* wait 1ms */ mmc_delay(DELAY_COUNT); /* if dat line is not 1111b return error */ tmp = MMC->SRS09; if ((tmp & dat_level) != dat_level) { ret_status = MSS_MMC_ERR_SWITCH_VOLTAGE_FAILED; response_status = TRANSFER_IF_FAIL; } else { ret_status = MSS_MMC_TRANSFER_SUCCESS; } } } } } if ((TRANSFER_IF_SUCCESS == response_status) && (ret_status == MSS_MMC_TRANSFER_SUCCESS)) { response_status = cif_send_cmd(MMC_CLEAR, MMC_CMD_2_ALL_SEND_CID, MSS_MMC_RESPONSE_R2); if (TRANSFER_IF_SUCCESS == response_status) { response_status = cif_send_cmd(MMC_CLEAR, MMC_CMD_3_SET_RELATIVE_ADDR, MSS_MMC_RESPONSE_R6); sdcard_RCA = ((MMC->SRS04 >> SHIFT_16BIT) & MASK_16BIT); if ((S18A == MMC_CLEAR) && (S18R != MMC_CLEAR)) { sd_card_uhsi_supported(); } if (TRANSFER_IF_SUCCESS == response_status) { int csd_struct; int c_size = 0; /* Read CSD register from device */ response_status = cif_send_cmd(sdcard_RCA << RCA_SHIFT_BIT, MMC_CMD_9_SEND_CSD, MSS_MMC_RESPONSE_R2); /* Sector size from "Max. write data block length" of CSD[25:22]*/ csd_max_sector_lwr = MMC->SRS04 & SECT_SIZE_CSD_MASK; max_sector_len = csd_max_sector_lwr >> SECT_SIZE_CSD_SHIFT; g_sector_size = (uint16_t)((uint32_t)MMC_SET << max_sector_len); csd_struct = get_srs_bits(126,2); switch (csd_struct) { case 0: c_size = get_srs_bits(62, 12); g_hw_sec_count = (c_size + 1) << (get_srs_bits(47, 3) + 2); break; case 1: c_size = get_srs_bits(48, 22); g_hw_sec_count = (c_size + 1) << 10; break; default: response_status = TRANSFER_IF_FAIL; break; } } if (TRANSFER_IF_SUCCESS == response_status) { response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, MMC_CMD_7_SELECT_DESELECT_CARD, MSS_MMC_RESPONSE_R1B); if(TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } } if (TRANSFER_IF_SUCCESS == response_status) { /* disable host normal interrupts for masking incorrect interrupts that may occur while changing the bus width.*/ tmp = MMC->SRS13; MMC->SRS13 = tmp & ~(uint32_t)SRS13_CARD_INTERRUPT_STAT_EN; mmc_delay(DELAY_COUNT); response_status = cif_send_cmd(sdcard_RCA << SHIFT_16BIT, SD_CMD_55, MSS_MMC_RESPONSE_R1); if (TRANSFER_IF_SUCCESS == response_status) { if (cfg->data_bus_width == MSS_MMC_DATA_WIDTH_4BIT) { /* 4-bit bus data width */ bus_width = SHIFT_2BIT; } else { /* 1-bit bus data width */ bus_width = MMC_CLEAR; } /* set bus with in the card 4-bit -2, 1-bit - 0 */ response_status = cif_send_cmd(bus_width, SD_ACMD_6, MSS_MMC_RESPONSE_R1); if (TRANSFER_IF_SUCCESS == response_status) { if (cfg->data_bus_width == MSS_MMC_DATA_WIDTH_4BIT) { MMC->SRS10 |= SRS10_DATA_WIDTH_4BIT; } MMC->SRS13 = tmp; /* mmc init success */ g_mmc_init_complete = MMC_SET; /* get SCR register */ ret_status = MSS_MMC_single_block_read(READ_SEND_SCR, scr_reg); if (ret_status == MSS_MMC_TRANSFER_SUCCESS) { ret_status = set_sd_host_device_bus_mode(cfg); if (ret_status == MSS_MMC_TRANSFER_SUCCESS) { /* up the Host MMC clock frequency */ set_host_sdclk(cfg->clk_rate); switch(cfg->bus_speed_mode) { case MSS_SDCARD_MODE_SDR12: ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_SDR12, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } break; case MSS_SDCARD_MODE_SDR25: ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_SDR25, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } break; case MSS_SDCARD_MODE_SDR50: ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_SDR50, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } tmp = MMC->SRS17; if (((tmp & SRS17_USE_TUNING_SDR50) != MMC_CLEAR) && (response_status != TRANSFER_IF_FAIL)) { ret_status = sd_tuning(); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } } break; case MSS_SDCARD_MODE_SDR104: ret_status = sd_tuning(); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } break; case MSS_SDCARD_MODE_DDR50: ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_DDR50, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } break; case MSS_MMC_PHY_DELAY_INPUT_HIGH_SPEED: ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_HIGH_SPEED, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } break; default: ret_status = phy_training_mmc(MSS_MMC_PHY_DELAY_INPUT_DEFAULT_SPEED, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } break; } } else { response_status = TRANSFER_IF_FAIL; } } else { response_status = TRANSFER_IF_FAIL; } } else { response_status = TRANSFER_IF_FAIL; } } else { MMC->SRS13 = tmp; } } } } } } } if (TRANSFER_IF_SUCCESS == response_status) { ret_status = MSS_MMC_TRANSFER_SUCCESS; } else { ret_status = MSS_MMC_TRANSFER_FAIL; } /* variable set but unused, so referencing to avoid compiler warning */ (void)CCS; return (ret_status); } /******************************************************************************/ static mss_mmc_status_t set_sd_host_device_bus_mode(const mss_mmc_cfg_t * cfg) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint8_t card_access_mode; uint8_t card_driver_strength = SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_B; switch (cfg->bus_speed_mode) { case (uint8_t)MSS_SDCARD_MODE_SDR12: case (uint8_t)MSS_SDCARD_MODE_DEFAULT_SPEED: card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR12; break; case (uint8_t)MSS_SDCARD_MODE_HIGH_SPEED: case (uint8_t)MSS_SDCARD_MODE_SDR25: card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR25; break; case (uint8_t)MSS_SDCARD_MODE_SDR50: card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR50; break; case (uint8_t)MSS_SDCARD_MODE_SDR104: card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR104; break; case (uint8_t)MSS_SDCARD_MODE_DDR50: card_access_mode = SDCARD_SWITCH_ACCESS_MODE_DDR50; break; default: ret_status = MSS_MMC_INVALID_PARAMETER; break; } if (ret_status == MSS_MMC_NO_ERROR) { ret_status= sd_host_process_switch_function(card_access_mode, SDCARD_SWITCH_GROUP_NR_1); if (ret_status == MSS_MMC_TRANSFER_SUCCESS) { ret_status = set_host_uhsi_mode(cfg->bus_speed_mode, card_driver_strength); } } return (ret_status); } /******************************************************************************/ static mss_mmc_status_t set_host_uhsi_mode ( uint8_t access_mode, uint8_t driver_strengh ) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint32_t tmp; uint32_t uhs_mode; uint8_t enable_high_speed = MMC_CLEAR; switch (access_mode) { case (uint8_t)MSS_SDCARD_MODE_SDR12: case (uint8_t)MSS_SDCARD_MODE_DEFAULT_SPEED: uhs_mode = SRS15_UHS_MODE_SDR12; break; case (uint8_t)MSS_SDCARD_MODE_SDR25: case (uint8_t)MSS_SDCARD_MODE_HIGH_SPEED: uhs_mode = SRS15_UHS_MODE_SDR25; enable_high_speed = MMC_SET; break; case (uint8_t)MSS_SDCARD_MODE_SDR50: uhs_mode = SRS15_UHS_MODE_SDR50; enable_high_speed = MMC_SET; break; case (uint8_t)MSS_SDCARD_MODE_SDR104: uhs_mode = SRS15_UHS_MODE_SDR104; enable_high_speed = MMC_SET; break; case (uint8_t)MSS_SDCARD_MODE_DDR50: uhs_mode = SRS15_UHS_MODE_DDR50; enable_high_speed = MMC_SET; break; default: ret_status = MSS_MMC_INVALID_PARAMETER; break; } if (ret_status == MSS_MMC_NO_ERROR) { uint32_t SRS15 = MMC->SRS15; SRS15 &= ~SRS15_DRIVER_TYPE_MASK; switch (driver_strengh) { case SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_A: SRS15 |= SRS15_DRIVER_TYPE_A; break; case SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_B: SRS15 |= SRS15_DRIVER_TYPE_B; break; case SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_C: SRS15 |= SRS15_DRIVER_TYPE_C; break; case SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_D: SRS15 |= SRS15_DRIVER_TYPE_D; break; default: /* nothing */ break; } MMC->SRS15 = SRS15; if (enable_high_speed != MMC_CLEAR) { /* enable high-speed in the SDIO host controller */ tmp = MMC->SRS10; tmp |= SRS10_HIGH_SPEED_ENABLE; MMC->SRS10 = tmp; } else { /* disable high-speed in the SDIO host controller */ tmp = MMC->SRS10; tmp &= ~SRS10_HIGH_SPEED_ENABLE; MMC->SRS10 = tmp; } tmp = MMC->SRS15; tmp &= ~SRS15_UHS_MODE_MASK; tmp |= uhs_mode; MMC->SRS15 = tmp; ret_status = MSS_MMC_TRANSFER_SUCCESS; } return (ret_status); } /******************************************************************************/ static mss_mmc_status_t sd_host_process_switch_function ( uint8_t function_num, uint8_t group_num ) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint8_t tmp_buffer[BLK_SIZE]; uint32_t argument; uint32_t argumentBase = MMC_CLEAR; const uint32_t shift = (((uint32_t)group_num - MMC_SET) * SHIFT_4BIT); if (shift < SHIFT_32BIT) { argumentBase = (uint32_t)(MASK_24BIT & ~(MASK_4BIT << shift)) | ((uint32_t)function_num << shift); } argument = argumentBase | (uint32_t)SDCARD_SWITCH_FUNC_MODE_CHECK; /* first check if function is supported */ ret_status = sd_host_exec_cmd6_command(argument, tmp_buffer, function_num, group_num); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { ret_status = MSS_MMC_SDCARD_NOT_SUPPORT_BUS_MODE; } else if (SDCARD_SWICH_FUNC_GET_STAT_CODE(tmp_buffer, group_num) == MASK_4BIT) { /* if status code for function is 0xF then function is not supported by a card */ ret_status = MSS_MMC_SDCARD_NOT_SUPPORT_BUS_MODE; } else { argument = argumentBase | (uint32_t)SDCARD_SWITCH_FUNC_MODE_SWITCH; /* execute command to switch function */ ret_status = sd_host_exec_cmd6_command(argument, tmp_buffer, function_num, group_num); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { ret_status = MSS_MMC_SDCARD_NOT_SUPPORT_BUS_MODE; } else if (SDCARD_SWICH_FUNC_GET_STAT_CODE(tmp_buffer, group_num) != function_num) { /* Status indicates the same function number as specified in the argument, which means Supported function successful function change. */ ret_status = MSS_MMC_SDCARD_CMD6_SWITCH_ERROR; } else { ret_status = MSS_MMC_TRANSFER_SUCCESS; } } return (ret_status); } /******************************************************************************/ static mss_mmc_status_t sd_tuning(void) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint8_t repeat_count; uint32_t tmp; uint32_t read_pattern[BYTES_128]; tmp = MMC->SRS15; /* reset tuning unit */ tmp &= ~SRS15_SAMPLING_CLOCK_SELECT; /* start of tuning */ tmp |= SRS15_EXECUTE_TUNING; MMC->SRS15 = tmp; repeat_count = BYTES_40; while ((tmp & SRS15_EXECUTE_TUNING) != MMC_CLEAR) { ret_status = read_tune_block(read_pattern, BYTES_64, SD_CMD_19_SEND_TUNING_BLK); if ((repeat_count == MMC_CLEAR) || (ret_status != MSS_MMC_TRANSFER_SUCCESS)) { break; } tmp = MMC->SRS15; --repeat_count; } if ((ret_status == MSS_MMC_TRANSFER_SUCCESS) && ((tmp & SRS15_SAMPLING_CLOCK_SELECT) == MMC_CLEAR)) { ret_status = MSS_MMC_SDCARD_TUNING_FAILED; } /* tuning completed */ return (ret_status); } /******************************************************************************/ static mss_mmc_status_t sd_host_exec_cmd6_command ( uint32_t argument, uint8_t *buffer, uint8_t function_num, uint8_t group_num ) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; volatile uint32_t timeout = COMMANDS_TIMEOUT; uint8_t do_continue = MMC_SET; do { ret_status = cmd6_single_block_read(argument, (uint32_t *)buffer, BYTES_64); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { break; } /* check data structure version if it is 1 then checking the busy status is possible */ if (buffer[17u] == MMC_SET) { /* if function is busy continue loop wait until function will be ready */ if (SDCARD_SWICH_FUNC_GET_BUSY_STAT(buffer, group_num, function_num) == MMC_CLEAR) { do_continue = MMC_CLEAR; } } else { do_continue = MMC_CLEAR; } --timeout; } while ((timeout != MMC_CLEAR) && (do_continue != MMC_CLEAR)); if (timeout == MMC_CLEAR) { ret_status = MSS_MMC_TRANSFER_FAIL; } else { ret_status = MSS_MMC_TRANSFER_SUCCESS; } return (ret_status); } /******************************************************************************/ static mss_mmc_status_t sd_card_uhsi_supported(void) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; const uint8_t group_num = MMC_SET; uint8_t function_num = SDCARD_SWITCH_ACCESS_MODE_SDR50; uint32_t data_c6[BYTES_128]; uint8_t *tmp_buffer = (uint8_t *)data_c6; uint32_t tmp; uint32_t argument = MMC_CLEAR; const uint32_t shift = ((group_num - MMC_SET) * SHIFT_4BIT); if (shift < SHIFT_32BIT) { argument = (uint32_t)(MASK_24BIT & ~(MASK_4BIT << shift)) | ((uint32_t)function_num << shift) | (uint32_t)SDCARD_SWITCH_FUNC_MODE_CHECK; } ret_status = cmd6_single_block_read(argument, data_c6, BYTES_64); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { ret_status = MSS_MMC_SDCARD_NOT_SUPPORT_BUS_MODE; } else if (SDCARD_SWICH_FUNC_GET_STAT_CODE(tmp_buffer, group_num) == MASK_4BIT) { /* if status code for function is 0xF then function is not supported by a card */ ret_status = MSS_MMC_SDCARD_NOT_SUPPORT_BUS_MODE; } else if (SDCARD_SWICH_FUNC_GET_STAT_CODE(tmp_buffer, group_num) == function_num) { MMC->SRS10 |= SRS10_DATA_WIDTH_4BIT; /* disable sd clock */ tmp = MMC->SRS11; tmp &= ~(uint32_t)SRS11_SD_CLOCK_ENABLE; MMC->SRS11 = tmp; /* 1.8V signal enable */ tmp = MMC->SRS15; tmp |= SRS15_18V_ENABLE; MMC->SRS15 = tmp; /* wait 5ms */ mmc_delay(DELAY_COUNT); mmc_delay(DELAY_COUNT); /* if 1.8V signal enable is cleared by host return with error */ tmp = MMC->SRS15; if ((tmp & SRS15_18V_ENABLE) == MMC_CLEAR) { ret_status = MSS_MMC_ERR_SWITCH_VOLTAGE_FAILED; } else { /* internal clock enable */ tmp = MMC->SRS11; tmp |= (uint32_t)SRS11_INT_CLOCK_ENABLE; MMC->SRS11 = tmp; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); mMMC_ARM_TIMEOUT(mmc_spin_timeout); while (MMC_CLEAR == (MMC->SRS11 & SRS11_INT_CLOCK_STABLE)) { mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } /* enable sd clock */ tmp = MMC->SRS11; tmp |= (uint32_t)SRS11_SD_CLOCK_ENABLE; MMC->SRS11 = tmp; /* wait 1ms */ mmc_delay(DELAY_COUNT); ret_status = MSS_MMC_TRANSFER_SUCCESS; } } else { ret_status = MSS_MMC_TRANSFER_FAIL; } return (ret_status); } /******************************************************************************/ static uint8_t is_uhsi_supported(void) { uint8_t result = MMC_SET; uint32_t tmp; tmp = MMC->SRS16; if ((tmp & SRS16_VOLTAGE_1_8V_SUPPORT) == MMC_CLEAR) { result = MMC_CLEAR; } else { tmp = MMC->SRS17; uint32_t uhsi_modes = (uint32_t)(SRS17_SDR50_SUPPORTED | SRS17_SDR104_SUPPORTED | SRS17_DDR50_SUPPORTED); if ((tmp & uhsi_modes) == MMC_CLEAR) { result = MMC_CLEAR; } } return (result); } /******************************************************************************/ static mss_mmc_status_t set_device_hs400_mode(const mss_mmc_cfg_t *cfg) { cif_response_t response_status = TRANSFER_IF_SUCCESS; uint32_t srs10, hrs6; uint32_t hs_timing = MMC_HS200_MODE; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint32_t csd_reg[BLK_SIZE/WORD_SIZE]; uint8_t *pcsd_reg; uint8_t hw_ext_csd_rev; uint8_t hw_device_type; uint8_t hw_hs_timing; uint32_t data_width = cfg->data_bus_width; if (MSS_MMC_DATA_WIDTH_8BIT != data_width) { ret_status = MSS_MMC_TRANSFER_FAIL; return ret_status; } /* set 8-bit bus mode */ srs10 = MMC->SRS10; srs10 |= SRS10_EXTENDED_DATA_TRANSFER_WIDTH; MMC->SRS10 = srs10; /* do HS400 Mode Operation, not HS400_ES */ if (MSS_MMC_MODE_HS400 == cfg->bus_speed_mode) { /* Set MMC data bus width */ response_status = cif_send_cmd(MMC_DW_CSD | (data_width << SHIFT_8BIT), MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } if (TRANSFER_IF_SUCCESS == response_status) { hs_timing = MMC_HS200_MODE; response_status = cif_send_cmd(hs_timing, MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } } if (TRANSFER_IF_SUCCESS == response_status) { /* eMMC Mode select in Host controller */ hrs6 = MMC->HRS06; hrs6 &= ~MSS_MMC_MODE_MASK; hrs6 |= MSS_MMC_MODE_HS200; MMC->HRS06 = hrs6; /* Up the Host MMC clock frequency */ set_host_sdclk(cfg->clk_rate); /* HS200 tuning */ ret_status = execute_tunning_mmc(MSS_MMC_DATA_WIDTH_8BIT); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) return ret_status; ret_status = MSS_MMC_single_block_read(READ_SEND_EXT_CSD, csd_reg); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { pcsd_reg = (uint8_t *)csd_reg; /* offsets defined in JESD84-B51 extended CSD */ g_hw_sec_count = csd_reg[EXT_CSD_SECTOR_COUNT_OFFSET/WORD_SIZE]; hw_ext_csd_rev = pcsd_reg[EXT_CSD_REVISION_OFFSET] & BYTE_MASK; hw_hs_timing = pcsd_reg[EXT_CSD_HS_TIMING_OFFSET]; } else { ret_status = MSS_MMC_TRANSFER_FAIL; return ret_status; } } if (TRANSFER_IF_SUCCESS != response_status) { ret_status = MSS_MMC_TRANSFER_FAIL; return ret_status; } } /* High Speed Mode set */ hs_timing = MMC_HS_MODE; response_status = cif_send_cmd(hs_timing, MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { if (MSS_MMC_MODE_HS400_ES == cfg->bus_speed_mode) { response_status = check_device_status(response_status); } else { uint32_t srs9; do { srs9 = MMC->SRS09; }while ((srs9 & SRS9_DAT0_SIGNAL_LEVEL) == MMC_CLEAR); response_status = TRANSFER_IF_SUCCESS; } } if (TRANSFER_IF_SUCCESS == response_status) { set_host_sdclk(MSS_MMC_CLOCK_50MHZ); /* Enable Host High Speed */ MMC->SRS10 |= (MMC_SET << SHIFT_2BIT); if (MSS_MMC_MODE_HS400 == cfg->bus_speed_mode) { data_width = MMC_DUAL_DATA_WIDTH_8BIT; } else if (MSS_MMC_MODE_HS400_ES == cfg->bus_speed_mode) { /* Enable strobe support*/ data_width = MMC_ES_DUAL_DATA_WIDTH_8BIT; } else { data_width = MMC_DUAL_DATA_WIDTH_8BIT; } /* Set MMC data bus width */ response_status = cif_send_cmd(MMC_DW_CSD | (data_width << SHIFT_8BIT), MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } if (TRANSFER_IF_SUCCESS == response_status) { /* eMMC Mode select in Host controller */ hrs6 = MMC->HRS06; hrs6 &= ~MSS_MMC_MODE_MASK; hrs6 |= MSS_MMC_MODE_DDR; MMC->HRS06 = hrs6; set_host_sdclk(MSS_MMC_CLOCK_50MHZ); /* Set HS400 mode */ hs_timing = MMC_HS400_MODE; response_status = cif_send_cmd(hs_timing, MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } if (TRANSFER_IF_SUCCESS == response_status) { /* eMMC Mode select in Host controller */ hrs6 = MMC->HRS06; hrs6 &= ~MSS_MMC_MODE_MASK; if (MSS_MMC_MODE_HS400 == cfg->bus_speed_mode) { hrs6 |= MSS_MMC_MODE_HS400; } else if (MSS_MMC_MODE_HS400_ES == cfg->bus_speed_mode) { hrs6 |= MSS_MMC_MODE_HS400_ES; } else { hrs6 = MMC_CLEAR; } MMC->HRS06 = hrs6; /* Up the Host MMC clock frequency */ set_host_sdclk(cfg->clk_rate); ret_status = MSS_MMC_single_block_read(MMC_CLEAR, (uint32_t *)csd_reg); if (MSS_MMC_TRANSFER_SUCCESS != ret_status) { ret_status = MSS_MMC_TRANSFER_FAIL; } } } } if (TRANSFER_IF_SUCCESS != response_status) { ret_status = MSS_MMC_TRANSFER_FAIL; } /* variable set but unused, so referencing to avoid compiler warning */ (void)hw_ext_csd_rev; (void)hw_device_type; (void)hw_hs_timing; return (ret_status); } /******************************************************************************/ static mss_mmc_status_t device_set_hs_timing(uint32_t hs_mode, const mss_mmc_cfg_t * cfg) { cif_response_t response_status = TRANSFER_IF_SUCCESS; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint32_t srs10, hrs6; volatile uint32_t hs_timing = MMC_HS_MODE_DEFAULT; uint8_t phy_delay_type; uint32_t data_width = cfg->data_bus_width; /* set 4/8-bit bus mode */ srs10 = MMC->SRS10; if (data_width == MSS_MMC_DATA_WIDTH_4BIT) { srs10 |= SRS10_DATA_WIDTH_4BIT; } else if (data_width == MSS_MMC_DATA_WIDTH_8BIT) { srs10 |= SRS10_EXTENDED_DATA_TRANSFER_WIDTH; } else { srs10 &= ~SRS10_DATA_WIDTH_4BIT; srs10 &= ~SRS10_EXTENDED_DATA_TRANSFER_WIDTH; } MMC->SRS10 = srs10; switch (hs_mode) { case DEVICE_SUPPORT_LEGACY: hs_timing = MMC_LEGACY_MODE; phy_delay_type = MSS_MMC_PHY_DELAY_INPUT_MMC_LEGACY; if (cfg->clk_rate > MSS_MMC_CLOCK_26MHZ) { response_status = TRANSFER_IF_FAIL; } break; case DEVICE_SUPPORT_SDR: hs_timing = MMC_HS_MODE; phy_delay_type = MSS_MMC_PHY_DELAY_INPUT_MMC_SDR; break; case DEVICE_SUPPORT_DDR: hs_timing = MMC_HS_MODE; phy_delay_type = MSS_MMC_PHY_DELAY_INPUT_MMC_DDR; if (MSS_MMC_DATA_WIDTH_8BIT == data_width) { data_width = MMC_DUAL_DATA_WIDTH_8BIT; } else if (MSS_MMC_DATA_WIDTH_4BIT == data_width) { data_width = MMC_DUAL_DATA_WIDTH_4BIT; } else { response_status = TRANSFER_IF_FAIL; } break; case DEVICE_SUPPORT_HS200: hs_timing = MMC_HS200_MODE; if (MSS_MMC_DATA_WIDTH_1BIT == data_width) { response_status = TRANSFER_IF_FAIL; } break; default: response_status = TRANSFER_IF_FAIL; break; } if (TRANSFER_IF_SUCCESS == response_status) { if (DEVICE_SUPPORT_DDR == hs_mode) { response_status = cif_send_cmd(hs_timing, MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); if (TRANSFER_IF_SUCCESS == response_status) { /* Set MMC data bus width */ response_status = cif_send_cmd(MMC_DW_CSD | (data_width << SHIFT_8BIT), MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } } } } else if (DEVICE_SUPPORT_LEGACY == hs_mode) { /* Set MMC data bus width */ response_status = cif_send_cmd(MMC_DW_CSD | (data_width << SHIFT_8BIT), MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } } else { /* Set MMC data bus width */ response_status = cif_send_cmd(MMC_DW_CSD | (data_width << SHIFT_8BIT), MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); if (TRANSFER_IF_SUCCESS == response_status) { response_status = cif_send_cmd(hs_timing, MMC_CMD_6_SWITCH, MSS_MMC_RESPONSE_R1B); if (TRANSFER_IF_FAIL != response_status) { response_status = check_device_status(response_status); } } } } if (TRANSFER_IF_SUCCESS == response_status) { /* eMMC Mode select in Host controller */ hrs6 = MMC->HRS06; hrs6 &= ~MSS_MMC_MODE_MASK; hrs6 |= cfg->bus_speed_mode; MMC->HRS06 = hrs6; /* Up the Host MMC clock frequency */ set_host_sdclk(cfg->clk_rate); if(DEVICE_SUPPORT_HS200 == hs_mode) { ret_status = MSS_MMC_TRANSFER_SUCCESS; } else { /* Set Phy delay for select MMC mode */ ret_status = phy_training_mmc(phy_delay_type, cfg->clk_rate); if (ret_status != MSS_MMC_TRANSFER_SUCCESS) { response_status = TRANSFER_IF_FAIL; } } } } if (TRANSFER_IF_SUCCESS != response_status) { ret_status = MSS_MMC_TRANSFER_FAIL; } return (ret_status); } /******************************************************************************/ static uint8_t set_host_sdclk(uint32_t frequencyKHz) { uint32_t temp, temp1; uint32_t baseclkkHz; uint32_t i; uint32_t setFreqKhz; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); /* disable sd clock */ temp = MMC->SRS11; temp &= ~(uint32_t)SRS11_SD_CLOCK_ENABLE; MMC->SRS11 = temp; /* read base clock frequency for SD clock in kilo herz */ temp = MMC->SRS16; baseclkkHz = ((temp & 0x0000FF00u) >> 8U) * 1000u; if (baseclkkHz == 0u) { return 1u; } /* read current value of SRS11 register */ temp = MMC->SRS11; /* clear old frequency base settings */ temp &= ~(uint32_t)SRS11_SEL_FREQ_BASE_MASK; /* 10-bit Divider Clock Mode */ for (i = 1u; i < 2046u; i++) { if (((baseclkkHz / i) < frequencyKHz) || (((baseclkkHz / i) == frequencyKHz) && ((baseclkkHz % i) == 0u))) { break; } } temp1 = ((i / 2u) << 8); /* Set SDCLK Frequency Select and Internal Clock Enable */ temp |= (temp1 & 0xFF00u) | ((temp1 & 0x30000u) >> 10) | (uint32_t)SRS11_INT_CLOCK_ENABLE; temp &= ~(uint32_t)SRS11_CLOCK_GENERATOR_SELECT; setFreqKhz = baseclkkHz / i; MMC->SRS11 = temp; mMMC_ARM_TIMEOUT(mmc_spin_timeout); while ((MMC->SRS11 & SRS11_INT_CLOCK_STABLE) == 0u) { mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } /* enable sd clock */ temp = MMC->SRS11; temp |= (uint32_t)SRS11_SD_CLOCK_ENABLE; MMC->SRS11 = temp; (void)setFreqKhz; // variable set but unused, so referencing to avoid compiler warning return 0; } /******************************************************************************/ static mss_mmc_status_t set_data_timeout(uint32_t timeout_val_us) { mss_mmc_status_t status = MSS_MMC_NO_ERROR; uint32_t temp, sdmclk_khz, sdmclk_Mhz, timeout_interval; uint8_t j; uint32_t sdmclk, timeoutVal; temp = MMC->SRS16; sdmclk_khz = (temp & 0x0000003Fu);/* 0x4u; - 0x4 is dummy -> 50Mhz * 4 = 200Mhz, */ if (((temp & SRS16_TIMEOUT_CLOCK_UNIT_MHZ) == 0u) && (timeout_val_us < 1000u)) { status = MSS_MMC_INVALID_PARAMETER; } else if (sdmclk_khz == 0u) { status = MSS_MMC_BASE_CLK_IS_ZERO_ERR; } else { if ((temp & SRS16_TIMEOUT_CLOCK_UNIT_MHZ) != 0u) { sdmclk_khz *= 1000u; } sdmclk_Mhz = sdmclk_khz / 1000u; if (sdmclk_Mhz == 0u) { sdmclk = sdmclk_khz; timeoutVal = timeout_val_us / 1000u; } else { sdmclk = sdmclk_Mhz; timeoutVal = timeout_val_us; } /* calculate data Timeout Counter Value */ timeout_interval = 8192u/*2 ^ 13*/; for (j = 0u; j < 15u; j++) { /* if (timeoutVal < ((1 / sdmclk) * timeout_interval)) */ if (timeoutVal < (timeout_interval / sdmclk)) { break; } timeout_interval *= 2u; } timeout_interval = (uint32_t)j << 16u; temp = MMC->SRS11; temp &= (uint32_t)~SRS11_TIMEOUT_MASK; temp |= timeout_interval; MMC->SRS11 = temp; } return (status); } /******************************************************************************/ static mss_mmc_status_t set_sdhost_power(uint32_t voltage) { uint32_t temp, srs16; mss_mmc_status_t status = MSS_MMC_NO_ERROR; /* disable SD bus power */ temp = MMC->SRS10; temp &= ~SRS10_SD_BUS_POWER; MMC->SRS10 = temp; /*clear current voltage settings*/ temp &= ~SRS10_BUS_VOLTAGE_MASK; srs16 = MMC->SRS16; /* if Voltage == 0 * disable bus power * power is disabled so do nothing, return no error */ if (voltage != MMC_CLEAR) { switch (voltage) { case SRS10_SET_3_3V_BUS_VOLTAGE: if ((srs16 & SRS16_VOLTAGE_3_3V_SUPPORT) == MMC_CLEAR) { status = MSS_MMC_INVALID_PARAMETER; break; } /* set new voltage value */ temp |= (SRS10_SET_3_3V_BUS_VOLTAGE | SRS10_SD_BUS_POWER); break; case SRS10_SET_3_0V_BUS_VOLTAGE: if ((srs16 & SRS16_VOLTAGE_3_0V_SUPPORT) == MMC_CLEAR) { status = MSS_MMC_INVALID_PARAMETER; break; } /* set new voltage value */ temp |= (SRS10_SET_3_0V_BUS_VOLTAGE | SRS10_SD_BUS_POWER); break; case SRS10_SET_1_8V_BUS_VOLTAGE: if ((srs16 & SRS16_VOLTAGE_1_8V_SUPPORT) == MMC_CLEAR) { status = MSS_MMC_INVALID_PARAMETER; break; } /* set new voltage value */ temp |= (SRS10_SET_1_8V_BUS_VOLTAGE | SRS10_SD_BUS_POWER); break; default: status = MSS_MMC_INVALID_PARAMETER; break; } if (status == MSS_MMC_NO_ERROR) { MMC->SRS10 = temp; } mmc_delay(DELAY_COUNT); } return (status); } /******************************************************************************/ static void mmc_delay(uint32_t value) { while (value--) asm volatile(""); } /******************************************************************************/ static mss_mmc_status_t cmd6_single_block_read(uint32_t src_addr, uint32_t * dst_addr, uint32_t size) { uint32_t isr_errors; uint32_t blk_read, srs03_data, srs9; uint16_t word_cnt = (BLK_SIZE/WORD_SIZE); uint32_t idx_cnt = MMC_CLEAR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; /* Block length and count*/ MMC->SRS01 = (size | (MMC_SET << BLOCK_COUNT_ENABLE_SHIFT)); /* DPS, Data transfer direction - read */ srs03_data = (uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_READ |SRS3_BLOCK_COUNT_ENABLE | SRS3_RESP_ERR_CHECK_EN | SRS3_RESP_INTER_DISABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN); /* Check cmd and data line busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((srs9 & (SRS9_CMD_INHIBIT_CMD | SRS9_CMD_INHIBIT_DAT)) != MMC_CLEAR); word_cnt = (size/WORD_SIZE); /* Command argument */ MMC->SRS02 = src_addr; /* execute command */ MMC->SRS03 = (uint32_t)((SD_CMD_6 << MMC_SRS03_COMMAND_SHIFT) | srs03_data); idx_cnt = MMC_CLEAR; mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { blk_read = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (MMC_CLEAR == (blk_read & (SRS12_BUFFER_READ_READY | SRS12_ERROR_INTERRUPT))); /* Read in the contents of the Buffer */ if ((blk_read & SRS12_BUFFER_READ_READY) != MMC_CLEAR) { while (word_cnt > (BUFF_EMPTY)) { dst_addr[idx_cnt] = MMC->SRS08; ++idx_cnt; --word_cnt; } } isr_errors = MMC->SRS12; /* Abort if any errors*/ if ((SRS12_ERROR_STATUS_MASK & isr_errors) == MMC_CLEAR) { ret_status = MSS_MMC_TRANSFER_SUCCESS; } else { ret_status = MSS_MMC_ERR_INTERRUPT; } /* Clear all status interrupts except: * current limit error, card interrupt, card removal, card insertion */ MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR | SRS12_CARD_INTERRUPT | SRS12_CARD_REMOVAL | SRS12_CARD_INSERTION); return (ret_status); } /******************************************************************************/ static mss_mmc_status_t execute_tunning_mmc(uint8_t data_width) { mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; uint32_t ReadPattern[128u]; uint8_t i, j, PatternOk[40u]; uint8_t Pos; uint8_t BufferSize = (data_width == MSS_MMC_DATA_WIDTH_4BIT)? 64u:128u; uint32_t const *WritePattern = calc_write_pattern(data_width); for (j = 0u; j < 40u; j++) { host_mmc_tune(j); mmc_delay(0xFFu); for (i = 0u; i < (BufferSize / 4u); i++) { ReadPattern[i] = 0u; } ret_status = read_tune_block(ReadPattern, BufferSize, MMC_CMD_21_SEND_TUNE_BLK); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { /* compare data with pattern */ PatternOk[j] = 1u; for (i = 0u; i < (BufferSize / 4u); i++) { if (WritePattern[i] != ReadPattern[i]) { PatternOk[j] = 0u; /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; /* read pattern is not correct - exit loop */ break; } } } else { /* Reset Data and cmd line */ MMC->SRS11 |= MMC_RESET_DATA_CMD_LINE; PatternOk[j] = 0u; } } Pos = calc_longest_valid_delay_chain_val(PatternOk); /* Delay value set to Pos */ host_mmc_tune(Pos); mmc_delay(0xFFFu); ret_status = read_tune_block(ReadPattern, BufferSize, MMC_CMD_21_SEND_TUNE_BLK); return (ret_status); } /******************************************************************************/ static mss_mmc_status_t read_tune_block(uint32_t *read_data, uint32_t size, uint8_t cmd) { uint32_t isr_errors; uint32_t blk_read, srs03_data, srs9; uint16_t word_cnt = (BLK_SIZE/WORD_SIZE); uint32_t idx_cnt = MMC_CLEAR; mss_mmc_status_t ret_status = MSS_MMC_NO_ERROR; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); /* Clear all status interrupts */ MMC->SRS12 = MMC_STATUS_CLEAR; /* Block length and count*/ MMC->SRS01 = (size | (MMC_SET << BLOCK_COUNT_ENABLE_SHIFT)); /* DPS, Data transfer direction - read */ srs03_data = (uint32_t)(SRS3_DATA_PRESENT | SRS3_TRANS_DIRECT_READ |SRS3_BLOCK_COUNT_ENABLE | SRS3_RESP_ERR_CHECK_EN | SRS3_RESP_INTER_DISABLE | SRS3_RESPONSE_CHECK_TYPE_R1 | SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN); /* Check cmd and data line busy */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while ((srs9 & (SRS9_CMD_INHIBIT_CMD | SRS9_CMD_INHIBIT_DAT)) != MMC_CLEAR); word_cnt = size/WORD_SIZE; /* Command argument */ MMC->SRS02 = MMC_CLEAR; /* execute command */ MMC->SRS03 = (uint32_t)((cmd << MMC_SRS03_COMMAND_SHIFT) | srs03_data); idx_cnt = MMC_CLEAR; mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { blk_read = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, MSS_MMC_NOT_INITIALISED); } while (MMC_CLEAR == (blk_read & (SRS12_BUFFER_READ_READY | SRS12_ERROR_INTERRUPT))); /* Read in the contents of the Buffer */ if ((blk_read & SRS12_BUFFER_READ_READY) != MMC_CLEAR) { while (word_cnt > (BUFF_EMPTY)) { read_data[idx_cnt] = MMC->SRS08; ++idx_cnt; --word_cnt; } } isr_errors = MMC->SRS12; /* Abort if any errors*/ if ((SRS12_ERROR_STATUS_MASK & isr_errors) == MMC_CLEAR) { ret_status = MSS_MMC_TRANSFER_SUCCESS; } else { ret_status = MSS_MMC_ERR_INTERRUPT; } /* Clear all status interrupts */ MMC->SRS12 = MMC_STATUS_CLEAR; return (ret_status); } /******************************************************************************/ static const uint32_t* calc_write_pattern(const uint8_t bus_width) { static const uint32_t emmc_pattern4b[64 / 4] = { 0x00ff0fffU, 0xccc3ccffU, 0xffcc3cc3U, 0xeffefffeU, 0xddffdfffU, 0xfbfffbffU, 0xff7fffbfU, 0xefbdf777U, 0xf0fff0ffU, 0x3cccfc0fU, 0xcfcc33ccU, 0xeeffefffU, 0xfdfffdffU, 0xffbfffdfU, 0xfff7ffbbU, 0xde7b7ff7U }; static const uint32_t emmc_pattern8b[128 / 4] = { 0xff00ffffU, 0x0000ffffU, 0xccccffffU, 0xcccc33ccU, 0xcc3333ccU, 0xffffccccU, 0xffffeeffU, 0xffeeeeffU, 0xffddffffU, 0xddddffffU, 0xbbffffffU, 0xbbffffffU, 0xffffffbbU, 0xffffff77U, 0x77ff7777U, 0xffeeddbbU, 0x00ffffffU, 0x00ffffffU, 0xccffff00u, 0xcc33ccccU, 0x3333ccccU, 0xffccccccU, 0xffeeffffU, 0xeeeeffffU, 0xddffffffU, 0xddffffffU, 0xffffffddU, 0xffffffbbU, 0xffffbbbbU, 0xffff77ffU, 0xff7777ffU, 0xeeddbb77U }; const uint32_t* write_pattern = NULL_POINTER; if ((uint8_t)MSS_MMC_DATA_WIDTH_8BIT == bus_width) { write_pattern = (const uint32_t*)emmc_pattern8b; } if ((uint8_t)MSS_MMC_DATA_WIDTH_4BIT == bus_width) { write_pattern = (const uint32_t*)emmc_pattern4b; } return (write_pattern); } /******************************************************************************/ static void host_mmc_tune(uint8_t value) { uint32_t hrs6, read_data; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); hrs6 = MMC->HRS06; hrs6 &= ~HRS6_EMMC_TUNE_VALUE_MASK; hrs6 |= (uint32_t)((value << SHIFT_8BIT) | HRS6_EMMC_TUNE_REQUEST); MMC->HRS06 = hrs6; mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { read_data = MMC->HRS06; mMMC_CHECK_TIMEOUT(mmc_spin_timeout); } while ((read_data & HRS6_EMMC_TUNE_REQUEST) != MMC_CLEAR); } /******************************************************************************/ static uint8_t calc_longest_valid_delay_chain_val(const uint8_t* pattern_ok) { /* looking for longest valid delay chain value (the best tuning value) */ uint8_t pos = 0u; uint8_t length = 0u; uint8_t curr_length = 0u; uint8_t i; for (i = 0u; i < 40u; i++) { if (pattern_ok[i] == 1u) { curr_length++; if (curr_length > length) { pos = i - length; length++; } } else { curr_length = 0u; } } pos += (length / 2u); return (pos); } /******************************************************************************/ static cif_response_t check_device_status(cif_response_t rsp_status) { uint32_t srs9; mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { srs9 = MMC->SRS09; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, TRANSFER_IF_FAIL); } while ((srs9 & SRS9_DAT0_SIGNAL_LEVEL) == MMC_CLEAR); /* * Writing to the EXT CSD register takes significant time, * so function must not return until the 'READY FOR DATA' * bit is set in the Card Status Register. */ mMMC_ARM_TIMEOUT(mmc_spin_timeout); while (DEVICE_BUSY == rsp_status) { rsp_status = cif_send_cmd(sdcard_RCA << RCA_SHIFT_BIT, MMC_CMD_13_SEND_STATUS, MSS_MMC_RESPONSE_R1); mMMC_CHECK_TIMEOUT(mmc_spin_timeout, TRANSFER_IF_FAIL); } return (rsp_status); } /******************************************************************************/ static uint32_t get_srs_bits(int from, int count) { volatile uint32_t *resp = &MMC->SRS04; uint32_t mask, ret; int off, shft; from -= 8; mask = (count < 32 ? 1 << count : 0) - 1; off = from / 32; shft = from & 31; ret = resp[off] >> shft; if (from + shft > 32) { ret |= resp[off + 1] << (32 - shft) % 32; } return ret & mask; } /******************************************************************************/ #ifdef __cplusplus } #endif mss_mmc.h000066400000000000000000001323561432224323300365320ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC MSS eMMC SD bare metal software driver public API. * * SVN $Revision: 12579 $ * SVN $Date: 2019-12-04 16:41:30 +0530 (Wed, 04 Dec 2019) $ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS eMMC SD Bare Metal Driver ============================================================================== Introduction ============================================================================== The PolarFire SoC MSS includes an SD host controller and an eMMC/SD PHY. The SD Host Controller can support multiple eMMC/SD standards with bus widths of 1 bit, 4 bits, and 8 bits at clock rates up to 200 MHz. The PolarFire SoC MSS eMMC SD software driver, provided as C source code, supports a set of functions for controlling eMMC/SD as part of a bare-metal system where no operating system is available. The driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of the driver. The PolarFire SoC MSS eMMC SD driver provides the following features: - Configuring the eMMC/SD/SDIO - Single block read and write without DMA. - Multiple or single block read and write with DMA (SDMA, ADMA2). - eMMC command queue block read and write. - eMMC standards LEGACY, SDR, DDR, HS200, HS400 and HS400-ES - SD card standards Default Speed(DS), High Speed(HS), UHS-I(SDR12, SDR25, SDR50, SDR104, DDR50). - Single block read and write operation for SDIO. ============================================================================== Theory of Operation ============================================================================== The PolarFire SoC MSS eMMC SD driver functions allow 512-byte blocks of data to be written to and read from a eMMC/SD device connected to the host controller. The blocks can be read/written singly or using the multi block functions. There are two variants of the single block functions. One set are blocking, the other are non-blocking. The multi block functions are non-blocking. Note: The eMMC/SD device connected to the eMMC/SD host hardware must support a sector size of 512-bytes. This is the default block size for the eMMC/SD device > 2GB. The PolarFire SoC MSS eMMC SD driver functions are grouped into the following categories: - Initialization - Block Transfer Control - Block Transfer Status - Interrupt Handling - Command Queue -------------------------------- Initialization -------------------------------- The initialization of the MSS eMMC SD driver involves the following steps: - Initialize the mss_mmc_cfg_t data structure. - Call the MSS_MMC_init() function. The configuration data structure mss_mmc_cfg_t should set eMMC/SD/SDIO clock frequency, data width, card type and speed before calling the MSS_MMC_init() function. The MSS_MMC_init() function takes a pointer to the configuration data structure of type mss_mmc_cfg_t. The MSS_MMC_sector_count_get() returns the umber of sectors available on the eMMC or SD card.. -------------------------------- Block Transfer Control -------------------------------- The following functions are used for block read and write: - MSS_MMC_single_block_read() - MSS_MMC_single_block_write() - MSS_MMC_sdma_read() - MSS_MMC_sdma_write() - MSS_MMC_adma2_read() - MSS_MMC_adma2_write() - MSS_MMC_sdio_single_block_read() - MSS_MMC_sdio_single_block_write() Write Transfer To write a single block of data to the eMMC/SD device, a call is made to the MSS_MMC_single_block_write() function. To write a single block or multiple blocks of data to the eMMC/SD device, using DMA, a call is made to the MSS_MMC_sdma_write() or MSS_MMC_adma2_write() functions. To write a single block of data to the SDIO device, a call is made to the MSS_MMC_sdio_single_block_write() function. Read Transfer To read a single block of data stored within the eMMC/SD device, a call is made to the MSS_MMC_single_block_read() function. To read a single block or multiple blocks of data stored within the eMMC/SD device, using DMA, a call is made to the MSS_MMC_sdma_read() or MSS_MMC_adma2_read() functions. To read a single block of data stored within the SDIO device, a call is made to the MSS_MMC_sdio_single_block_read() function. -------------------------------- Block Transfer Status -------------------------------- The status of the eMMC SD block read or write transfer can be retrieved using the MSS_MMC_get_transfer_status() function. -------------------------------- Interrupt Handling -------------------------------- The MSS_MMC_set_handler() function is used to register a handler function that will be called by the driver when a block transfer completes. The driver passes the outcome of the transfer to the completion handler in the form of a status parameter indicating if the transfer was successful or the type of error that occurred during the transfer. The application must create and register a transfer completion handler function to suit the application. -------------------------------- Command Queue -------------------------------- The following functions are used for eMMC command queue operation: - MSS_MMC_cq_init() - MSS_MMC_cq_write() - MSS_MMC_cq_read() The MSS_MMC_cq_init() function initializes command queue in the eMMC device and the host controller. To write a single block or multiple blocks of data to the eMMC device using a command queue, a call is made to the MSS_MMC_cq_write() function. This function supports up to 32 tasks. To read a single block or multiple blocks of data stored within the eMMC device using a command queue, a call is made to the MSS_MMC_cq_read() function. This function supports up to 32 tasks. *//*=========================================================================*/ #ifndef __MSS_MMC_H #define __MSS_MMC_H #include "hal/cpu_types.h" #ifdef __cplusplus extern "C" #endif /*----------------------------------------------------------------------------*/ /* Clock rate*/ #define MSS_MMC_CLOCK_400KHZ 400u #define MSS_MMC_CLOCK_12_5MHZ 12500u #define MSS_MMC_CLOCK_25MHZ 25000u #define MSS_MMC_CLOCK_26MHZ 26000u #define MSS_MMC_CLOCK_50MHZ 50000u #define MSS_MMC_CLOCK_70MHZ 70000u #define MSS_MMC_CLOCK_100MHZ 100000u #define MSS_MMC_CLOCK_200MHZ 200000u /* card type */ #define MSS_MMC_CARD_TYPE_NONE 0u #define MSS_MMC_CARD_TYPE_MMC 1u #define MSS_MMC_CARD_TYPE_SD 2u #define MSS_MMC_CARD_TYPE_SDIO 3u #define MSS_MMC_CARD_TYPE_COMBO 4u /* Host controller eMMC mode select */ /* High-speed single data rate supports clock frequency up to 52 MHz and data * bus width of 1 bit, 4 bits, and 8 bits. */ #define MSS_MMC_MODE_SDR 0x2u /* High speed double data rate supports clock frequency up to 52 MHz and data * bus width of 4 bits and 8 bits. */ #define MSS_MMC_MODE_DDR 0x3u /* SDR data sampling supports clock frequency up to 200 MHz and data bus width * of 4 bits and 8 bits. */ #define MSS_MMC_MODE_HS200 0x4u /* DDR data sampling supports clock frequency up to 200 MHz and data bus width * of 8 bits. */ #define MSS_MMC_MODE_HS400 0x5u /* HS400 mode with Enhanced Strobe. */ #define MSS_MMC_MODE_HS400_ES 0x6u /* Backwards compatibility with legacy MMC card supports clock frequency up to * 26MHz and data bus width of 1 bit, 4 bits, and 8 bits. */ #define MSS_MMC_MODE_LEGACY 0x7u #define MSS_MMC_MODE_MASK 0x00000007u #define MSS_MMC_MODE_SDCARD 0x0u /* Host controller SD/SDIO card mode select */ /* Default speed supports clock frequency up to 25 MHz and data bus width of * 4 bits. */ #define MSS_SDCARD_MODE_DEFAULT_SPEED 0x8u /* High-speed supports clock frequency up to 50 MHz and data bus width of * 4 bits. */ #define MSS_SDCARD_MODE_HIGH_SPEED 0x9u /* Ultra-High speed-I (UHS-I) single data rate supports clock frequency up to * 25 MHz and data bus width of 4 bits. */ #define MSS_SDCARD_MODE_SDR12 0xAu /* Ultra-High speed-I (UHS-I) single data rate supports clock frequency up to * 50 MHz and data bus width of 4 bits. */ #define MSS_SDCARD_MODE_SDR25 0xBu /* Ultra-High speed-I (UHS-I) single data rate supports clock frequency up to * 100 MHz and data bus width of 4 bits. */ #define MSS_SDCARD_MODE_SDR50 0xCu /* Ultra-High speed-I (UHS-I) single data rate supports clock frequency up to * 208 MHz and data bus width of 4 bits. */ #define MSS_SDCARD_MODE_SDR104 0xDu /* Ultra-High speed-I (UHS-I) double data rate supports clock frequency up to * 50 MHz and data bus width of 4 bits. */ #define MSS_SDCARD_MODE_DDR50 0xEu /* Host controller data width */ #define MSS_MMC_DATA_WIDTH_1BIT 0x00u #define MSS_MMC_DATA_WIDTH_4BIT 0x01u #define MSS_MMC_DATA_WIDTH_8BIT 0x02u /* eMMC bus voltage */ /* 1.8v */ #define MSS_MMC_1_8V_BUS_VOLTAGE 18u /* 3.3v */ #define MSS_MMC_3_3V_BUS_VOLTAGE 33u #define MSS_SDIO_FUNCTION_NUMBER_0 0u #define MSS_SDIO_FUNCTION_NUMBER_1 1u #define MSS_SDIO_FUNCTION_NUMBER_2 2u #define MSS_SDIO_FUNCTION_NUMBER_3 3u #define MSS_SDIO_FUNCTION_NUMBER_4 4u #define MSS_SDIO_FUNCTION_NUMBER_5 5u #define MSS_SDIO_FUNCTION_NUMBER_6 6u #define MSS_SDIO_FUNCTION_NUMBER_7 7u /*-------------------------------------------------------------------------*//** The mss_mmc_status_t type is used to indicate the return status of the eMMC/SD data transfer. A variable of this type is returned by the MSS_MMC_init(), MSS_MMC_single_block_write(), MSS_MMC_single_block_read(), MSS_MMC_sdma_write(), MSS_MMC_sdma_read(), MSS_MMC_adma2_write(), MSS_MMC_adma2_read(), MSS_MMC_cq_init(), MSS_MMC_cq_write(), MSS_MMC_cq_read(), MSS_MMC_sdio_single_block_read(), MSS_MMC_sdio_single_block_write() functions. */ typedef enum { MSS_MMC_INIT_SUCCESS = 0u, MSS_MMC_INIT_FAILURE, MSS_MMC_NOT_INITIALISED, MSS_MMC_TRANSFER_IN_PROGRESS, MSS_MMC_TRANSFER_FAIL, MSS_MMC_TRANSFER_SUCCESS, MSS_MMC_DWIDTH_ERR, MSS_MMC_RCA_ERROR, MSS_MMC_CID_RESP_ERR, MSS_MMC_OP_COND_ERR, MSS_MMC_RESET_ERR, MSS_MMC_CRC_ERR, MSS_MMC_UNSUPPORTED_HW_REVISION, MSS_MMC_INVALID_PARAMETER, MSS_MMC_NO_ERROR, MSS_MMC_BASE_CLK_IS_ZERO_ERR, MSS_MMC_CARD_STATE_STABLE_ERR, MSS_MMC_CARD_INSERTED_ERR, MSS_MMC_MODE_NOT_SUPPORT_DATAWIDTH, MSS_MMC_CLK_DIV_ERR, MSS_MMC_RESPONSE_ERROR, MSS_MMC_ERR_INTERRUPT, MSS_MMC_ERR_SWITCH_VOLTAGE_FAILED, MSS_MMC_CARD_SELECT_ERROR, MSS_MMC_CARD_SELECT_SUCCESS, MSS_MMC_DEVICE_NOT_SUPPORT_HS400, MSS_MMC_DEVICE_NOT_SUPPORT_HS200, MSS_MMC_DEVICE_NOT_SUPPORT_DDR, MSS_MMC_DEVICE_NOT_SUPPORT_SDR, MSS_MMC_DEVICE_NOT_SUPPORT_LOW_POWER, MSS_MMC_HS400_MODE_SETUP_FAILURE, MSS_MMC_DEVICE_NOT_SUPPORT_CQ, MSS_MMC_CQ_INIT_FAILURE, MSS_MMC_CQ_NOT_INITIALISED, MSS_MMC_SDCARD_NOT_SUPPORT_SPEED, MSS_MMC_SDCARD_NOT_SUPPORT_VOLTAGE, MSS_MMC_SDCARD_NOT_SUPPORT_BUS_MODE, MSS_MMC_SDCARD_CMD6_SWITCH_ERROR, MSS_MMC_SDCARD_TUNING_FAILED, MSS_MMC_SDIO_ERR_BUS_SPEED_UNSUPP, MSS_MMC_DEVICE_NOT_SUPPORT_HPI, MSS_MMC_DEVICE_IS_NOT_IN_HPI_MODE, MSS_MMC_DEVICE_HPI_NOT_DISABLED, MSS_MMC_DATA_SIZE_IS_NOT_MULTI_BLOCK, MSS_MMC_DEVICE_ERROR } mss_mmc_status_t; /*-------------------------------------------------------------------------*//** The mss_mmc_cfg_t type provides the prototype for the configuration values of the MSS eMMC SD driver. The application need to create a record of this type to hold the configuration of the eMMC/SD/SDIO. The MSS_MMC_init() function initializes the MSS eMMC SD using this structure. A pointer to an initialized of this structure should be passed as the first parameter to the MSS_MMC_init() function. */ typedef struct { /* Specifies the clock frequency of the eMMC/SD/SDIO devices */ uint32_t clk_rate; /* Specifies the card type is the eMMC/SD/SDIO */ uint8_t card_type; /* Specifies the data bus width of the eMMC/SD/SDIO */ uint8_t data_bus_width; /* Specifies the bus speed mode of the eMMC/SD/SDIO */ uint8_t bus_speed_mode; /* Specifies the bus voltage for eMMC */ uint8_t bus_voltage; } mss_mmc_cfg_t; /*-------------------------------------------------------------------------*//** This type definition specifies the prototype of a function that can be registered with this driver as a eMMC/SD transfer completion handler function through a call to MSS_MMC_set_handler(). The eMMC/SD transfer completion handler will be called by the driver when an eMMC/SD transfer completes. The PolarFire SoC MSS eMMC SD driver passes the outcome of the transfer to the completion handler in the form of a status parameter indicating if the transfer is successful or the type of error that occurred during the transfer. */ typedef void (*mss_mmc_handler_t)(uint32_t status); /*-----------------------------Public APIs------------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_MMC_init() function initializes the MSS eMMC SD host controller and the eMMC/SD/SDIO device. The MSS_MMC_init()function takes a pointer to a configuration data structure of type mss_mmc_cfg_t as parameter. This configuration data structure contains all the information required to configure the MSS eMMC SD. The configuration passed to the MSS_MMC_init() function specifies the type of interface used to connect the MSS eMMC SD host controller and the eMMC/SD/SDIO device. It also specifies the allowed clock frequency, data bus width and bus speed mode. The MSS_MMC_init() function must be called prior to any MSS eMMC SD data transfer functions being called. @param cfg This parameter is a pointer to a data structure of type mss_mmc_cfg_t containing the MSS eMMC SD desired configuration. The application must fill the configuration data structure parameters before passing it as parameter to the call to the MSS_MMC_init() function. @return This function returns the initialization status of the eMMC/SD/SDIO device as a value of type mss_mmc_status_t. Example: The following example shows how to initialize the eMMC device and configure the data rate 25Mhz. @code mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { //... } @endcode */ mss_mmc_status_t MSS_MMC_init ( const mss_mmc_cfg_t * cfg ); /*-------------------------------------------------------------------------*//** The function MSS_MMC_get_info() returns the sector size and count of the eMMC or .SD card @param sector_size This parameter is a pointer to the data containing the sector size in bytes. @param sector_count This parameter is a pointer to the data containing the sector count. @return This function returns the size and the number of sectors read from the device. */ void MSS_MMC_get_info ( uint16_t *sector_size, uint32_t *sector_count ); /*-------------------------------------------------------------------------*//** The MSS_MMC_single_block_write() function is used to transmit a single block of data from the host controller to the eMMC/SD device. The size of the block of data transferred by this function is always 512 bytes, which is the standard sector size for all eMMC/SD devices with a capacity of greater than 2 GB. Note: This function is a blocking function and will not return until the write operation is successful or an error occurs. @param src_addr This parameter is a pointer to a buffer containing the data to be stored in the eMMC/SD device. The buffer to which this parameter points should be declared with a minimum size of 512 bytes. @param dst_addr Specifies the sector address in the eMMC/SD device where the data is to be stored. Note: For eMMC/SD devices of greater than 2 GB in size, this address refers to a 512-byte sector. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device, perform a single block transfer. @code #define SECT_1 0x01u #define BUFFER_SIZE 512u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t tx_data_buffer[BUFFER_SIZE] = {0u}; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { tx_data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_single_block_write(tx_data_buffer, SECT_1); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { //.. } } @endcode */ mss_mmc_status_t MSS_MMC_single_block_write ( const uint32_t * src_addr, uint32_t dst_addr ); /*-------------------------------------------------------------------------*//** The MSS_MMC_single_block_read() function is used to read a single block of data from the eMMC/SD device to the host controller. The size of the block of data read by this function is always 512 bytes, which is the standard sector size for all eMMC/SD devices with a capacity of greater than 2 GB. Note: This function is a blocking function and will not return until the read operation is successful or an error occurs. @param src_addr Specifies the sector address in the eMMC/SD device from where the data is to be read. Note: For eMMC/SD devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param dst_addr This parameter is a pointer to a buffer where the data to read from the eMMC/SD device will be stored. The buffer to which this parameter points should be declared with a minimum size of 512 bytes. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device, perform a single block transfer and read back the data from the sector written to within the eMMC device. @code #define SECT_1 0x01u #define BUFFER_SIZE 512u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t tx_data_buffer[BUFFER_SIZE] = {0u}; uint8_t rx_data_buffer[BUFFER_SIZE] = {0u}; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { tx_data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_single_block_write(tx_data_buffer, SECT_1); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { ret_status = MSS_MMC_single_block_read(SECT_1, rx_data_buffer); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { //.. } } } @endcode */ mss_mmc_status_t MSS_MMC_single_block_read ( uint32_t src_addr, uint32_t * dst_addr ); /*-------------------------------------------------------------------------*//** The MSS_MMC_sdma_write() function is used to transfer a single block or multi blocks of data from the host controller to the eMMC/SD device using SDMA. The size of the block of data transferred by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC/SD devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_sdma_write() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_sdma_write() function again. Note: This function is a non-blocking function and returns immediately after initiating the write transfer. @param src This parameter is a pointer to a buffer containing the data to be stored in the eMMC/SD device. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param dest Specifies the sector address in the eMMC/SD device where the data is to be stored. Note: For eMMC/SD devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (32MB - 512). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device, perform a multi block write transfer using SDMA. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_sdma_write(data_buffer, SECT_1, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } @endcode */ mss_mmc_status_t MSS_MMC_sdma_write ( const uint8_t *src, uint32_t dest, uint32_t size ); /*-------------------------------------------------------------------------*//** The MSS_MMC_sdma_read() function is used to read a single block or multiple blocks of data from the eMMC/SD device to the host controller using SDMA. The size of the block of data read by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC/SD devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_sdma_read() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_sdma_read() function again. Note: This function is a non-blocking function and will return immediately after initiating the read transfer. @param src Specifies the sector address in the eMMC/SD device from where the data is to be read. Note: For eMMC/SD devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param dest This parameter is a pointer to a buffer where the data to read from the eMMC/SD device will be stored. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (32MB - 512). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device, perform a multi block read transfer using SDMA. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_sdma_read(SECT_1, data_buffer, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } @endcode */ mss_mmc_status_t MSS_MMC_sdma_read ( uint32_t src, uint8_t *dest, uint32_t size ); /*-------------------------------------------------------------------------*//** The MSS_MMC_adma2_write() function is used to transfer a single block or multiple blocks of data from the host controller to the eMMC/SD device using ADMA2. The size of the block of data transferred by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC/SD devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_adma2_write() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_adma2_write() function again. Note: This function is a non-blocking function and returns immediately after initiating the write transfer. @param src This parameter is a pointer to a buffer containing the data to be stored in the eMMC/SD device. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param dest Specifies the sector address in the eMMC/SD device where the data is to be stored. Note: For eMMC/SD devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (32MB - 512). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device, perform a multi block transfer using ADMA2. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_adma2_write(data_buffer, SECT_1, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } @endcode */ /*mss_mmc_status_t MSS_MMC_adma2_write ( const uint8_t *src, uint32_t dest, uint32_t size ); */ /*-------------------------------------------------------------------------*//** The MSS_MMC_adma2_read() function is used to read a single or multiple blocks of data from the eMMC/SD device to the host controller using ADMA2. The size of the block of data read by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC/SD devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_adma2_read() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_adma2_read() function again. Note: This function is a non-blocking function and returns immediately after initiating the read transfer. @param src Specifies the sector address in the eMMC/SD device from where the data is to be read. Note: For eMMC/SD devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param dest This parameter is a pointer to a buffer where the data to read from the eMMC/SD device will be stored. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (32MB -512). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device, perform a multi block read transfer using ADMA2. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; g_mmc.bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_adma2_read(SECT_1, data_buffer, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } @endcode */ /*mss_mmc_status_t MSS_MMC_adma2_read ( uint32_t src, uint8_t *dest, uint32_t size ); */ /*-------------------------------------------------------------------------*//** The MSS_MMC_sdio_single_block_write() function is used to transfer a single block of data from the host controller to the SDIO device. The size of the block of data transferred by this function is 512 bytes. Note: This function is a blocking function and will not return until the write operation is successful or an error occurs. @param function_num Specifies the SDIO standard function number. @param src_addr This parameter is a pointer to a buffer containing the data to be stored in the SDIO device. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param dst_addr Specifies the function register address in the SDIO device where the data is to be stored. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the SDIO device and perform single block transfer. @code #define BUFFER_SIZE 512u #define REG_NUM 0x00000001u #define SDIO_FUN_NUM 0x00000001u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_12MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_SDIO; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_SDCARD_MODE_DEFAULT_SPEED; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_sdio_single_block_write(SDIO_FUN_NUM, data_buffer, REG_NUM); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { //... } } @endcode */ /*mss_mmc_status_t MSS_MMC_sdio_single_block_write ( uint8_t function_num, const uint32_t * src_addr, uint32_t dst_addr );*/ /*-------------------------------------------------------------------------*//** The MSS_MMC_sdio_single_block_read() function is used to read a single block of data from the the SDIO device to host controller. The size of the block of data transferred by this function is set to 512 bytes. Note: This function is a blocking function and will not return until the write operation is successful or an error occurs. @param function_num Specifies the SDIO standard function number. @param src_addr Specifies the SDIO function number space register address in the SDIO device from where the 512 bytes block of data will be read. @param dst_addr This parameter is a pointer to a buffer where the data read from the SDIO device will be stored. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the SDIO device and perform single block transfer. @code #define BUFFER_SIZE 512u #define REG_NUM 0x00000001u #define SDIO_FUN_NUM 0x00000001u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; g_mmc0.clk_rate = MSS_MMC_CLOCK_12MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_SDIO; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_SDCARD_MODE_DEFAULT_SPEED; ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_sdio_single_block_read(SDIO_FUN_NUM, REG_NUM, data_buffer); if (MSS_MMC_TRANSFER_SUCCESS == ret_status) { //... } } @endcode */ /*mss_mmc_status_t MSS_MMC_sdio_single_block_read ( uint8_t function_num, uint32_t src_addr, uint8_t *dst_addr );*/ /*-------------------------------------------------------------------------*//** The MSS_MMC_get_transfer_status() function returns the status of the MMC transfer initiated by a call to MSS_MMC_sdma_write(), MSS_MMC_sdma_read(), MSS_MMC_adma2_write(), MSS_MMC_adma2_read(), MSS_MMC_cq_write(), MSS_MMC_cq_read() functions. @param This function has no parameters. @return This function returns a value of type mss_mmc_status_t. The possible return values are: - MSS_MMC_TRANSFER_IN_PROGRESS - MSS_MMC_TRANSFER_SUCCESS - MSS_MMC_TRANSFER_FAIL - MSS_MMC_RESPONSE_ERROR Example: The following example shows the use of MSS_MMC_get_transfer_status() function. @code mss_mmc_status_t ret_status; ret_status = MSS_MMC_write(data_buffer, SECT_1, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while(ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) @endcode */ mss_mmc_status_t MSS_MMC_get_transfer_status(void); /*-------------------------------------------------------------------------*//** The MSS_MMC_set_handler() function registers a handler function that will be called by the driver when a read o write transfer completes. The application must create and register a transfer completion handler function. The MSS eMMC SD driver passes the outcome of the transfer to the completion handler in the form of a status (SRS12 register) parameter indicating if the transfer is successful or the type of error that occurred during the transfer if the transfer failed. @param handler The handler parameter is a pointer to a handler function provided by the application. This handler is of type mss_mmc_handler_t. The handler function must take one parameter of type uint32_t and must not return a value. @return This function does not return a value. Example: The following example shows the use of MSS_MMC_set_handler() function. @code #define BLOCK_1 0x00000001u #define BUFFER_SIZE 1024 #define ERROR_INTERRUPT 0x8000 #define TRANSFER_COMPLETE 0x1 void transfer_complete_handler(uint32_t srs12_status); volatile uint32_t g_xfer_in_progress = 0; mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { MSS_MMC_set_handler(transfer_complete_handler); ret_status = MSS_MMC_adma2_write(data_buffer, BLOCK_1, BUFFER_SIZE); if (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) { while(g_xfer_in_progress) { ; } } } void transfer_complete_handler(uint32_t srs12_status) { g_xfer_in_progress = 0; uint32_t isr_err; if(ERROR_INTERRUPT & srs12_status) { isr_err = srs12_status >> 16; } else if(TRANSFER_COMPLETE & srs12_status) { isr_err = 0; } else { } } @endcode */ void MSS_MMC_set_handler(mss_mmc_handler_t handler); /*-------------------------------------------------------------------------*//** The MSS_MMC_cq_init() function enables command queue in the eMMC device and in the host controller. The command queue allows the application to queue multiple read or write tasks. Note: The MSS_MMC_init() must be configured for eMMC mode before using the MSS_MMC_cq_init() function. @param This function has no parameters. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. */ /*mss_mmc_status_t MSS_MMC_cq_init(void); */ /*-------------------------------------------------------------------------*//** The MSS_MMC_cq_write() function is used to transmit a single block or multiple blocks of data from the host controller to the eMMC device using command queue with single or multiple tasks based on the data size. The size of the block of data transferred by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_cq_write() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_cq_write() function again. Note: This function is a non-blocking function and returns immediately after initiating the write transfer. @param src This parameter is a pointer to a buffer containing the data to be stored in the eMMC device. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param dest Specifies the sector address in the eMMC device where the data is to be stored. Note: For eMMC devices of greater than 2 GB in size, this address refers to a 512 byte sector. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (1GB - 16KB). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device and perform a multi block transfer.. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_init(); if ( MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_write(data_buffer, SECT_1, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } } @endcode */ /*mss_mmc_status_t MSS_MMC_cq_write ( const uint8_t *src, uint32_t dest, uint32_t size );*/ /*-------------------------------------------------------------------------*//** The MSS_MMC_cq_read() function is used to read a single block or multiple blocks of data from the eMMC device to the host controller using command queue with single or multiple tasks based on the data size. The size of the block of data read by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_cq_read() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_cq_read() function again. Note: This function is a non-blocking function and returns immediately after initiating the write transfer. @param src_addr Specifies the sector address in the eMMC device from where the datato is to be read. Note: For eMMC devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param dst_addr This parameter is a pointer to a buffer where the data to read from the eMMC device will be stored. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (1GB - 16KB). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device and perform a multi block transfer. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_init(); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_read(SECT_1, data_buffer, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } } @endcode */ /*mss_mmc_status_t MSS_MMC_cq_read ( uint32_t src, uint8_t *dest, uint32_t size );*/ #ifdef __cplusplus } #endif #endif /* __MSS_MMC_H */ mss_mmc_if.c000066400000000000000000000275541432224323300372060ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS eMMC SD Interface Level Driver. * * This eMMC/SD Interface driver provides functions for transferring * configuration and programming commands to the eMMC/SD device. Functions * contained within the eMMC/SD interface driver are accessed through the * mss_mmc_if.h header file. * * SVN $Revision: 12579 $ * SVN $Date: 2019-12-04 16:41:30 +0530 (Wed, 04 Dec 2019) $ */ #include "mss_mmc_if.h" #include "mss_mmc_regs.h" #include "mss_mmc_types.h" #ifdef __cplusplus extern "C" { #endif #define MMC_CLEAR 0u #define MMC_SET 1u #define SHIFT_16BIT 16u #define DELAY_COUNT 0xFFFFu #define SDHCI_CMD_MAX_TIMEOUT 3200u #define SDHCI_CMD_DEFAULT_TIMEOUT 100u #define CMD_INDEX_MASK 0x3Fu #define CMD_TYPE_MASK 0xC0u /***************************************************************************//** * Local Function Prototypes */ static cif_response_t response_1_parser(void); static uint32_t process_request_checkresptype(uint8_t responsetype); static cif_response_t cq_execute_task(uint8_t task_id); /***************************************************************************//** * cif_send_cmd() * See ".h" for details of how to use this function. */ cif_response_t cif_send_cmd(uint32_t cmd_arg, uint32_t cmd_type, uint8_t resp_type) { uint32_t trans_status_isr; cif_response_t ret_status = TRANSFER_IF_FAIL; uint32_t time = MMC_CLEAR; uint32_t cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT; uint32_t value = DELAY_COUNT; /* check if command line is not busy */ while ((MMC->SRS09 & SRS9_CMD_INHIBIT_CMD) != NO_CMD_INHIBIT) { if (time >= cmd_timeout) { if (2u * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) { cmd_timeout += cmd_timeout; } else { return TRANSFER_IF_FAIL; } } time++; while (value--); value = DELAY_COUNT; } /* clear all status interrupts except: * current limit error, card interrupt, card removal, card insertion */ MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR | SRS12_CARD_INTERRUPT | SRS12_CARD_REMOVAL | SRS12_CARD_INSERTION); /* Transfer the Command to the MMC device */ send_mmc_cmd(cmd_arg, cmd_type, resp_type, CHECK_IF_CMD_SENT_POLL); /* No responses for CMD 0,4,15 */ if ((MMC_CMD_0_GO_IDLE_STATE != cmd_type) && (MMC_CMD_4_SET_DSR != cmd_type) && (MMC_CMD_15_GOTO_INACTIVE_STATE != cmd_type)) { trans_status_isr = MMC->SRS12; if ((SRS12_COMMAND_COMPLETE == (trans_status_isr & SRS12_COMMAND_COMPLETE)) && (MMC_CLEAR == (SRS12_ERROR_INTERRUPT & trans_status_isr))) { /* If the response is an R1/B response */ if ((MSS_MMC_RESPONSE_R1 == resp_type) || (MSS_MMC_RESPONSE_R1B == resp_type)) { ret_status = response_1_parser(); } else { ret_status = TRANSFER_IF_SUCCESS; } } else if (SRS12_ERROR_INTERRUPT == (SRS12_ERROR_INTERRUPT & trans_status_isr)) { ret_status = TRANSFER_IF_FAIL; } else { ret_status = TRANSFER_IF_FAIL; } } else { ret_status = TRANSFER_IF_SUCCESS; } /* clear flags for the next time */ MMC->SRS12 = ~(SRS12_CURRENT_LIMIT_ERROR | SRS12_CARD_INTERRUPT | SRS12_CARD_REMOVAL | SRS12_CARD_INSERTION); return(ret_status); } /***************************************************************************//** * The send_mmc_cmd() function transfers the eMMC/SD command and argument to the * eMMC/SD device and waits until the core indicates that the command has been * transferred successfully. */ void send_mmc_cmd(uint32_t cmd_arg, uint32_t cmd_type, uint8_t resp_type, cmd_response_check_options cmd_option) { uint32_t cmd_index, command_information; uint32_t trans_status_isr; command_information = process_request_checkresptype(resp_type); cmd_index = cmd_type & CMD_INDEX_MASK; cmd_type = (cmd_type & CMD_TYPE_MASK) << SHIFT_16BIT; MMC->SRS02 = cmd_arg; MMC->SRS03 = (uint32_t)((cmd_index << CMD_SHIFT) | cmd_type | command_information); mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); switch (cmd_option) { /* only need to wait around if expecting no response */ case CHECK_IF_CMD_SENT_POLL: mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { trans_status_isr = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout); } while (((SRS12_COMMAND_COMPLETE | SRS12_ERROR_INTERRUPT) & trans_status_isr) == MMC_CLEAR); break; case CHECK_IF_CMD_SENT_INT: break; case CHECK_IF_CMD_SENT_NO: /* use when expecting a response */ /* No check- will be checked when response received */ break; default: /* nothing */ break; } } /***************************************************************************//** * The response_1_parser() returns the contents of the Card Status Register. * This function checks that none of the error fields are set within the CSR * and the status of the READY_FOR_DATA flag (Bit 8). */ static cif_response_t response_1_parser(void) { cif_response_t ret_status = TRANSFER_IF_FAIL; uint32_t response; response = MMC->SRS04; if (MMC_CLEAR == (CARD_STATUS_ALL_ERRORS_MASK & response)) /* no error */ { if ((CARD_STATUS_READY_FOR_DATA & response) != MMC_CLEAR) { ret_status = TRANSFER_IF_SUCCESS; } else { ret_status = DEVICE_BUSY; } } return(ret_status); } /*****************************************************************************/ static uint32_t process_request_checkresptype(uint8_t responsetype) { uint32_t command_information; /* check response type */ switch (responsetype) { default: case MSS_MMC_RESPONSE_NO_RESP: command_information = (uint32_t)SRS3_NO_RESPONSE; break; case MSS_MMC_RESPONSE_R2: command_information = (uint32_t)(SRS3_RESP_LENGTH_136 | SRS3_CRC_CHECK_EN); break; case MSS_MMC_RESPONSE_R3: case MSS_MMC_RESPONSE_R4: command_information = (uint32_t)SRS3_RESP_LENGTH_48; break; case MSS_MMC_RESPONSE_R1: case MSS_MMC_RESPONSE_R5: case MSS_MMC_RESPONSE_R6: case MSS_MMC_RESPONSE_R7: command_information = (uint32_t)(SRS3_RESP_LENGTH_48 | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN); break; case MSS_MMC_RESPONSE_R1B: case MSS_MMC_RESPONSE_R5B: command_information = (uint32_t)(SRS3_RESP_LENGTH_48B | SRS3_CRC_CHECK_EN | SRS3_INDEX_CHECK_EN); break; } return (command_information); } /******************************************************************************/ cif_response_t cif_send_cq_direct_command(uint8_t *desc_base_addr, uint32_t cmd_arg, uint32_t cmd_type, uint8_t resp_type, uint8_t task_id) { uint32_t *dcmdTaskDesc; uint32_t flags; uint32_t desc_offset; uint32_t reg; uint32_t cmd_response; cif_response_t ret_status = TRANSFER_IF_FAIL; /* Enable direct command */ reg = MMC->CQRS02; reg |= (uint32_t)CQRS02_DIRECT_CMD_ENABLE; MMC->CQRS02 = reg; desc_offset = CQ_HOST_NUMBER_OF_TASKS * task_id; dcmdTaskDesc = (uint32_t *)(desc_base_addr + desc_offset); /* first prepare general task flags */ flags = (uint32_t)(CQ_DESC_VALID | CQ_DESC_END | CQ_DESC_ACT_TASK | CQ_DESC_INT); /* now prepare direct command specific flags */ flags |= ((cmd_type & 0x3FU) << SHIFT_16BIT); switch (resp_type) { case MSS_MMC_RESPONSE_NO_RESP: flags |= (uint32_t)CQ_DESC_DCMD_RESP_TYPE_NO_RESP; break; case MSS_MMC_RESPONSE_R1: case MSS_MMC_RESPONSE_R4: case MSS_MMC_RESPONSE_R5: flags |= (uint32_t)CQ_DESC_DCMD_RESP_TYPE_R1_R4_R5; break; case MSS_MMC_RESPONSE_R1B: flags |= (uint32_t)CQ_DESC_DCMD_RESP_TYPE_R1B; break; default: /* nothing */ break; } flags |= (uint32_t)CQ_DESC_DCMD_CMD_TIMING; dcmdTaskDesc[0] = flags; dcmdTaskDesc[1] = cmd_arg << SHIFT_16BIT; dcmdTaskDesc[2] = MMC_CLEAR; dcmdTaskDesc[3] = MMC_CLEAR; dcmdTaskDesc[4] = (uint32_t)(CQ_DESC_VALID | CQ_DESC_END | CQ_DESC_ACT_NOP); dcmdTaskDesc[5] = MMC_CLEAR; dcmdTaskDesc[6] = MMC_CLEAR; dcmdTaskDesc[7] = MMC_CLEAR; ret_status = cq_execute_task(task_id); cmd_response = MMC->CQRS18; reg = MMC->CQRS02; reg &= ~(uint32_t)CQRS02_DIRECT_CMD_ENABLE; MMC->CQRS02 = reg; if (TRANSFER_IF_SUCCESS == ret_status) { if ((CARD_STATUS_ALL_ERRORS_MASK & cmd_response) == MMC_CLEAR) /* no error */ { if ((CARD_STATUS_READY_FOR_DATA & cmd_response) != MMC_CLEAR) { ret_status = TRANSFER_IF_SUCCESS; } else { ret_status = DEVICE_BUSY; } } } return ret_status; } /******************************************************************************/ static cif_response_t cq_execute_task(uint8_t task_id) { cif_response_t ret_status = TRANSFER_IF_FAIL; uint32_t reg; uint32_t trans_status_isr; uint32_t cmd_response; uint32_t value = DELAY_COUNT; /* Set doorbell to start processing descriptors by controller */ reg = MMC_SET << task_id; MMC->CQRS10 = reg; while (value--) { ; } mMMC_DECLARE_TIMEOUT(mmc_spin_timeout); mMMC_ARM_TIMEOUT(mmc_spin_timeout); do { trans_status_isr = MMC->SRS12; mMMC_CHECK_TIMEOUT(mmc_spin_timeout, TRANSFER_IF_FAIL); } while (((SRS12_ERROR_INTERRUPT | SRS12_CMD_QUEUING_INT) & trans_status_isr) == MMC_CLEAR); if ((trans_status_isr & (SRS12_ERROR_INTERRUPT | SRS12_CMD_QUEUING_INT)) != MMC_CLEAR) { trans_status_isr = MMC->SRS12; MMC->SRS12 = trans_status_isr; if ((trans_status_isr & SRS12_ERROR_INTERRUPT) != MMC_CLEAR) { ret_status = TRANSFER_IF_FAIL; } if ((trans_status_isr & SRS12_CMD_QUEUING_INT) != MMC_CLEAR) { reg = MMC->CQRS04; MMC->CQRS04 = reg; if ((reg & CQRS04_RESP_ERR_INT) != MMC_CLEAR) { ret_status = TRANSFER_IF_FAIL; } if ((reg & CQRS04_TASK_COMPLETE_INT) != MMC_CLEAR) { reg = MMC->CQRS11; /* clear all caught notifications */ MMC->CQRS11 = reg; if (task_id == CQ_DCMD_TASK_ID) { if ((reg & (MMC_SET << task_id)) != MMC_CLEAR) { cmd_response = MMC->CQRS18; ret_status = TRANSFER_IF_SUCCESS; } } else { ret_status = TRANSFER_IF_SUCCESS; } } } } else { ret_status = TRANSFER_IF_FAIL; } (void) cmd_response; // unused, so referencing to avoid compiler warning return ret_status; } /******************************************************************************/ #ifdef __cplusplus } #endif mss_mmc_if.h000066400000000000000000000116351432224323300372040ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS eMMC SD Interface Level Header File. * * This eMMC SD Interface header file provides access to functions which are * used to configure and program the eMMC/SD device to allow data transfers * to be performed with the eMMC/SD Host. * * SVN $Revision: 12579 $ * SVN $Date: 2019-12-04 16:41:30 +0530 (Wed, 04 Dec 2019) $ */ #ifndef __MSS_MMC_IF_H #define __MSS_MMC_IF_H #ifdef __cplusplus extern "C" #endif #include "hal/cpu_types.h" /***************************************************************************//** * Macro Definitions */ #define CMD_SHIFT 24u #define NO_CMD_INHIBIT 0u /***************************************************************************//** The cif_response type is used to specify the status of the eMMC/SD command transfer to the eMMC/SD device. A value of this type is returned by the cif_send_cmd() function. */ typedef enum { TRANSFER_IF_FAIL = 0u, TRANSFER_IF_SUCCESS = 1u, DEVICE_BUSY = 2u, } cif_response_t; typedef enum { CHECK_IF_CMD_SENT_POLL = 0u, CHECK_IF_CMD_SENT_INT = 1u, CHECK_IF_CMD_SENT_NO = 2u } cmd_response_check_options; /***************************************************************************//** The cif_send_cmd() function handles the interface level command and response data for communicating with the eMMC/SD device. This function issues configuration and control commands to the device, waits on the status register to update indicating that there was a response received (were expected) and parses the response to determine the successfulness of the transfer. @param cmd_arg The cmd_arg parameter specifies the eMMC/SD argument to be passed to the eMMC/SD device. @param cmd_type The cmd_type parameter specifies the eMMC/SD Command type to be passed to the eMMC/SD device. @param resp_type The resp_type parameter specifies the eMMC/SD response type to be received from eMMC/SD device. @return This function returns a value of type cif_response_t representing the successfulness of the transfer. If this return value indicates that the eMMC/SD device is busy, subsequent actions must be taken to ensure that a command is not issued until the device returns to idle. Example: @code #define MMC_DW_CSD 0x03B70300u #define MMC_CMD_SWITCH 6u cif_response_t response_status; response_status = cif_send_cmd(MMC_DW_CSD, MMC_CMD_SWITCH, MMC_RESPONSE_R1B); while(DEVICE_BUSY == response_status) { response_status = cif_send_cmd(RCA_VALUE, MMC_CMD_13_SEND_STATUS, MMC_RESPONSE_R1); } @endcode */ cif_response_t cif_send_cmd ( uint32_t cmd_arg, uint32_t cmd_type, uint8_t resp_type ); /***************************************************************************//** The send_mmc_cmd() function handles the interface level command and response data for communicating with the eMMC/SD device. This function issues configuration and control commands to the device, waits on the status register to update indicating that there was a response received (were expected) and parses the response to determine the successfulness of the transfer. @param cmd_arg The cmd_arg parameter specifies the eMMC/SD argument to be passed to the eMMC/SD device. @param cmd_type The cmd_type parameter specifies the eMMC/SD Command type to be passed to the eMMC/SD device. @param resp_type The resp_type parameter specifies the eMMC/SD response type to be received from eMMC/SD device. @param cmd_option The cmd_option parameter specifies if the function checks if eMMC/SD has sent the command or not before returning. There is no need to check if you are expecting a response, just check for the response. @return This function returns a value of type cif_response_t representing the successfulness of the transfer. If this return value indicates that the eMMC/SD device is busy, subsequent actions must be taken to ensure that a command is not issued until the device returns to idle. Example: @code send_mmc_cmd(RCA_VALUE, MMC_CMD_13_SEND_STATUS, MMC_RESPONSE_R1, CHECK_IF_CMD_SENT_NO); @endcode */ void send_mmc_cmd ( uint32_t cmd_arg, uint32_t cmd_type, uint8_t resp_type, cmd_response_check_options cmd_option ); /******************************************************************************/ cif_response_t cif_send_cq_direct_command ( uint8_t *desc_base_addr, uint32_t cmd_arg, uint32_t cmd_type, uint8_t resp_type, uint8_t task_id ); /******************************************************************************/ #ifdef __cplusplus } #endif #endif /* __MSS_MMC_IF_H */ mss_mmc_internal_api.h000066400000000000000000000504671432224323300412610ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS eMMC SD driver API's for internal use cases. * * SVN $Revision: 12619 $ * SVN $Date: 2019-12-09 12:07:14 +0530 (Mon, 09 Dec 2019) $ */ /*=========================================================================*//** Note: The MSS_MMC_pause_sdma_write_hpi(), MSS_MMC_resume_sdma_write_hpi(), MSS_MMC_packed_read(), MSS_MMC_packed_write(), MSS_MMC_cq_single_task_write(), MSS_MMC_cq_single_task_read()functions provided purely for SVG use cases. -------------------------------- High Priority Interrupt -------------------------------- The following functions are used for eMMC high priority interrupt operation: - MSS_MMC_pause_sdma_write_hpi() - MSS_MMC_resume_sdma_write_hpi() To stop ongoing multiple block write transfers to the eMMC device using the high priority interrupt, a call is made to the MSS_MMC_pause_sdma_write_hpi() function. To resume previously interrupted multiple block transfer of eMMC device, a call is made to the MSS_MMC_resume_sdma_write_hpi() function. -------------------------------- Packed Commands -------------------------------- The following functions are used for eMMC packed command read and write: - MSS_MMC_packed_read() - MSS_MMC_packed_write() To read several multiple blocks of data stored within the eMMC device using the packed group of read commands, a call is made to the MSS_MMC_packed_read() function, specifying the base address of the buffer holding the data of the packed command header block and the base address of buffer where the data read from the eMMC device will be stored. To write several multiple blocks of data to the eMMC device using the packed group of write commands, a call is made to the MSS_MMC_packed_write() function, specifying the base address of the buffer holding the data of the packed command header block and the base address of buffer containing the data blocks to be stored into the eMMC device. -------------------------------- Command Queue -------------------------------- The following functions are used for eMMC command queue single task operation: - MSS_MMC_cq_single_task_write() - MSS_MMC_cq_single_task_read() To write a single block or multiple blocks of data to the eMMC device using a command queue, a call is made to the MSS_MMC_cq_single_task_write() function. This function supports a single task only. To read a single block or multiple blocks of data stored within the eMMC device using a command queue, a call is made to the MSS_MMC_cq_single_task_read() function. This function supports a single task only. *//*=========================================================================*/ #ifndef __MSS_MMC_INTERNAL_API_H #define __MSS_MMC_INTERNAL_API_H #ifdef __cplusplus extern "C" #endif #include "hal/cpu_types.h" /*-------------------------------------------------------------------------*//** The MSS_MMC_pause_sdma_write_hpi() function is used to pause the ongoing SDMA write transfer using the eMMC high priority interrupt (HPI). Note: This MSS_MMC_pause_sdma_write_hpi()function has parameters provided purely for svg use case. if this function in production release then we should remove the need for parameters. @param src This parameter is a pointer to a buffer containing actual the data to be stored in the eMMC device. The src parameter must be identical to the src parameter of the MSS_MMC_sdma_write() function. @param dest This parameter specifies the sector address in the eMMC device where the block is to be stored. The dest parameter must be identical to the dest parameter of the MSS_MMC_sdma_write() function. @param size The parameter size specifies the size in bytes of the requested transfer. The size parameter must be identical to the size parameter of the MSS_MMC_sdma_write() function. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device and perform an HPI @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_sdma_write(data_buffer, SECT_1, BUFFER_SIZE); if(ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) { ret_status = MSS_MMC_pause_sdma_write_hpi(data_buffer, SECT_1, BUFFER_SIZE); if(ret_status == MSS_MMC_TRANSFER_SUCCESS) { //.. } } } @endcode */ mss_mmc_status_t MSS_MMC_pause_sdma_write_hpi ( const uint8_t *src, uint32_t dest, uint32_t size ); /*-------------------------------------------------------------------------*//** The MSS_MMC_resume_sdma_write_hpi() function is used to resume writing the remaining blocks to the target device which was previously interrupted by a call to MSS_MMC_pause_sdma_write_hpi(). @param This function has no parameters. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device and perform a HPI interrupt and resume remaining block operation. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_sdma_write(data_buffer, SECT_1, BUFFER_SIZE); if(ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) { ret_status = MSS_MMC_pause_sdma_write_hpi(data_buffer, SECT_1, BUFFER_SIZE); if(ret_status == MSS_MMC_TRANSFER_SUCCESS) { ret_status = MSS_MMC_resume_sdma_write_hpi(); if(ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) { do { ret_status = MSS_MMC_get_transfer_status(); }while(ret_status == MSS_MMC_TRANSFER_IN_PROGRESS); } } } } @endcode */ mss_mmc_status_t MSS_MMC_resume_sdma_write_hpi(void); /*-------------------------------------------------------------------------*//** The MSS_MMC_packed_write() function is used to transmit a packed group of data from the host to the eMMC device. The write commands can be packed in a group of commands (all write) that transfer the data for all commands in the group in one transfer on the bus. Note : This function is a non-blocking function and returns immediately after initiating the write transfer. @param src This parameter is a pointer to a buffer containing the data blocks to be stored in the eMMC device. The first block containing the packed-command header and all data sectors of the individual packed commands are appended together after the header. @param dest Specifies the sector address in the eMMC device where the block is to be stored. The dest shall be the same address that is specified by the first individual write command in the packed group. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512. The size parameter shall be the sum of all block counts of the individual writes plus one for the header. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: This example shows how to initialize the device and perform a packed write transfer. @code #define SECT_9 0x09u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; uint8_t packed_write[512]; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; packed_write[0] = 0x01; // version packed_write[1] = 0x02; // 0x2 - write packed_write[2] = 0x02; // no of entries packed_write[3] = 0x00; packed_write[4] = 0x00; packed_write[5] = 0x00; packed_write[6] = 0x00; packed_write[7] = 0x00; packed_write[8] = 0x04; // CMD23 arg1 - 4 blocks packed_write[9] = 0x00; packed_write[10] = 0x00; packed_write[11] = 0x00; packed_write[12] = 0x09; // CMD25 arg1 - sector no 9 packed_write[13] = 0x00; packed_write[14] = 0x00; packed_write[15] = 0x00; packed_write[16] = 0x04; // CMD23 arg2 - 4-blocks packed_write[17] = 0x00; packed_write[18] = 0x00; packed_write[19] = 0x00; packed_write[20] = 0x29; // CMD25 agr2 - sector no 0x29 packed_write[21] = 0x00; packed_write[22] = 0x00; packed_write[23] = 0x00; for (loop_count = 24; loop_count < 512; loop_count++) { packed_write[loop_count] = 0; } for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } // packed header block for (loop_count = 0; loop_count < 512; loop_count++) { data_buffer[loop_count] = packed_write[loop_count]; } resp_reg = MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_packed_write(data_buffer, SECT_9, BUFFER_SIZE); if (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) { do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } } @endcode */ mss_mmc_status_t MSS_MMC_packed_write ( const uint8_t *src, uint32_t dest, uint32_t size ); /*-------------------------------------------------------------------------*//** The MSS_MMC_packed_read() function is used to read several multiple block of data from the device to the host using packed group. The read commands can be packed in group of commands (all read) that transfer the data for all commands in the group in one transfer on the bus. Note : This function is a non-blocking function and returns immediately after initiating the block transfer. @param src Specifies the sector address in the eMMC device where the block is to be read. The src shall be the same address that is specified by the first individual read command in the packed group. @param dest This parameter is a pointer to a buffer where the data read from the eMMC device will be stored. The buffer to which this parameter points should be declared with a minimum size of 512 bytes. @param packed_header This parameter is a pointer to a buffer containing the packed-command header block. @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512. The size parameter shall be the sum of all block counts of the individual read. @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: This example shows how to initialize the device and perform a packed read transfer. @code #define SECT_9 0x09u #define BUFFER_SIZE 4096u mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; uint8_t packed_read[512]; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; packed_read[0] = 0x01; // version packed_read[1] = 0x02; // 0x1 - read packed_read[2] = 0x02; // no of entries packed_read[3] = 0x00; packed_read[4] = 0x00; packed_read[5] = 0x00; packed_read[6] = 0x00; packed_read[7] = 0x00; packed_read[8] = 0x04; // CMD23 arg1 - 4 blocks packed_read[9] = 0x00; packed_read[10] = 0x00; packed_read[11] = 0x00; packed_read[12] = 0x09; // CMD18 arg1 - sector no 9 packed_read[13] = 0x00; packed_read[14] = 0x00; packed_read[15] = 0x00; packed_read[16] = 0x04; // CMD23 arg2 - 4-blocks packed_read[17] = 0x00; packed_read[18] = 0x00; packed_read[19] = 0x00; packed_read[20] = 0x29; // CMD18 agr2 - sector no 0x29 packed_read[21] = 0x00; packed_read[22] = 0x00; packed_read[23] = 0x00; for(loop_count = 24; loop_count < 512; loop_count++) { packed_read[loop_count] = 0; } for(loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = = 0x00; } resp_reg = MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_packed_read(SECT_9, data_buffer, (uint32 *)packed_read, BUFFER_SIZE); if (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) { do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } } @endcode */ mss_mmc_status_t MSS_MMC_packed_read ( uint32_t src, uint8_t *dest, uint32_t *packed_header, uint32_t size ); /*-------------------------------------------------------------------------*//** The MSS_MMC_cq_single_task_write() function is used to transmit a single block or multiple blocks of data from the host controller to the eMMC device using command queue with single task based on the data size. The size of the block of data transferred by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_cq_single_task_write() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_cq_single_task_write() function again. Note: This function is a non-blocking function and returns immediately after initiating the write transfer. Note: This MSS_MMC_cq_single_task_write() and MSS_MMC_cq_single_task_read() functions are provided purely for svg use case. For production release we will remove. @param src This parameter is a pointer to a buffer containing the data to be stored in the eMMC device. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param dest Specifies the sector address in the eMMC device where the data is to be stored. Note: For eMMC devices of greater than 2 GB in size, this address refers to a 512 byte sector. @param task_id Specifies the eMMC command queue task id number 0 to 31 @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (32MB - 512). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device and perform a multi block transfer.. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u #define TASK_ID 0x01 mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_init(); if ( MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_single_task_write(data_buffer, SECT_1, TASK_ID, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } } @endcode */ mss_mmc_status_t MSS_MMC_cq_single_task_write ( const uint8_t *src, uint32_t dest, uint8_t task_id, uint32_t size ); /*-------------------------------------------------------------------------*//** The MSS_MMC_cq_single_task_read() function is used to read a single or multiple blocks of data from the eMMC device to the host controller using command queue with single task based on the data size. The size of the block of data read by this function must be set to 512 bytes or a multiple of 512 bytes. The 512 bytes is the standard sector size for all eMMC devices with a capacity of greater than 2 GB. Note: A call to MSS_MMC_cq_single_task_read() while a transfer is in progress will not initiate a new transfer. Use the MSS_MMC_get_transfer_status() function or a completion handler registered by the MSS_MMC_set_handler() function to check the status of the current transfer before calling the MSS_MMC_cq_single_task_read() function again. Note: This function is a non-blocking function and returns immediately after initiating the write transfer. @param src Specifies the sector address in the eMMC device from where the data is to be read. Note: For eMMC devices of greater than 2 GB in size, this address refers to a 512-byte sector. @param dest This parameter is a pointer to a buffer where the data to read from the eMMC device will be stored. The buffer to which this parameter points must be declared with a minimum size of 512 bytes. @param task_id Specifies the eMMC command queue task id number 0 to 31 @param size Specifies the size in bytes of the requested transfer. The value of size must be a multiple of 512 but not greater than (32MB - 512). @return This function returns a value of type mss_mmc_status_t which specifies the transfer status of the operation. Example: The following example shows how to initialize the device and perform a multi block transfer. @code #define SECT_1 0x01u #define BUFFER_SIZE 4096u #define TASK_ID 0x02 mss_mmc_cfg_t g_mmc0; mss_mmc_status_t ret_status; uint8_t data_buffer[BUFFER_SIZE]; uint32_t loop_count; g_mmc0.clk_rate = MSS_MMC_CLOCK_25MHZ; g_mmc0.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc0.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc0.bus_speed_mode = MSS_MMC_MODE_LEGACY; for (loop_count = 0; loop_count < (BUFFER_SIZE); loop_count++) { data_buffer[loop_count] = 0x45 + loop_count; } ret_status = MSS_MMC_init(&g_mmc0); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_init(); if (MSS_MMC_INIT_SUCCESS == ret_status) { ret_status = MSS_MMC_cq_single_task_read(SECT_1, data_buffer, TASK_ID, BUFFER_SIZE); do { ret_status = MSS_MMC_get_transfer_status(); }while (ret_status == MSS_MMC_TRANSFER_IN_PROGRESS) } } @endcode */ mss_mmc_status_t MSS_MMC_cq_single_task_read ( uint32_t src, uint8_t *dest, uint8_t task_id, uint32_t size ); #ifdef __cplusplus } #endif #endif /* __MSS_MMC_INTERNAL_API_H */ mss_mmc_regs.h000066400000000000000000001474101432224323300375470ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register definitions of the PolarFire SoC MSS eMMC SD. * * SVN $Revision: 12579 $ * SVN $Date: 2019-12-04 16:41:30 +0530 (Wed, 04 Dec 2019) $ */ #ifndef __MSS_MMC_REGS_H_ #define __MSS_MMC_REGS_H_ #ifdef __cplusplus extern "C" { #endif /* PolarFire SoC MSS eMMC/SD/SDIO Host Controller register set */ typedef struct { volatile uint32_t HRS00; volatile uint32_t HRS01; volatile uint32_t HRS02; volatile uint32_t HRS03; volatile uint32_t HRS04; volatile uint32_t HRS05; volatile uint32_t HRS06; volatile uint32_t HRS07; volatile uint32_t RESERVED0[22u]; volatile uint32_t HRS30; volatile uint32_t HRS31; volatile uint32_t HRS32; volatile uint32_t HRS33; volatile uint32_t HRS34; volatile uint32_t HRS35; volatile uint32_t HRS36; volatile uint32_t HRS37; volatile uint32_t HRS38; volatile uint32_t RESERVED1[20u]; volatile uint32_t HRS59; volatile uint32_t RESERVED2[3u]; volatile uint32_t CRS63; volatile uint32_t RESERVED3[64u]; volatile uint32_t SRS00; volatile uint32_t SRS01; volatile uint32_t SRS02; volatile uint32_t SRS03; volatile uint32_t SRS04; volatile uint32_t SRS05; volatile uint32_t SRS06; volatile uint32_t SRS07; volatile uint32_t SRS08; volatile uint32_t SRS09; volatile uint32_t SRS10; volatile uint32_t SRS11; volatile uint32_t SRS12; volatile uint32_t SRS13; volatile uint32_t SRS14; volatile uint32_t SRS15; volatile uint32_t SRS16; volatile uint32_t SRS17; volatile uint32_t SRS18; volatile uint32_t SRS19; volatile uint32_t SRS20; volatile uint32_t SRS21; volatile uint32_t SRS22; volatile uint32_t SRS23; volatile uint32_t SRS24; volatile uint32_t SRS25; volatile uint32_t SRS26; volatile uint32_t SRS27; volatile uint32_t RESERVED4[100u]; volatile uint32_t CQRS00; volatile uint32_t CQRS01; volatile uint32_t CQRS02; volatile uint32_t CQRS03; volatile uint32_t CQRS04; volatile uint32_t CQRS05; volatile uint32_t CQRS06; volatile uint32_t CQRS07; volatile uint32_t CQRS08; volatile uint32_t CQRS09; volatile uint32_t CQRS10; volatile uint32_t CQRS11; volatile uint32_t CQRS12; volatile uint32_t CQRS13; volatile uint32_t CQRS14; volatile uint32_t RESERVED5; volatile uint32_t CQRS16; volatile uint32_t CQRS17; volatile uint32_t CQRS18; volatile uint32_t RESERVED6; volatile uint32_t CQRS20; volatile uint32_t CQRS21; volatile uint32_t CQRS22; volatile uint32_t CQRS23; }MMC_TypeDef; #define MMC_BASE 0x20008000u #define MMC ((MMC_TypeDef *) MMC_BASE) /*----------------------------------------------------------------------------- @name (HRS6) - masks and macros ------------------------------------------------------------------------------ */ #define HRS6_EMMC_MODE_MASK 0x00000007u #define HRS6_EMMC_MODE_SDCARD (0x0u << 0) #define HRS6_EMMC_MODE_SDR (0x2u << 0) #define HRS6_EMMC_MODE_DDR (0x3u << 0) #define HRS6_EMMC_MODE_HS200 (0x4u << 0) #define HRS6_EMMC_MODE_HS400 (0x5u << 0) #define HRS6_EMMC_MODE_HS400_ES (0x6u << 0) #define HRS6_EMMC_MODE_LEGACY (0x7u << 0) #define HRS6_EMMC_TUNE_VALUE_MASK 0x00003F00u #define HRS6_EMMC_TUNE_REQUEST 0x00008000u /*----------------------------------------------------------------------------- @name Block count and size register (SRS01) - masks ------------------------------------------------------------------------------ */ /* Block count for current transfer mask */ #define SRS1_BLOCK_COUNT 0xFFFF0000u /* DMA buffer size 4kB */ #define SRS1_DMA_BUFF_SIZE_4KB 0x00000000u /* DMA buffer size 8kB */ #define SRS1_DMA_BUFF_SIZE_8KB 0x00001000u /* DMA buffer size 16kB */ #define SRS1_DMA_BUFF_SIZE_16KB 0x00002000u /* DMA buffer size 32kB */ #define SRS1_DMA_BUFF_SIZE_32KB 0x00003000u /* DMA buffer size 64kB */ #define SRS1_DMA_BUFF_SIZE_64KB 0x00004000u /* DMA buffer size 128kB */ #define SRS1_DMA_BUFF_SIZE_128KB 0x00005000u /* DMA buffer size 265kB */ #define SRS1_DMA_BUFF_SIZE_256KB 0x00006000u /* DMA buffer size 512kB */ #define SRS1_DMA_BUFF_SIZE_512KB 0x00007000u /* DMA buffer size mask */ #define SRS1_DMA_BUFF_SIZE_MASK 0x00007000u /* Transfer block size mask */ #define SRS1_BLOCK_SIZE 0x00000FFFu /*----------------------------------------------------------------------------- @name Transfer mode and command information register (SRS3) - masks ------------------------------------------------------------------------------ */ /* command type */ /* Abort CMD12, CMD52 for writing "I/O Abort" in CCCR */ #define SRS3_ABORT_CMD (0x3u << 22) /* Resume CMD52 for writing "Function Select" in CCCR */ #define SRS3_RESUME_CMD (0x2u << 22) /*Suspend CMD52 for writing "Bus Suspend" in CCCR */ #define SRS3_SUSPEND_CMD (0x1u << 22) /* data is present and will be transferred using the DAT line */ #define SRS3_DATA_PRESENT 0x00200000u /* index check enable */ #define SRS3_INDEX_CHECK_EN 0x00100000u /* response CRC check enable */ #define SRS3_CRC_CHECK_EN 0x00080000u /* response type */ /* response type - no response */ #define SRS3_NO_RESPONSE (0x0u << 16) /* response type - response length 136 */ #define SRS3_RESP_LENGTH_136 (0x1u << 16) /* response type - response length 48 */ #define SRS3_RESP_LENGTH_48 (0x2u << 16) /* response type - response length 48 and check Busy after response */ #define SRS3_RESP_LENGTH_48B (0x3u << 16) /* RID - Response Interrupt Disable When set to 1, the Command Complete Interrupt (SRS12.CC) will be disabled */ #define SRS3_RESP_INTER_DISABLE 0x00000100u /* RECE - Response Error Check Enable. When set 1, the host will look after R1/R5 responses. */ #define SRS3_RESP_ERR_CHECK_EN 0x00000080u /* Response type Response type R1 for the response content checker */ #define SRS3_RESPONSE_CHECK_TYPE_R1 (0x0u << 6) /* Response type R5 for the response content checker */ #define SRS3_RESPONSE_CHECK_TYPE_R5 (0x1u << 6) /* multi block DAT line data transfers */ #define SRS3_MULTI_BLOCK_SEL 0x00000020u /* Data Transfer Direction Select */ /* data transfer direction - write */ #define SRS3_TRANS_DIRECT_WRITE (0x0u << 4) /* data transfer direction - read */ #define SRS3_TRANS_DIRECT_READ (0x1u << 4) /* Auto CMD Enable */ /* Auto CMD23 enable */ #define SRS3_AUTOCMD23_ENABLE (0x2u << 2) /* Auto CMD12 enable */ #define SRS3_AUTOCMD12_ENABLE (0x1u << 2) /* Block count enable */ #define SRS3_BLOCK_COUNT_ENABLE 0x00000002u /* DMA enable */ #define SRS3_DMA_ENABLE 0x00000001u /*----------------------------------------------------------------------------- @name Present state register masks (SRS9) - masks ------------------------------------------------------------------------------ */ /* U2DET - STB.L Detection (UHS-II only) * Field used when UHS-II interface is enabled (U2IE=1) * and SD clock is supplied (SDCE=1) */ #define SRS9_STBL_DETECTION 0x80000000u /* U2SYN Lane Synchronization (UHS-II only) * After STB.L Detection set 1, * this bit is set when SYN LLS is received on D1 lan*/ #define SRS9_LANE_SYNCHRONIZATION 0x40000000u /* U2DOR - In Dormant State (UHS-II only) */ #define SRS9_IN_DORMANT_STATE 0x20000000u /* CMD line signal level */ #define SRS9_CMD_SIGNAL_LEVEL 0x01000000u /* DAT[3:0] Line Signal Level */ /* DAT3 signal level */ #define SRS9_DAT3_SIGNAL_LEVEL (0x1u << 23) /* DAT2 signal level */ #define SRS9_DAT2_SIGNAL_LEVEL (0x1u << 22) /* DAT1 signal level */ #define SRS9_DAT1_SIGNAL_LEVEL (0x1u << 21) /* DAT0 signal level */ #define SRS9_DAT0_SIGNAL_LEVEL (0x1u << 20) /* Write protect switch pin level */ #define SRS9_WP_SWITCH_LEVEL 0x00080000u /* Card detect pin level */ #define SRS9_CARD_DETECT_LEVEL 0x00040000u /* Card state stable */ #define SRS9_CARD_STATE_STABLE 0x00020000u /* Card inserted */ #define SRS9_CARD_INSERTED 0x00010000u /* Buffer read enable */ #define SRS9_BUFF_READ_EN 0x00000800u /* Buffer write enable */ #define SRS9_BUFF_WRITE_EN 0x00000400u /* Read transfer active */ #define SRS9_READ_TRANS_ACTIVE 0x00000200u /* Write transfer active */ #define SRS9_WRITE_TRANS_ACTIVE 0x00000100u /* DAT[7:4] Line Signal Level */ /* DAT7 Line Signal Level l (SD Mode only) */ #define SRS9_WRITE_DAT7_PIN_LEVEL (0x1u << 7) /* DAT6 Line Signal Level l (SD Mode only) */ #define SRS9_WRITE_DAT6_PIN_LEVEL (0x1u << 6) /* DAT5 Line Signal Level l (SD Mode only) */ #define SRS9_WRITE_DAT5_PIN_LEVEL (0x1u << 5) /* DAT4 Line Signal Level l (SD Mode only) */ #define SRS9_WRITE_DAT4_PIN_LEVEL (0x1u << 4) /* The signal will be used by the SD driver to rerun the DAT line active */ #define SRS9_DAT_LINE_ACTIVE 0x00000004u /* Command Inhibit (DAT) */ #define SRS9_CMD_INHIBIT_DAT 0x00000002u /* Command Inhibit (CMD) */ #define SRS9_CMD_INHIBIT_CMD 0x00000001u /*----------------------------------------------------------------------------- @name SRS10 ------------------------------------------------------------------------------ */ /* SD Bus Voltage Select */ /* SD bus voltage - 3.3V */ #define SRS10_SET_3_3V_BUS_VOLTAGE (0x7u << 9) /* SD bus voltage - 3.0V */ #define SRS10_SET_3_0V_BUS_VOLTAGE (0x6u << 9) /* SD bus voltage - 1.8V */ #define SRS10_SET_1_8V_BUS_VOLTAGE (0x5u << 9) /* SD bus voltage mask */ #define SRS10_BUS_VOLTAGE_MASK (0x7u << 9) /* SD bus power. The SD device is powered. */ #define SRS10_SD_BUS_POWER 0x00000100u /* select SDMA mode */ #define SRS10_DMA_SELECT_SDMA (0x0u << 3) /* select ADMA1 mode */ #define SRS10_DMA_SELECT_ADMA1 (0x1u << 3) /* select ADMA2 mode */ #define SRS10_DMA_SELECT_ADMA2 (0x2u << 3) /* DMA mode selection mask */ #define SRS10_DMA_SELECT_MASK (0x3u << 3) /* Set 4 bit data transfer width */ #define SRS10_DATA_WIDTH_4BIT 0x00000002u /* Extended Data Transfer Width */ #define SRS10_EXTENDED_DATA_TRANSFER_WIDTH 0x00000020u /* High speed enable. */ #define SRS10_HIGH_SPEED_ENABLE 0x00000004u /* Turning on the LED.*/ #define SRS10_TURN_ON_LED 0x00000001u /*----------------------------------------------------------------------------- @name SRS11 ------------------------------------------------------------------------------ */ /* Data timeout mask */ #define SRS11_TIMEOUT_MASK (0xFu << 16) /* SD clock enable */ #define SRS11_SD_CLOCK_ENABLE 0x00000004u /* SDCLK Frequency mask */ #define SRS11_SEL_FREQ_BASE_MASK (0x0000FF00u | 0x000000C0u) /*The SDCLK Frequency Divider method can be selected by this field */ #define SRS11_CLOCK_GENERATOR_SELECT (0x1u << 5) /* Internal clock stable */ #define SRS11_INT_CLOCK_STABLE 0x00000002u /* internal clock enable */ #define SRS11_INT_CLOCK_ENABLE 0x00000001u /*----------------------------------------------------------------------------- @name Interrupt status register (SRS12) - masks ------------------------------------------------------------------------------ */ /* ERSP - Response Error (SD Mode only) */ #define SRS12_RESPONSE_ERROR 0x08000000u /* Tuning error */ /*#define SRS12_TUNING_ERROR 0x04000000u*/ /* ADMA error */ #define SRS12_ADMA_ERROR 0x02000000u /* Auto CMD (CMD12 or CMD23) error */ #define SRS12_AUTO_CMD_ERROR 0x01000000u /* Current limit error host controller is not supplying power to SD card due some failure. */ #define SRS12_CURRENT_LIMIT_ERROR 0x00800000u /* Data end bit error */ #define SRS12_DATA_END_BIT_ERROR 0x00400000u /* Data CRC error */ #define SRS12_DATA_CRC_ERROR 0x00200000u /* Data timeout error */ #define SRS12_DATA_TIMEOUT_ERROR 0x00100000u /* Command index error. Index error occurs in the command response. */ #define SRS12_COMMAND_INDEX_ERROR 0x00080000u /* Command end bit error */ #define SRS12_COMMAND_END_BIT_ERROR 0x00040000u /* Command CRC error */ #define SRS12_COMMAND_CRC_ERROR 0x00020000u /* Command timeout error */ #define SRS12_COMMAND_TIMEOUT_ERROR 0x00010000u /* Error interrupt */ #define SRS12_ERROR_INTERRUPT 0x00008000u /* Command Queuing - interrupt */ #define SRS12_CMD_QUEUING_INT 0x00004000u #if 0 /* Re-Tuning Event */ #define SRS12_RETUNING_EVENT 0x00001000u /* Interrupt on line C */ #define SRS12_INTERRUPT_ON_LINE_C 0x00000800u /* Interrupt on line B */ #define SRS12_INTERRUPT_ON_LINE_B 0x00000400u /* Interrupt on line A */ #define SRS12_INTERRUPT_ON_LINE_A 0x00000200u #endif /* Card interrupt */ #define SRS12_CARD_INTERRUPT 0x00000100u /* Card removal */ #define SRS12_CARD_REMOVAL 0x00000080u /* Card insertion */ #define SRS12_CARD_INSERTION 0x00000040u /* Buffer read ready. Host is ready to read the buffer. */ #define SRS12_BUFFER_READ_READY 0x00000020u /* Buffer write ready. Host is ready for writing data to the buffer.*/ #define SRS12_BUFFER_WRITE_READY 0x00000010u /* DMA interrupt */ #define SRS12_DMA_INTERRUPT 0x00000008u /* Block gap event */ #define SRS12_BLOCK_GAP_EVENT 0x00000004u /* Transfer complete */ #define SRS12_TRANSFER_COMPLETE 0x00000002u /* Command complete */ #define SRS12_COMMAND_COMPLETE 0x00000001u /* normal interrupt status mask */ #define SRS12_NORMAL_STAUS_MASK (0xFFFFu) #define SRS12_ERROR_STATUS_MASK (0xFFFF8000u) #define SRS12_ERROR_CMD_LINE (SRS12_COMMAND_TIMEOUT_ERROR \ | SRS12_COMMAND_CRC_ERROR \ | SRS12_COMMAND_END_BIT_ERROR \ | SRS12_COMMAND_INDEX_ERROR) /*----------------------------------------------------------------------------- @name Interrupt status enable register (SRS13) - masks ------------------------------------------------------------------------------ */ /** ERSP_SE - Response Error Status Enable */ #define SRS13_RESPONSE_ERROR_STAT_EN 0x08000000u /* Tuning error status enable */ #define SRS13_TUNING_ERROR_STAT_EN (0x1u << 26) /* ADMA error status enable */ #define SRS13_ADMA_ERROR_STAT_EN 0x02000000u /* Auto CMD12 error status enable */ #define SRS13_AUTO_CMD12_ERR_STAT_EN 0x01000000u /* Current limit error status enable */ #define SRS13_CURRENT_LIMIT_ERR_STAT_EN 0x00800000u /* Data end bit error status enable */ #define SRS13_DATA_END_BIT_ERR_STAT_EN 0x00400000u /* Data CRC error status enable */ #define SRS13_DATA_CRC_ERR_STAT_EN 0x00200000u /* Data timeout error status enable */ #define SRS13_DATA_TIMEOUT_ERR_STAT_EN 0x00100000u /* Command index error status enable */ #define SRS13_COMMAND_INDEX_ERR_STAT_EN 0x00080000u /* Command end bit error status enable */ #define SRS13_COMMAND_END_BIT_ERR_STAT_EN 0x00040000u /* Command CRC error status enable */ #define SRS13_COMMAND_CRC_ERR_STAT_EN 0x00020000u /* Command timeout error status enable */ #define SRS13_COMMAND_TIMEOUT_ERR_STAT_EN 0x00010000u /* Command Queuing Status Enable */ #define SRS13_CMD_QUEUING_STAT_EN 0x00004000u /* Re-Tuning Event status enable */ #define SRS13_RETUNING_EVENT_STAT_EN (0x1u << 12) /*Interrupt on line C status enable */ #define SRS13_INTERRUPT_ON_LINE_C_STAT_EN (0x1u << 11) /* Interrupt on line B status enable */ #define SRS13_INTERRUPT_ON_LINE_B_STAT_EN (0x1u << 10) /* Interrupt on line A status enable */ #define SRS13_INTERRUPT_ON_LINE_A_STAT_EN (0x1u << 9) /* Card interrupt status enable */ #define SRS13_CARD_INTERRUPT_STAT_EN 0x00000100u /* Card removal status enable */ #define SRS13_CARD_REMOVAL_STAT_EN 0x00000080u /* Card insertion status enable */ #define SRS13_CARD_INERTION_STAT_EN 0x00000040u /* Buffer read ready status enable */ #define SRS13_BUF_READ_READY_STAT_EN 0x00000020u /* Buffer write ready status enable */ #define SRS13_BUF_WRITE_READY_STAT_EN 0x00000010u /* DMA interrupt status enable */ #define SRS13_DMA_INTERRUPT_STAT_EN 0x00000008u /* Block gap event status enable */ #define SRS13_BLOCK_GAP_EVENT_STAT_EN 0x00000004u /* Transfer complete status enable */ #define SRS13_TRANSFER_COMPLETE_STAT_EN 0x00000002u /* Command complete status enable */ #define SRS13_COMMAND_COMPLETE_STAT_EN 0x00000001u /*----------------------------------------------------------------------------- @name Interrupt signal enable register (SRS14) - masks ------------------------------------------------------------------------------ */ /* Response error interrupt signdla enable */ #define SRS14_RESPONSE_ERROR_SIG_EN 0x08000000u /* Tuning error signal enable */ #define SRS14_TUNING_ERROR_SIG_EN 0x04000000u /* ADMA error signal enable */ #define SRS14_ADMA_ERROR_SIG_EN 0x02000000u /* Auto CMD12 error signal enable */ #define SRS14_AUTO_CMD12_ERR_SIG_EN 0x01000000u /* Current limit error signal enable */ #define SRS14_CURRENT_LIMIT_ERR_SIG_EN 0x00800000u /* Data end bit error signal enable */ #define SRS14_DATA_END_BIT_ERR_SIG_EN 0x00400000u /* Data CRC error signal enable */ #define SRS14_DATA_CRC_ERR_SIG_EN 0x00200000u /* Data timeout error signal enable */ #define SRS14_DATA_TIMEOUT_ERR_SIG_EN 0x00100000u /* Command index error signal enable */ #define SRS14_COMMAND_INDEX_ERR_SIG_EN 0x00080000u /* Command end bit error signal enable */ #define SRS14_COMMAND_END_BIT_ERR_SIG_EN 0x00040000u /* Command CRC error signal enable */ #define SRS14_COMMAND_CRC_ERR_SIG_EN 0x00020000u /* Command timeout error signal enable */ #define SRS14_COMMAND_TIMEOUT_ERR_SIG_EN 0x00010000u /* Command Queuing - interrupt enable */ #define SRS14_CMD_QUEUING_SIG_EN 0x00004000u /* SD4HC__SRS__SRS14__RSVD_0_MASK 0x00003E00u */ /* Re-Tuning Event signal enable */ #define SRS14_RETUNING_EVENT_SIG_EN (0x1u << 12) /*Interrupt on line C signal enable */ #define SRS14_INTERRUPT_ON_LINE_C_SIG_EN (0x1u << 11) /* Interrupt on line B signal enable */ #define SRS14_INTERRUPT_ON_LINE_B_SIG_EN (0x1u << 10) /* Interrupt on line A signal enable */ #define SRS14_INTERRUPT_ON_LINE_A_SIG_EN (0x1u << 9) /* Card interrupt signal enable */ #define SRS14_CARD_INTERRUPT_SIG_EN 0x00000100u /* Card removal signal enable */ #define SRS14_CARD_REMOVAL_SIG_EN 0x00000080u /* Card insertion signal enable */ #define SRS14_CARD_INERTION_SIG_EN 0x00000040u /* Buffer read ready signal enable */ #define SRS14_BUFFER_READ_READY_SIG_EN 0x00000020u /* Buffer write ready signal enable */ #define SRS14_BUFFER_WRITE_READY_SIG_EN 0x00000010u /* DMA interrupt signal enable */ #define SRS14_DMA_INTERRUPT_SIG_EN 0x00000008u /* Block gap event signal enable */ #define SRS14_BLOCK_GAP_EVENT_SIG_EN 0x00000004u /* Transfer complete signal enable */ #define SRS14_TRANSFER_COMPLETE_SIG_EN 0x00000002u /* Command complete signal enable */ #define SRS14_COMMAND_COMPLETE_SIG_EN 0x00000001u /*----------------------------------------------------------------------------- @name AutoCMD12 Error Status Register/Host Control Register (SRR15) - masks ------------------------------------------------------------------------------ */ /* Preset Value Enable */ #define SRS15_PRESET_VALUE_ENABLE 0x80000000u /* Asynchronous Interrupt Enable */ #define SRS15_ASYNCHRONOUS_INT_EN (0x1u << 30) /* 64-bit Addressing Specifies the addressing mode for DMA ending. */ #define SRS15_64_BIT_ADDRESSING 0x20000000u /* Host Version 4.00 Enable * Selects backward (SD Host 3.00 Version) compatibility mode * or SD Host 4.00 Version mode */ #define SRS15_HOST_4_ENABLE 0x10000000u /* UHS-II Interface Enable */ #define SRS15_UHSII_ENABLE 0x01000000u /* Sampling Clock Select */ #define SRS15_SAMPLING_CLOCK_SELECT 0x00800000u /* Execute Tuning */ #define SRS15_EXECUTE_TUNING 0x00400000u /* Driver Strength Select mask */ #define SRS15_DRIVER_TYPE_MASK (0x3u << 20) /* Driver Strength Select type D */ #define SRS15_DRIVER_TYPE_D (0x3u << 20) /* Driver Strength Select type C */ #define SRS15_DRIVER_TYPE_C (0x2u << 20) /* Driver Strength Select type A */ #define SRS15_DRIVER_TYPE_A (0x1u << 20) /* Driver Strength Select type B */ #define SRS15_DRIVER_TYPE_B (0x0u << 20) /* This bit is to switch I/O signaling voltage level on */ /* the SD interface between 3.3V and 1.8V */ #define SRS15_18V_ENABLE 0x00080000u /* UHS mode select mask */ #define SRS15_UHS_MODE_MASK (0x7u << 16) /* UHS-II mode select */ #define SRS15_UHS_MODE_UHSII (0x7u << 16) /* DDR50 mode select */ #define SRS15_UHS_MODE_DDR50 (0x4u << 16) /* SDR104 mode select */ #define SRS15_UHS_MODE_SDR104 (0x3u << 16) /* SDR50 mode select */ #define SRS15_UHS_MODE_SDR50 (0x2u << 16) /* SDR25 mode select */ #define SRS15_UHS_MODE_SDR25 (0x1u << 16) /* SDR12 mode select */ #define SRS15_UHS_MODE_SDR12 (0x0u << 16) /* Command not issued bu auto CMD12 error */ #define SRS15_CMD_NOT_ISSUED_ERR 0x00000080u /* Auto CMD12 index error */ #define SRS15_AUTO_CMD12_INDEX_ERR 0x00000010u /* Auto CMD12 end bit error */ #define SRS15_AUTO_CMD12_END_BIT_ERR 0x00000008u /* Auto CMD12 CRC error */ #define SRS15_AUTO_CMD12_CRC_ERR 0x00000004u /* Auto CMD12 timeout error */ #define SRS15_AUTO_CMD12_TIMEOUT_ERR 0x00000002u /* Autp CMD12 not executed */ #define SRS15_AUTO_CMD12_NOT_EXECUTED 0x00000001u /*----------------------------------------------------------------------------- @name SRS16 ------------------------------------------------------------------------------ */ #define SRS16_64BIT_SUPPORT 0x10000000u /* 512 is the maximum block size that can be written */ /* to the buffer in the Host Controller. */ #define SRS16_MAX_BLOCK_LENGTH_512 (0x0u << 16) /* 1024 is the maximum block size that can be written */ /* to the buffer in the Host Controller. */ #define SRS16_MAX_BLOCK_LENGTH_1024 (0x1u << 16) /* 2048 is the maximum block size that can be written to*/ /* the buffer in the Host Controller. */ #define SRS16_MAX_BLOCK_LENGTH_2048 (0x2u << 16) /* timeout unit clock is MHz*/ #define SRS16_TIMEOUT_CLOCK_UNIT_MHZ 0x00000080u /* 64-bit System Bus Support */ #define SRS16_64BIT_SUPPORT 0x10000000u /* Voltage 1.8V is supported */ #define SRS16_VOLTAGE_1_8V_SUPPORT 0x04000000u /* Voltage 3.0V is supported */ #define SRS16_VOLTAGE_3_0V_SUPPORT 0x02000000u /* Voltage 3.3V is supported */ #define SRS16_VOLTAGE_3_3V_SUPPORT 0x01000000u #define SRS13_STATUS_EN (SRS13_TUNING_ERROR_STAT_EN \ | SRS13_ADMA_ERROR_STAT_EN \ | SRS13_AUTO_CMD12_ERR_STAT_EN \ | SRS13_CURRENT_LIMIT_ERR_STAT_EN \ | SRS13_DATA_END_BIT_ERR_STAT_EN \ | SRS13_DATA_CRC_ERR_STAT_EN \ | SRS13_DATA_TIMEOUT_ERR_STAT_EN \ | SRS13_COMMAND_INDEX_ERR_STAT_EN \ | SRS13_COMMAND_END_BIT_ERR_STAT_EN \ | SRS13_COMMAND_CRC_ERR_STAT_EN \ | SRS13_COMMAND_TIMEOUT_ERR_STAT_EN \ | SRS13_RETUNING_EVENT_STAT_EN \ | SRS13_INTERRUPT_ON_LINE_A_STAT_EN \ | SRS13_INTERRUPT_ON_LINE_B_STAT_EN \ | SRS13_INTERRUPT_ON_LINE_C_STAT_EN \ | SRS13_CARD_REMOVAL_STAT_EN \ | SRS13_CARD_INERTION_STAT_EN \ | SRS13_BUF_READ_READY_STAT_EN \ | SRS13_BUF_WRITE_READY_STAT_EN \ | SRS13_DMA_INTERRUPT_STAT_EN \ | SRS13_BLOCK_GAP_EVENT_STAT_EN \ | SRS13_TRANSFER_COMPLETE_STAT_EN \ | SRS13_COMMAND_COMPLETE_STAT_EN \ | SRS13_RESPONSE_ERROR_STAT_EN \ | SRS13_CMD_QUEUING_STAT_EN) /*----------------------------------------------------------------------------- @name Capabilities Register #2 Fields (SRS17) - masks ------------------------------------------------------------------------------ */ /* VDD2 Supported */ #define SRS17_VDD2_ENABLED 0x10000000u /* Macro gets value of clock multiplier */ static inline uint32_t SRS17_GET_CLOCK_MULTIPLIER(const uint32_t val) { return ((val & 0x00FF0000u) >> 16u); } /* Re-Tuning Modes SD4HC__SRS__SRS17__RTNGM_MASK */ /* Re-Tuning Modes - mode 3 */ #define SRS17_RETUNING_MODE_3 (0x2u << 14) /* Re-Tuning Modes - mode 2 */ #define SRS17_RETUNING_MODE_2 (0x1u << 14) /* Re-Tuning Modes - mode 1 */ #define SRS17_RETUNING_MODE_1 (0x0u << 14) /* tuning operation is necessary in SDR50 mode */ #define SRS17_USE_TUNING_SDR50 0x00002000u /* It gest value of timer Count for Re-Tuning, */ static inline uint32_t SRS17_GET_RETUNING_TIMER_COUNT(const uint32_t val) { /* (1 << (((val >> 8) & 0xF) - 1)) */ uint32_t result = 0x80000000u; /* 1 << -1 */ uint32_t shift = ((val & 0x00000F00u) >> 8u); if (shift > 0u) { shift -= 1u; result = (((uint32_t)1u) << shift); } return (result); } /* 1.8V Line Driver Type D Supported */ #define SRS17_1_8V_DRIVER_TYPE_D_SUPPORTED 0x00000040u /* 1.8V Line Driver Type C Supported */ #define SRS17_1_8V_DRIVER_TYPE_C_SUPPORTED 0x00000020u /* 1.8V Line Driver Type A Supported */ #define SRS17_1_8V_DRIVER_TYPE_A_SUPPORTED 0x00000010u /* UHS-II Supported */ #define SRS17_UHSII_SUPPORTED 0x00000008u /* DDR50 Supported */ #define SRS17_DDR50_SUPPORTED 0x00000004u /* SDR104 Supported */ #define SRS17_SDR104_SUPPORTED 0x00000002u /* SDR50 Supported */ #define SRS17_SDR50_SUPPORTED 0x00000001u /*----------------------------------------------------------------------------- @name PHY settings register (HRS4) - masks and macros ------------------------------------------------------------------------------ */ /* PHY request acknowledge */ #define HRS_PHY_ACKNOWLEDGE_REQUEST 0x04000000u /* make read request */ #define HRS_PHY_READ_REQUEST 0x02000000u /* make write request */ #define HRS_PHY_WRITE_REQUEST 0x01000000u /*----------------------------------------------------------------------------- @name PHY Delay Value Registers addressing ------------------------------------------------------------------------------ */ /* PHY register addresses using */ #define UIS_ADDR_HIGH_SPEED 0x00u #define UIS_ADDR_DEFAULT_SPEED 0x01u #define UIS_ADDR_UHSI_SDR12 0x02u #define UIS_ADDR_UHSI_SDR25 0x03u #define UIS_ADDR_UHSI_SDR50 0x04u #define UIS_ADDR_UHSI_DDR50 0x05u #define UIS_ADDR_MMC_LEGACY 0x06u #define UIS_ADDR_MMC_SDR 0x07u #define UIS_ADDR_MMC_DDR 0x08u #define UIS_ADDR_SDCLK 0x0Bu #define UIS_ADDR_HS_SDCLK 0x0Cu #define UIS_ADDR_DAT_STROBE 0x0Du /*--------------------------------------------------------------------------- @name OCR register bits definitions of SD memory cards ---------------------------------------------------------------------------- */ #define SDCARD_REG_OCR_2_7_2_8 (1u << 15) #define SDCARD_REG_OCR_2_8_2_9 (1u << 16) #define SDCARD_REG_OCR_2_9_3_0 (1u << 17) #define SDCARD_REG_OCR_3_0_3_1 (1u << 18) #define SDCARD_REG_OCR_3_1_3_2 (1u << 19) #define SDCARD_REG_OCR_3_2_3_3 (1u << 20) #define SDCARD_REG_OCR_3_3_3_4 (1u << 21) #define SDCARD_REG_OCR_3_4_3_5 (1u << 22) #define SDCARD_REG_OCR_3_5_3_6 (1u << 23) /* Switching to 1.8V request */ #define SDCARD_REG_OCR_S18R (1u<< 24) /* Switching to 1.8V accepted */ #define SDCARD_REG_OCR_S18A (1u << 24) /* SDXC power controll (0 - power saving, 1 - maximum performance) */ /* (this bit is not aviable in the SDIO cards) */ #define SDCARD_REG_OCR_XPC (1u << 28) /* card capacity status (this bit is not aviable in the SDIO cards) */ #define SDCARD_REG_OCR_CCS (1u << 30) /* card power up busy status (this is not aviable in the SDIO cards) */ #define SDCARD_REG_OCR_READY (1u << 31) /*--------------------------------------------------------------------------- @name SCR register bits defnitions and slot masks ---------------------------------------------------------------------------- */ /* CMD20 (speed class controll) command is supported by card */ #define SDCARD_REG_CMD20 (1u << 0) /* CMD23 (set block count) command is supported by card */ #define SDCARD_REG_CMD23 (1u << 1) static inline uint32_t SDCARD_REG_GET_EXT_SECURITY(uint32_t x) { return ((x >> 11) & 0xFU); } #define SDCARD_REG_SD_SPEC3_SUPPORT (1u << 15) /* SD supported bus width 1 bit */ #define SDCARD_REG_SCR_SBW_1BIT (1u << 16) /* SD supported bus width 4 bit */ #define SDCARD_REG_SCR_SBW_4BIT (4u << 16) /* SD bus width mask */ #define SDCARD_REG_SCR_SBW_MASK 0x000F0000u /* SD security mask */ #define SDCARD_REG_SCR_SEC_MASK 0x00700000u /* SD security - no security */ #define SDCARD_REG_SCR_SEC_NO 0x00000000u /* SD security version 1.01 */ #define SDCARD_REG_SCR_SEC_VER_101 0x00200000u /* SD security version 2.00 */ #define SDCARD_REG_SCR_SEC_VER_200 0x00300000u /* Data state after erase is 1 */ #define SDCARD_REG_SCR_DSAE_1 0x00800000u /* Physical Layer Specification Version supported by the card mask. */ #define SDCARD_REG_SCR_SPEC_MAS 0x0F000000u /* Physical Layer Specification Version 1.00 - 1.01 */ #define SDCARD_REG_SCR_SPEC_VER_100 0x00000000u /* Physical Layer Specification Version 1.10 */ #define SDCARD_REG_SCR_SPEC_VER_110 0x01000000u /* Physical Layer Specification Version 2.00 */ #define SDCARD_REG_SCR_SPEC_VER_200 0x02000000u /* Physical Layer Specification mask */ #define SDCARD_REG_SCR_SPEC_VER_MASK 0x0F000000u /* SCR structure mask */ #define SDCARD_REG_SCR_STRUCTURE_MASK 0xF0000000u /* SCR version 1.0 */ #define SDCARD_REG_SCR_VER_10 0x00000000u /*--------------------------------------------------------------------------- @name Response R4 bit definitions ---------------------------------------------------------------------------- */ /* card ready bit */ #define SDCARD_R4_CARD_READY (1u << 31) /* memory present bit */ #define SDCARD_R4_MEMORY_PRESENT (1u << 27) /*--------------------------------------------------------------------------- @name SD card function register bits, masks and macros definitions ---------------------------------------------------------------------------- */ /* Check function mode - is used to query if the card supports a specific function or functions. */ #define SDCARD_SWITCH_FUNC_MODE_SWITCH (0x1u << 31) /* Set function mode - is used to switch the functionality of the card.*/ #define SDCARD_SWITCH_FUNC_MODE_CHECK (0x0u << 31) /* Card access mode - SDR12 default */ #define SDCARD_SWITCH_ACCESS_MODE_SDR12 0x0u /* Card access mode - SDR25 highspeed */ #define SDCARD_SWITCH_ACCESS_MODE_SDR25 0x1u /* Card access mode - SDR50 */ #define SDCARD_SWITCH_ACCESS_MODE_SDR50 0x2u /* Card access mode - SDR104 */ #define SDCARD_SWITCH_ACCESS_MODE_SDR104 0x3u /* Card access mode - DDR50 */ #define SDCARD_SWITCH_ACCESS_MODE_DDR50 0x4u /* Card command system - default */ #define SDCARD_SWITCH_CMD_SYSTEM_DEFAULT 0x0u /* Card command system - eCommerce command set */ #define SDCARD_SWITCH_CMD_SYSTEM_E_COMMERCE 0x1u /* Card command system - OTP */ #define SDCARD_SWITCH_CMD_SYSTEM_OTP 0x3u /* Card command system - ASSD */ #define SDCARD_SWITCH_CMD_SYSTEM_ASSD 0x4u /* Card command system - vendor specific command set */ #define SDCARD_SWITCH_CMD_SYSTEM_NR_VENDOR 0xEu /* Card driver strength - Type B default */ #define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_B 0x0u /* Card driver strength - Type A */ #define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_A 0x1u /* Card driver strength - Type C */ #define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_C 0x2u /* Card driver strength - Type D */ #define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_D 0x3u #define SDCARD_SWITCH_GROUP_NR_1 1u #define SDCARD_SWITCH_GROUP_NR_2 2u #define SDCARD_SWITCH_GROUP_NR_3 3u #define SDCARD_SWITCH_GROUP_NR_4 4u #define SDCARD_SWITCH_GROUP_NR_5 5u #define SDCARD_SWITCH_GROUP_NR_6 6u /* macro gets one byte from dword */ #define GetByte(dword, byte_nr) (((dword) >> ((byte_nr) * 8u)) & 0xFFu) static inline uint8_t GET_BYTE_FROM_BUFFER(const void* buffer, uintptr_t byteNr) { return ((uint8_t)GetByte((*(uint32_t*)((uintptr_t)buffer + (byteNr & ~3u))), (byteNr & 3u))); } static inline uint8_t GET_BYTE_FROM_BUFFER2(const void* buffer, uintptr_t bufferSize, uintptr_t byteNr) { return (GET_BYTE_FROM_BUFFER(buffer, bufferSize - 1u - byteNr)); } /* Macro returns 1 if given function is supported by the card */ static inline uint8_t SDCARD_SWITCH_FUNC_IS_FUNC_SUPPORTED(const uint8_t* val, uint8_t groupNum, uint8_t funcNum) { uint32_t supportStatus = 0u; if (funcNum < 32u) { const uintptr_t offset = (groupNum - 1u) * 2u; supportStatus = (((uint32_t)GET_BYTE_FROM_BUFFER2(val, 64u, 50u - offset) | (uint32_t)(GET_BYTE_FROM_BUFFER2(val, 64u, 51u - offset))) << 8) & (uint32_t)(1u << funcNum); } return ((supportStatus != 0u) ? 1u : 0u); } /* Macro gets function status code from the switch function status data structure */ static inline uint8_t SDCARD_SWICH_FUNC_GET_STAT_CODE(const uint8_t* val, uint8_t groupNum) { uint8_t result = 0u; const uint8_t shift = ((groupNum - 1u) % 2u) * 4u; const uintptr_t offset = 47u + ((groupNum - 1u) / 2u); result = (GET_BYTE_FROM_BUFFER2(val, 64u, offset) >> shift) & 0xFu; return (result); } /* Macro gets function busy status from the switch function status data structure */ /* Macro returns 1 if function is busy 0 otherwise */ static inline uint8_t SDCARD_SWICH_FUNC_GET_BUSY_STAT(const uint8_t* val, uint8_t groupNum, uint8_t funcNum) { uint32_t busyStatus = 0u; if (funcNum < 32u) { const uintptr_t offset = (groupNum - 1u) * 2u; busyStatus = ((GET_BYTE_FROM_BUFFER2(val, 64u, 34u - offset) | GET_BYTE_FROM_BUFFER2(val, 64u, 35u - offset)) << 8) & (uint32_t)(1u << funcNum); } return ((busyStatus != 0u) ? 1u : 0u); } /*--------------------------------------------------------------------------- @name Command masks ---------------------------------------------------------------------------- */ /* host hight capacity support -*/ #define SDCARD_ACMD41_HCS (1u << 30) /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- @name Response SPI R1 for SD memory cards bits defnitions ---------------------------------------------------------------------------- */ /* The card is in idle state and running the initializing process. */ #define SDCARD_RESP_R1_IDLE 0x01u /* An erase sequence was cleared before executing because an out of erase sequence command was received. */ #define SDCARD_RESP_R1_ERASE_RESET 0x02u /* An illegal command code was detected. */ #define SDCARD_RESP_R1_ILLEGAL_CMD_ERR 0x04u /* The CRC check of the last command failed. */ #define SDCARD_RESP_R1_COM_CRC_ERR 0x08u /* An error in the sequence of erase commands occurred. */ #define SDCARD_RESP_R1_ERASE_SEQUENCE_ERR 0x10u /* A misaligned address that did not match the block length was used in the command.*/ #define SDCARD_RESP_R1_ADDRESS_ERR 0x20u /* The command's argument (e.g. address, block length) was outside the allowed */ #define SDCARD_RESP_R1_PARAM_ERR 0x40u /* All errors mask */ #define SDCARD_RESP_R1_ALL_ERRORS (SDCARD_RESP_R1_ILLEGAL_CMD_ERR \ | SDCARD_RESP_R1_COM_CRC_ERR \ | SDCARD_RESP_R1_ERASE_SEQUENCE_ERR \ | SDCARD_RESP_R1_ADDRESS_ERR \ | SDCARD_RESP_R1_PARAM_ERR) /* No operation go to next descriptor on the list. */ #define ADMA2_DESCRIPTOR_TYPE_NOP (0x0u << 4) /* Transfer data from the pointed page and go to next descriptor on the list.*/ #define ADMA2_DESCRIPTOR_TYPE_TRAN (0x2u << 4) /* Go to the next descriptor list */ #define ADMA2_DESCRIPTOR_TYPE_LINK (0x3u << 4) /* the ADMA interrupt is generated */ /* when the ADMA1 engine finishes processing the descriptor. */ #define ADMA2_DESCRIPTOR_INT (0x1u << 2) /* it signals termination of the transfer */ /* and generates Transfer Complete Interrupt */ /* when this transfer is completed */ #define ADMA2_DESCRIPTOR_END (0x1u << 1) /* it indicates the valid descriptor on a list */ #define ADMA2_DESCRIPTOR_VAL (0x1u << 0) /*----------------------------------------------------------------------------- Command Queuing Configuration (CQRS02)- masks ------------------------------------------------------------------------------ */ /* Direct Command (DCMD) Enable */ #define CQRS02_DIRECT_CMD_ENABLE 0x00001000u /* Task Descriptor Size 128 bits */ #define CQRS02_TASK_DESCRIPTOR_SIZE_128 (1u << 8) /* Task Descriptor Size 64 bits */ #define CQRS02_TASK_DESCRIPTOR_SIZE_64 (0u << 8) /* Task Descriptor Size mask */ #define CQRS02_TASK_DESCRIPTOR_SIZE_MASK 0x00000100u /* Command Queuing Enable */ #define CQRS02_COMMAND_QUEUING_ENABLE 0x00000001u /*----------------------------------------------------------------------------- Command Queuing Interrupt Status (CQRS04)- masks ------------------------------------------------------------------------------ */ /* Task cleared interrupt */ #define CQRS04_TASK_CLEARED_INT 0x00000008u /* Response Error Detected Interrupt */ #define CQRS04_RESP_ERR_INT 0x00000004u /* Task Complete Interrupt */ #define CQRS04_TASK_COMPLETE_INT 0x00000002u /* Halt Complete Interrupt */ #define CQRS04_HALT_COMPLETE_INT 0x00000001u /*----------------------------------------------------------------------------- Command Queuing Interrupt Status Enable (CQRS05)- masks ------------------------------------------------------------------------------ */ /* Task cleared status enable */ #define CQRS05_TASK_CLEARED_STAT_EN 0x00000008u /* Response Error Detected status enable */ #define CQRS05_RESP_ERR_STAT_EN 0x00000004u /* Task Complete status enable */ #define CQRS05_TASK_COMPLETE_STAT_EN 0x00000002u /* Halt Complete status enable */ #define CQRS05_HALT_COMPLETE_STAT_EN 0x00000001u /*----------------------------------------------------------------------------- Command Queuing Interrupt Signal Enable (CQRS06)- masks ------------------------------------------------------------------------------ */ /* Task cleared interrupt signal enable */ #define CQRS06_TASK_CLEARED_INT_SIG_EN 0x00000008u /* Response Error Detected Interrupt signal enable */ #define CQRS06_RESP_ERR_INT_SIG_EN 0x00000004u /* Task Complete Interrupt signal enable */ #define CQRS06_TASK_COMPLETE_INT_SIG_EN 0x00000002u /* Halt Complete Interrupt signal enable */ #define CQRS06_HALT_COMPLETE_INT_SIG_EN 0x00000001u /*----------------------------------------------------------------------------- Command Queuing Interrupt Coalescing (CQRS07)- masks and macros ------------------------------------------------------------------------------ */ #define CQRS07_INT_COAL_ENABLE 0x80000000u /* Interrupt Coalescing Status Bit */ #define CQRS07_INT_COAL_STATUS_BIT 0x00100000u /* Counter and Timer Reset(ICCTR) */ #define CQRS07_INT_COAL_COUNTER_TIMER_RESET 0x00010000u /* Interrupt Coalescing Counter Threshold Write Enable */ #define CQRS07_INT_COAL_COUNT_THRESHOLD_WE 0x00008000u /* task management argument - discard task */ #define CQ_TASK_MGMT_ARG_TM_DISCARD_TASK 1u /* task management argument - discard queue */ #define CQ_TASK_MGMT_ARG_TM_DISCARD_QUEUE 2u /* number of supported tasks */ #define CQ_HOST_NUMBER_OF_TASKS 32u /* direct command task ID */ #define CQ_DCMD_TASK_ID 31u /*----------------------------------------------------------------------------- @name Task Descriptor Fields ------------------------------------------------------------------------------ */ /* The descriptor is valid */ #define CQ_DESC_VALID (1u << 0) /* it is the last descriptor */ #define CQ_DESC_END (1u << 1) /* Hardware shall generate an interrupt upon the task's completion */ #define CQ_DESC_INT (1u << 2) /* Descriptor type - Task descriptor */ #define CQ_DESC_ACT_TASK (5u << 3) /* Descriptor type - Data Transfer descriptor */ #define CQ_DESC_ACT_TRAN (4u << 3) /* Descriptor type - Link descriptor */ #define CQ_DESC_ACT_LINK (6u << 3) /* Descriptor type - No operation*/ #define CQ_DESC_ACT_NOP (0u << 3) /* enable force programming */ #define CQ_DESC_FORCE_PROG (6u << 1) /* set context ID */ static inline uint16_t CQ_DESC_SET_CONTEXT_ID(uint16_t id) { return ((id & 0xFU) << 7); } #define CQ_DESC_TAG_REQUEST (1u << 11) /* Data read direction */ #define CQ_DESC_DATA_DIR_READ (1u << 12) #define CQ_DESC_DATA_DIR_WRITE (0u << 12) /* High priority task */ #define CQ_DESC_PRIORITY_HIGH (1u << 13) #define CQ_DESC_QUEUE_BARRIER (1u << 14) #define CQ_DESC_RELIABLE_WRITE (1u << 15) /* set data block count to transfer */ static inline uint32_t CQ_DESC_SET_BLOCK_COUNT(uint32_t count) { return ((count & 0xFFFFu) << 16); } /* Length of data buffer in bytes. A value of 0000 means 64 KB */ static inline uint32_t CQ_DESC_SET_DATA_LEN(uint32_t len) { return ((len & 0xFFFFu) << 16); } static inline uint32_t CQ_DESC_DCMD_SET_CMD_INDEX(uint32_t idx) { return ((idx & 0x3Fu) << 16); } /* Command may be sent to device during data activity or busy time */ #define CQ_DESC_DCMD_CMD_TIMING (1u << 22) /* expected reponse on direct command - R1 or R4 or R5*/ #define CQ_DESC_DCMD_RESP_TYPE_R1_R4_R5 (2u << 23) /* expected reponse on direct command - R1B */ #define CQ_DESC_DCMD_RESP_TYPE_R1B (3u << 23) /* no expected reponse on direct command */ #define CQ_DESC_DCMD_RESP_TYPE_NO_RESP (0u << 23) /*----------------------------------------------------------------------------- @name CCCR transfer direction definitions ------------------------------------------------------------------------------ */ /* Read data from CCCR register */ #define SDIOHOST_CCCR_READ 0u /* Write data to CCCR register */ #define SDIOHOST_CCCR_WRITE 1u /*--------------------------------------------------------------------------- @name Bus interface control register bit definitions ---------------------------------------------------------------------------- */ /* Data 4 bit bus width */ #define SDCARD_BIS_BUS_WIDTH_4BIT 0x02u /* Data 1 bit bus width */ #define SDCARD_BIS_BUS_WIDTH_1BIT 0x00u /* Connect[0]/Disconnect[1] the 10K-90K ohm pull-up resistor on CD/DAT[3] */ /* (pin 1) of card. */ #define SDCARD_BIS_CD_DISABLE 0x80u /* Support contiunous SPI interrupt (irrespective of the state the CS line) */ #define SDCARD_BIS_SCSI 0x40u /* Enable contiunous SPI interrupt (irrespective of the state the CS line) */ #define SDCARD_BIS_ECSI 0x20u /*--------------------------------------------------------------------------- @name Card capability register bit definitions ---------------------------------------------------------------------------- */ /* Card supports direct commands during data trnsfer. (only in SD mode) */ #define SDCARD_CCR_SDC 0x01u /* Card supports multiblock */ #define SDCARD_CCR_SMB 0x02u /* Card supports read wait */ #define SDCARD_CCR_SRW 0x04u /* Card supports Suspend/Resume */ #define SDCARD_CCR_SBS 0x08u /* Card supports interrupt between blocks of data in 4-bit SD mode. */ #define SDCARD_CCR_S4MI 0x10u /* Enable interrupt between blocks of data in 4-bit SD mode. */ #define SDCARD_CCR_E4MI 0x20u /* Card is a low-speed card */ #define SDCARD_CCR_LSC 0x40u /* 4 bit support for Low-Speed cards */ #define SDCARD_CCR_4BLS 0x80u /*--------------------------------------------------------------------------- @name Bus speed register bit definitions ---------------------------------------------------------------------------- */ /* Support high speed. */ #define SDIO_CCCR_13_SHS 0x01u /* Enable high speed. */ #define SDIO_CCCR_13_EHS 0x02u #define SDIO_CCCR_13_BSS_MASK (0x7u << 1) #define SDIO_CCCR_13_BSS_SDR12 (0x0u << 1) #define SDIO_CCCR_13_BSS_SDR25 (0x1u << 1) #define SDIO_CCCR_13_BSS_SDR50 (0x2u << 1) #define SDIO_CCCR_13_BSS_SDR104 (0x3u << 1) #define SDIO_CCCR_13_BSS_DDR50 (0x4u << 1) /*--------------------------------------------------------------------------- @name USH-I suport bits register 0x14 ---------------------------------------------------------------------------- */ #define SDIO_CCCR_14_SSDR50 (0x1u << 0) #define SDIO_CCCR_14_SSDR104 (0x1u << 1) #define SDIO_CCCR_14_SDDR50 (0x1u << 2) /*--------------------------------------------------------------------------- @name Card status bits and masks definitions for cards (SD SDIO MMC) ---------------------------------------------------------------------------- */ /* Error authentication process */ #define CARD_SATUS_AKE_SEQ_ERROR (0x1u << 3) /* The card will expect ACMD, or an indication that the command has been interpreted as ACMD */ #define CARD_SATUS_APP_CMD (0x1u << 5) /* Card didn't switch to the expected mode as requested by the SWITCH command */ #define CARD_STATUS_SWITCH_ERROR (0x1u << 7) /* Corresponds to buffer empty signaling on the bus - buffer is ready */ #define CARD_STATUS_READY_FOR_DATA (0x1u << 8) /* The state of the card when receiving the command. Below are definded all 9 satuses.*/ #define CARD_STATUS_CS_MASK (0xFu << 9) /* Current status card is in Idle State */ #define CARD_STATUS_CS_IDLE (0x0u << 9) /* Current status card is in Ready State */ #define CARD_STATUS_CS_READY (0x1u << 9) /* Current status card is Identification State */ #define CARD_STATUS_CS_IDENT (0x2u << 9) /* Current status card is in Stand-by State */ #define CARD_STATUS_CS_STBY (0x3u << 9) /* Current status card is in Transfer State */ #define CARD_STATUS_CS_TRAN (0x4u << 9) /* Current status card is in Sending-data State */ #define CARD_STATUS_CS_DATA (0x5u << 9) /* Current status card is in Receive-data State */ #define CARD_STATUS_CS_RCV (0x6u << 9) /* Current status card is in Programming State */ #define CARD_STATUS_CS_PRG (0x7u << 9) /* Current status card is in Disconnect State */ #define CARD_STATUS_CS_DIS (0x8u << 9) /* An erase sequence was cleared before executing because an out of erase sequence command was received */ #define CARD_STATUS_ERASE_RESET (0x1u << 13) /* The command has been executed without using the internal ECC. */ #define CARD_STATUS_CARD_ECC_DISABLED (0x1u << 14) /* Problem with erase part of memory because it is protected */ #define CARD_STATUS_WP_ERASE_SKIP (0x1u << 15) /* Can be either one of the following errors: */ /* - The read only section of the CSD does not match the card content. */ /* - An attempt to reverse the copy (set as original) or permanent WP (unprotected) bits was made.*/ #define CARD_STATUS_CSD_OVERWRITE (0x1u << 16) /* The card could not sustain data programming in stream write mode */ #define CARD_STATUS_OVERRUN (0x1u << 17) /* The card could not sustain data transfer in stream read mode */ #define CARD_STATUS_UNDERRUN (0x1u << 18) /* A general or an unknown error occurred during the operation. */ #define CARD_STATUS_ERROR (0x1u << 19) /* Internal card controller error */ #define CARD_STATUS_CC_ERROR (0x1u << 20) /* Card internal ECC was applied but failure failed to correct the data.*/ #define CARD_STATUS_CARD_ECC_FAILED (0x1u << 21) /* Command not legal for the card state */ #define CARD_STATUS_ILLEGAL_COMMAND (0x1u << 22) /* The CRC check of the previous error command failed. */ #define CARD_STATUS_COM_CRC_ERROR (0x1u << 23) /* Set when a sequence or password error has been detected in lock/unlock card command.*/ #define CARD_STATUS_LOCK_UNLOCK_FAILED (0x1u << 24) /* When set, signals that the card is card locked by the host */ #define CARD_STATUS_CARD_IS_LOCKED (0x1u << 25) /* Set when the host attempts to write to a protected block or to the temporary or permanent write protected card. */ #define CARD_STATUS_WP_VIOLATION (0x1u << 26) /* An invalid selection of write-blocks for erase occurred.*/ #define CARD_STATUS_ERASE_PARAM (0x1u << 27) /* An error in the sequence of erase error commands occurred.*/ #define CARD_STATUS_ERASE_SEQ_ERROR (0x1u << 28) /* The transferred block length is not allowed for this card, or the number*/ /* of transferred bytes does not match the block length.*/ #define CARD_STATUS_BLOCK_LEN_ERROR (0x1u << 29) /* A misaligned address which did not match the block length was used in the command.*/ #define CARD_STATUS_ADDRESS_ERROR (0x1u << 30) /* The command's argument was out of the allowed range for this card.*/ #define CARD_STATUS_OUT_OF_RANGE (0x1u << 31) /* All errors mask definition */ #define CARD_STATUS_ALL_ERRORS_MASK ( CARD_STATUS_OUT_OF_RANGE \ | CARD_STATUS_ADDRESS_ERROR \ | CARD_STATUS_BLOCK_LEN_ERROR \ | CARD_STATUS_ERASE_SEQ_ERROR \ | CARD_STATUS_ERASE_PARAM \ | CARD_STATUS_WP_VIOLATION \ | CARD_STATUS_LOCK_UNLOCK_FAILED \ | CARD_STATUS_COM_CRC_ERROR \ | CARD_STATUS_ILLEGAL_COMMAND \ | CARD_STATUS_CARD_ECC_FAILED \ | CARD_STATUS_CC_ERROR \ | CARD_STATUS_ERROR \ | CARD_STATUS_UNDERRUN \ | CARD_STATUS_OVERRUN \ | CARD_STATUS_WP_ERASE_SKIP \ | CARD_STATUS_SWITCH_ERROR \ | CARD_SATUS_AKE_SEQ_ERROR ) /****************************************************************************/ #ifdef __cplusplus } #endif #endif /* __MSS_MMC_REGS_H_ */ mss_mmc_types.h000066400000000000000000000255271432224323300377570ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC MSS eMMC SD driver data structures. * * This eMMC Interface header file provides a subset of definitions from the eMMC * protocol JESD84-B51 * * SVN $Revision: 12579 $ * SVN $Date: 2019-12-04 16:41:30 +0530 (Wed, 04 Dec 2019) $ */ #ifndef __MSS_MMC_TYPE_H #define __MSS_MMC_TYPE_H #ifdef __cplusplus extern "C" #endif #include "config.h" #include "hal/cpu_types.h" #include // // We're going to use a trick to allow us have a macro with 1 or 2 arguments // This allows us to turn on and off a timeout easily... // // The expect flow is: // mHSS_DECLARE_TIMEOUT(my_timeout); // mMMC_ARM_TIMEOUT(my_timeout); // mMMC_CHECK_TIMEOUT(my_timeout); // #ifdef CONFIG_SERVICE_MMC_SPIN_TIMEOUT # ifdef CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT # define mMMC_CHECK_TIMEOUT_1(VAR) { VAR--; assert(VAR != 0u); } # define mMMC_CHECK_TIMEOUT_2(VAR, VALUE) { mMMC_CHECK_TIMEOUT_1(VAR); } # else # define mMMC_CHECK_TIMEOUT_1(VAR) { VAR--; if (VAR == 0u) { return; } } # define mMMC_CHECK_TIMEOUT_2(VAR, VALUE) { VAR--; if (VAR == 0u) { return VALUE; } } # endif # define mMMC_CHECK_TIMEOUT_0() { ASSERT(0==1); } # define mMMC_CHECK_TIMEOUT_X(x, VAR, VALUE, FUNC, ...) FUNC # define mMMC_CHECK_TIMEOUT(...) \ mMMC_CHECK_TIMEOUT_X(,##__VA_ARGS__,\ mMMC_CHECK_TIMEOUT_2(__VA_ARGS__),\ mMMC_CHECK_TIMEOUT_1(__VA_ARGS__),\ mMMC_CHECK_TIMEOUT_0(__VA_ARGS__)) # define mMMC_DECLARE_TIMEOUT(VAR) uint64_t VAR # define mMMC_ARM_TIMEOUT(VAR) VAR = (uint64_t)CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS #else # define mMMC_CHECK_TIMEOUT(...) { ; } # define mMMC_DECLARE_TIMEOUT(...) { ; } # define mMMC_ARM_TIMEOUT(...) { ; } #endif /***************************************************************************//** * Macro Definitions */ /* MMC/SD/SDIO commands */ #define MMC_CMD_15_GOTO_INACTIVE_STATE 15u /* No Rsp */ #define MMC_CMD_4_SET_DSR 4u /* No Rsp */ #define MMC_CMD_0_GO_IDLE_STATE 0u /* No Rsp */ #define MMC_CMD_6_SWITCH 6u /* R1b Rsp */ #define MMC_CMD_7_SELECT_DESELECT_CARD 7u /* R1/R1b Rsp */ #define MMC_CMD_3_SET_RELATIVE_ADDR 3u /* R1 Rsp */ #define MMC_CMD_17_READ_SINGLE_BLOCK 17u /* R1 Rsp */ #define MMC_CMD_18_READ_MULTIPLE_BLOCK 18u /* R1 Rsp */ #define MMC_CMD_24_WRITE_SINGLE_BLOCK 24u /* R1 Rsp */ #define MMC_CMD_23_SET_BLOCK_COUNT 23u /* R1 Rsp */ #define MMC_CMD_25_WRITE_MULTI_BLOCK 25u /* R1 Rsp */ #define MMC_CMD_13_SEND_STATUS 13u /* R1 Rsp */ #define MMC_CMD_12_STOP_TRANSMISSION 12u /* R1/R1b Rsp */ #define MMC_CMD_8_SEND_EXT_CSD 8u /* R1 Rsp */ #define MMC_CMD_21_SEND_TUNE_BLK 21u /* R1 Rsp */ #define MMC_CMD_14_BUSTEST_R 14u /* R1 Rsp */ #define MMC_CMD_19_BUSTEST_W 19u /* R1 Rsp */ #define MMC_CMD_2_ALL_SEND_CID 2u /* R2 Rsp */ #define MMC_CMD_9_SEND_CSD 9u /* R2 Rsp */ #define MMC_CMD_10_SEND_CID 10u /* R2 Rsp */ #define MMC_CMD_1_SEND_OP_COND 1u /* R3 Rsp */ #define MMC_CMD_39_FAST_IO 39u /* R4 Rsp */ #define MMC_CMD_40_GO_IRQ_STATE 40u /* R5 Rsp */ #define SD_CMD_8_SEND_IF_COND 8u /* R7 Rsp */ #define SD_ACMD_41_SEND_OP_COND 41u /* R3 Rsp */ #define SD_ACMD_42_SET_CLR_CARD_DETECT 42u /* R1 Rsp */ #define SD_CMD_11_VOLAGE_SWITCH 11u /* R1 Rsp */ #define SD_CMD_19_SEND_TUNING_BLK 19u /* R1 Rsp */ #define SD_CMD_55 55u #define SD_CMD_5 5u /* R4 Rsp */ #define SD_ACMD_6 6u /* R1 Rsp */ #define SD_ACMD_51 51u /* R1 Rsp */ #define SD_CMD_6 6u /* R1 Rsp */ #define SD_CMD_16 16u /* R1 Rsp */ #define SDIO_CMD_52_IO_RW_DIRECT 52u /*R5 Rsp */ #define SDIO_CMD_53_IO_RW_EXTENDED 53u /*R5 Rsp */ /* eMMC/SD Response Type */ typedef enum { MSS_MMC_RESPONSE_NO_RESP = 0u, MSS_MMC_RESPONSE_R1 = 1u, MSS_MMC_RESPONSE_R1B = 2u, MSS_MMC_RESPONSE_R2 = 3u, MSS_MMC_RESPONSE_R3 = 4u, MSS_MMC_RESPONSE_R4 = 5u, MSS_MMC_RESPONSE_R5 = 6u, MSS_MMC_RESPONSE_R5B = 7u, MSS_MMC_RESPONSE_R6 = 8u, MSS_MMC_RESPONSE_R7 = 9u, MSS_MMC_RESPONSE_R1A = 10u } MSS_MMC_response_type; typedef enum { /* access mode - SDR12 default (CLK: max 25MHz, DT: max 12MB/s) */ MSS_MMC_ACCESS_MODE_SDR12 = 0u, /* access mode - SDR15 default (CLK: max 50MHz, DT: max 25MB/s) */ MSS_MMC_ACCESS_MODE_SDR25 = 1u, /* access mode - SDR50 default (CLK: max 100MHz, DT: max 50MB/s) */ MSS_MMC_ACCESS_MODE_SDR50 = 2u, /* access mode - SDR104 default (CLK: max 208MHz, DT: max 104MB/s) */ MSS_MMC_ACCESS_MODE_SDR104 = 3u, /* access mode - DDR50 default (CLK: max 50MHz, DT: max 50MB/s) */ MSS_MMC_ACCESS_MODE_DDR50 = 4u, /* access mode - ultra high speed II mode */ MSS_MMC_ACCESS_MODE_UHSII = 5u, /* MMC access mode - legacy mode (CLK: max 26MHz, DT: max 26MB/s) */ MSS_MMC_ACCESS_MODE_MMC_LEGACY = 6u, /* MMC access mode - high speed SDR mode (CLK: max 26MHz, DT: max 26MB/s) */ MSS_MMC_ACCESS_MODE_HS_SDR = 7u, /* MMC access mode - high speed DDR mode (CLK: max 52MHz, DT: max 104MB/s) */ MSS_MMC_ACCESS_MODE_HS_DDR = 8u, /* MMC access mode - HS200 mode (CLK: max 200MHz, DT: max 200MB/s) */ MSS_MMC_ACCESS_MODE_HS_200 = 9u, /* MMC access mode - HS400 mode (CLK: max 200MHz, DT: max 400MB/s) */ MSS_MMC_ACCESS_MODE_HS_400 = 10u, /* MMC access mode - HS400 using Enhanced Strobe (CLK: max 200MHz, DT: max 400MB/s) */ MSS_MMC_ACCESS_MODE_HS_400_ES = 11u, } MSS_MMC_speed_mode; /* PHY configuration delay type */ typedef enum { /* delay in the input path for High Speed work mode */ MSS_MMC_PHY_DELAY_INPUT_HIGH_SPEED = 0u, /* delay in the input path for Default Speed work mode */ MSS_MMC_PHY_DELAY_INPUT_DEFAULT_SPEED = 1u, /* delay in the input path for SDR12 work mode */ MSS_MMC_PHY_DELAY_INPUT_SDR12 = 2u, /* delay in the input path for SDR25 work mode */ MSS_MMC_PHY_DELAY_INPUT_SDR25 = 3u, /* delay in the input path for SDR50 work mode */ MSS_MMC_PHY_DELAY_INPUT_SDR50 = 4u, /* delay in the input path for DDR50 work mode */ MSS_MMC_PHY_DELAY_INPUT_DDR50 = 5u, /* delay in the input path for eMMC legacy work mode */ MSS_MMC_PHY_DELAY_INPUT_MMC_LEGACY = 6u, /* delay in the input path for eMMC SDR work mode */ MSS_MMC_PHY_DELAY_INPUT_MMC_SDR = 7u, /* delay in the input path for eMMC DDR work mode */ MSS_MMC_PHY_DELAY_INPUT_MMC_DDR = 8u, /* Value of the delay introduced on the sdclk output for all modes except * HS200, HS400 and HS400_ES */ MSS_MMC_PHY_DELAY_DLL_SDCLK = 11u, /* Value of the delay introduced on the sdclk output for HS200, HS400 and * HS400_ES speed mode */ MSS_MMC_PHY_DELAY_DLL_HS_SDCLK = 12u, /* Value of the delay introduced on the dat_strobe input used in * HS400 / HS400_ES speed mode. */ MSS_MMC_PHY_DELAY_DLL_DAT_STROBE = 13u, } MSS_MMC_phydelay; /********************************************************************** * Enumerations **********************************************************************/ /* CCCR card control registers definitions */ typedef enum { /* CCCR version number and SDIO specification version number register */ MSS_MMC_CCCR_SDIO_REV = 0u, /* SD version number register */ MSS_MMC_CCCR_SD_SPEC_REV = 1u, /* IO enable function register */ MSS_MMC_CCCR_IO_ENABLE = 2u, /* IO ready function register */ MSS_MMC_CCCR_IO_READY = 3u, /* interrupt enable register */ MSS_MMC_CCCR_INT_ENABLE = 4u, /* interrupt pending register */ MSS_MMC_CCCR_INT_PENDING = 5u, /* IO Abort register. It used to stop a function transfer. */ MSS_MMC_CCCR_ABORT = 6u, /* Bus interface control register */ MSS_MMC_CCCR_BUS_CONTROL = 7u, /* Card capability register */ MSS_MMC_CCCR_CARD_CAPABILITY = 8u, /* Pointer to card's common Card Information Structure (CIS) */ MSS_MMC_CCCR_CIS_POINTER = 9u, /* Bus suspend register */ MSS_MMC_CCCR_BUS_SUSPENDED = 12u, /* Function select register */ MSS_MMC_CCCR_FUNCTION_SELECT = 13u, /* Exec flags register. The bits of this register are used by the host to * determine the current execution status of all functions (1-7) and memory (0). */ MSS_MMC_CCCR_EXEC_FLAGS = 14u, /* Ready flags register. The bits of this register tell the host the read * or write busy status for functions (1-7) and memory (0). */ MSS_MMC_CCCR_READY_FLAGS = 15u, /* I/O block size for Function 0 */ MSS_MMC_CCCR_FN0_BLOCK_SIZE = 16u, /* Power control register */ MSS_MMC_CCCR_POWER_CONTROL = 18u, /* Bus speed select */ MSS_MMC_CCCR_HIGH_SPEED = 19u, /* UHS-I support info */ MSS_MMC_CCCR_UHSI_SUPPORT = 20u, /* Driver Strength */ MSS_MMC_CCCR_DRIVER_STRENGTH = 21u, /* Interrupt extension */ MSS_MMC_CCCR_INT_EXT = 22u, } MSS_MMC_cccr_reg_addr; /* FBR card control registers definitions */ typedef enum { MSS_MMC_FBR_STD_SDIO_FN = 0u, MSS_MMC_FBR_EXT_SDIO_FN = 1u, MSS_MMC_FBR_POWER_SEL = 2u, MSS_MMC_FBR_ADDR_CIS = 9u, MSS_MMC_FBR_ADDR_CSA = 12u, MSS_MMC_FBR_DATA_CSA = 15u, MSS_MMC_FBR_BLOCK_SIZE = 16u, } MSS_MMC_fbr_reg_addr; /* Tuple names definitions of SDIO card */ typedef enum { /* NULL tuple */ MSS_MMC_TUPLE_CISTPL_NULL = 0u, /* Checksum control */ MSS_MMC_TUPLE_CISTPL_CHECKSUM = 16u, /* Level 1 version/product information */ MSS_MMC_TUPLE_CISTPL_VERS_1 = 21u, /* Alternate language string tuple */ MSS_MMC_TUPLE_CISTPL_ALTSTR = 22u, /* Manufacturer identification string tuple */ MSS_MMC_TUPLE_CISTPL_MANFID = 32u, /* Function identification tuple */ MSS_MMC_TUPLE_CISTPL_FUNCID = 33u, /* Additional information for functions built to support application * specifications for standard SDIO functions. */ MSS_MMC_TUPLE_CISTPL_SDIO_STD = 145u, /* Reserved for future use with SDIO devices */ MSS_MMC_TUPLE_CISTPL_SDIO_EXT = 146u, /* The End-of-chain Tuple */ MSS_MMC_TUPLE_CISTPL_END = 255u, } MSS_MMC_tuple_code; #ifdef __cplusplus } #endif #endif /* __MSS_MMC_TYPE_H */ mss_mmuart/000077500000000000000000000000001432224323300354425ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_uart.c000066400000000000000000001404521432224323300374510ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC Microprocessor Subsystem MMUART bare metal software driver * implementation. * */ #include "mss_uart.h" #include "mss_uart_regs.h" #include "mss_plic.h" #include "mss_util.h" #include "mss_legacy_defines.h" #include "fpga_design_config/fpga_design_config.h" #ifdef __cplusplus extern "C" { #endif #define MSS_UART0_LO_BASE (MSS_UART_TypeDef*)0x20000000UL #define MSS_UART1_LO_BASE (MSS_UART_TypeDef*)0x20100000UL #define MSS_UART2_LO_BASE (MSS_UART_TypeDef*)0x20102000UL #define MSS_UART3_LO_BASE (MSS_UART_TypeDef*)0x20104000UL #define MSS_UART4_LO_BASE (MSS_UART_TypeDef*)0x20106000UL #define MSS_UART0_HI_BASE (MSS_UART_TypeDef*)0x28000000UL #define MSS_UART1_HI_BASE (MSS_UART_TypeDef*)0x28100000UL #define MSS_UART2_HI_BASE (MSS_UART_TypeDef*)0x28102000UL #define MSS_UART3_HI_BASE (MSS_UART_TypeDef*)0x28104000UL #define MSS_UART4_HI_BASE (MSS_UART_TypeDef*)0x28106000UL mss_uart_instance_t g_mss_uart0_lo; mss_uart_instance_t g_mss_uart1_lo; mss_uart_instance_t g_mss_uart2_lo; mss_uart_instance_t g_mss_uart3_lo; mss_uart_instance_t g_mss_uart4_lo; mss_uart_instance_t g_mss_uart0_hi; mss_uart_instance_t g_mss_uart1_hi; mss_uart_instance_t g_mss_uart2_hi; mss_uart_instance_t g_mss_uart3_hi; mss_uart_instance_t g_mss_uart4_hi; /* This variable tracks if the UART peripheral is located on S5 or S6 on AXI * switch. This will be used to determine which UART instance to be passed to * UART interrupt handler. value 0 = S5(low). value 1 = S6(high) * Bit positions: * 0 ==> MMUART0 * 1 ==> MMUART1 * 2 ==> MMUART2 * 3 ==> MMUART3 * 4 ==> MMUART4 */ static uint8_t g_uart_axi_pos = 0x0u; /******************************************************************************* * Defines */ #define TX_COMPLETE 0u #define TX_FIFO_SIZE 16u #define FCR_TRIG_LEVEL_MASK 0xC0u #define IIRF_MASK 0x0Fu #define INVALID_INTERRUPT 0u #define INVALID_IRQ_HANDLER ((mss_uart_irq_handler_t) 0) #define NULL_HANDLER ((mss_uart_irq_handler_t) 0) #define MSS_UART_DATA_READY ((uint8_t) 0x01) #define SYNC_ASYNC_MODE_MASK (0x7u) /******************************************************************************* * Possible values for Interrupt Identification Register Field. */ #define IIRF_MODEM_STATUS 0x00u #define IIRF_THRE 0x02u #define IIRF_MMI 0x03u #define IIRF_RX_DATA 0x04u #define IIRF_RX_LINE_STATUS 0x06u #define IIRF_DATA_TIMEOUT 0x0Cu /******************************************************************************* * Receiver error status mask. */ #define STATUS_ERROR_MASK ( MSS_UART_OVERUN_ERROR | MSS_UART_PARITY_ERROR | \ MSS_UART_FRAMING_ERROR | MSS_UART_BREAK_ERROR | \ MSS_UART_FIFO_ERROR) /******************************************************************************* * Local functions. */ static void global_init(mss_uart_instance_t * this_uart, uint32_t baud_rate, uint8_t line_config); static void uart_isr(mss_uart_instance_t * this_uart); static void default_tx_handler(mss_uart_instance_t * this_uart); static void enable_irq(const mss_uart_instance_t * this_uart); static void disable_irq(const mss_uart_instance_t * this_uart); static void config_baud_divisors ( mss_uart_instance_t * this_uart, uint32_t baudrate ); /******************************************************************************* * Public Functions *******************************************************************************/ /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config ) { /* Perform generic initialization */ global_init(this_uart, baud_rate, line_config); /* Disable LIN mode */ this_uart->hw_reg->MM0 &= ~ELIN_MASK; /* Disable IrDA mode */ this_uart->hw_reg->MM1 &= ~EIRD_MASK; /* Disable SmartCard Mode */ this_uart->hw_reg->MM2 &= ~EERR_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_lin_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config ) { /* Perform generic initialization */ global_init(this_uart, baud_rate, line_config); /* Enable LIN mode */ this_uart->hw_reg->MM0 |= ELIN_MASK; /* Disable IrDA mode */ this_uart->hw_reg->MM1 &= ~EIRD_MASK; /* Disable SmartCard Mode */ this_uart->hw_reg->MM2 &= ~EERR_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_irda_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config, mss_uart_rzi_polarity_t rxpol, mss_uart_rzi_polarity_t txpol, mss_uart_rzi_pulsewidth_t pw ) { /* Perform generic initialization */ global_init(this_uart, baud_rate, line_config); /* Enable LIN mode */ this_uart->hw_reg->MM0 &= ~ELIN_MASK; /* Disable IrDA mode */ this_uart->hw_reg->MM1 |= EIRD_MASK; ((rxpol == MSS_UART_ACTIVE_LOW) ? (this_uart->hw_reg->MM1 &= ~EIRX_MASK) : (this_uart->hw_reg->MM1 |= EIRX_MASK)); ((txpol == MSS_UART_ACTIVE_LOW) ? (this_uart->hw_reg->MM1 &= ~EITX_MASK) : (this_uart->hw_reg->MM1 |= EITX_MASK)); ((pw == MSS_UART_3_BY_16) ? (this_uart->hw_reg->MM1 &= ~EITP_MASK) : (this_uart->hw_reg->MM1 |= EITP_MASK)); /* Disable SmartCard Mode */ this_uart->hw_reg->MM2 &= ~EERR_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_smartcard_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config ) { /* Perform generic initialization */ global_init(this_uart, baud_rate, line_config); /* Disable LIN mode */ this_uart->hw_reg->MM0 &= ~ELIN_MASK; /* Disable IrDA mode */ this_uart->hw_reg->MM1 &= ~EIRD_MASK; /* Enable SmartCard Mode : Only when data is 8-bit and 2 stop bits*/ if ((MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS) == (line_config & (MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS))) { this_uart->hw_reg->MM2 |= EERR_MASK; /* Enable single wire half-duplex mode */ this_uart->hw_reg->MM2 |= ESWM_MASK; } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_polled_tx ( mss_uart_instance_t * this_uart, const uint8_t * pbuff, uint32_t tx_size ) { uint32_t char_idx = 0u; uint32_t size_sent; uint8_t status; uint32_t temp_tx_size = tx_size; ASSERT(pbuff != ( (uint8_t*)0)); ASSERT(tx_size > 0u); if ((pbuff != ((uint8_t*)0)) && (temp_tx_size > 0u)) { /* Remain in this loop until the entire input buffer * has been transferred to the UART. */ do { /* Read the Line Status Register and update the sticky record */ status = this_uart->hw_reg->LSR; this_uart->status |= status; /* Check if TX FIFO is empty. */ if (status & MSS_UART_THRE) { uint32_t fill_size = TX_FIFO_SIZE; /* Calculate the number of bytes to transmit. */ if (temp_tx_size < TX_FIFO_SIZE) { fill_size = temp_tx_size; } /* Fill the TX FIFO with the calculated the number of bytes. */ for (size_sent = 0u; size_sent < fill_size; ++size_sent) { /* Send next character in the buffer. */ this_uart->hw_reg->THR = pbuff[char_idx]; char_idx++; } /* Calculate the number of bytes remaining(not transmitted yet)*/ temp_tx_size -= size_sent; } }while (temp_tx_size); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_polled_tx_string ( mss_uart_instance_t * this_uart, const uint8_t * p_sz_string ) { uint32_t char_idx = 0u; uint32_t fill_size; uint8_t data_byte; uint8_t status; ASSERT(p_sz_string != ((uint8_t*)0)); if (p_sz_string != ((uint8_t*)0)) { /* Get the first data byte from the input buffer */ data_byte = p_sz_string[char_idx]; /* First check for the NULL terminator byte. * Then remain in this loop until the entire string in the input buffer * has been transferred to the UART. */ while (0u != data_byte) { /* Wait until TX FIFO is empty. */ do { status = this_uart->hw_reg->LSR; this_uart->status |= status; }while (0u == (status & MSS_UART_THRE)); /* Send bytes from the input buffer until the TX FIFO is full * or we reach the NULL terminator byte. */ fill_size = 0u; while ((0u != data_byte) && (fill_size < TX_FIFO_SIZE)) { /* Send the data byte */ this_uart->hw_reg->THR = data_byte; ++fill_size; char_idx++; /* Get the next data byte from the input buffer */ data_byte = p_sz_string[char_idx]; } } } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_irq_tx ( mss_uart_instance_t * this_uart, const uint8_t * pbuff, uint32_t tx_size ) { ASSERT(pbuff != ((uint8_t*)0)); ASSERT(tx_size > 0u); if ((tx_size > 0u) && (pbuff != ((uint8_t*)0))) { /*Initialize the transmit info for the UART instance with the arguments*/ this_uart->tx_buffer = pbuff; this_uart->tx_buff_size = tx_size; this_uart->tx_idx = 0u; /* assign default handler for data transfer */ this_uart->tx_handler = default_tx_handler; /* enables TX interrupt */ this_uart->hw_reg->IER |= ETBEI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ int8_t MSS_UART_tx_complete ( mss_uart_instance_t * this_uart ) { int8_t ret_value = 0; uint8_t status = 0u; /* Read the Line Status Register and update the sticky record. */ status = this_uart->hw_reg->LSR; this_uart->status |= status; if ((TX_COMPLETE == this_uart->tx_buff_size) && ((status & MSS_UART_TEMT) != 0u)) { ret_value = (int8_t)1; } return ret_value; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ size_t MSS_UART_get_rx ( mss_uart_instance_t * this_uart, uint8_t * rx_buff, size_t buff_size ) { size_t rx_size = 0u; uint8_t status = 0u; ASSERT(rx_buff != ((uint8_t*)0)); ASSERT(buff_size > 0u); if ((rx_buff != (uint8_t*)0) && (buff_size > 0u)) { status = this_uart->hw_reg->LSR; this_uart->status |= status; while (((status & MSS_UART_DATA_READY) != 0u) && (rx_size < buff_size)) { rx_buff[rx_size] = this_uart->hw_reg->RBR; ++rx_size; status = this_uart->hw_reg->LSR; this_uart->status |= status; } } return rx_size; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_irq ( mss_uart_instance_t * this_uart, mss_uart_irq_t irq_mask ) { ASSERT(MSS_UART_INVALID_IRQ > irq_mask); enable_irq(this_uart); if (MSS_UART_INVALID_IRQ > irq_mask) { /* irq_mask encoding: 1- enable * bit 0 - Receive Data Available Interrupt * bit 1 - Transmitter Holding Register Empty Interrupt * bit 2 - Receiver Line Status Interrupt * bit 3 - Modem Status Interrupt */ this_uart->hw_reg->IER |= ((uint8_t)(((uint32_t)irq_mask & (uint32_t)IIRF_MASK))); /* * bit 4 - Receiver time-out interrupt * bit 5 - NACK / ERR signal interrupt * bit 6 - PID parity error interrupt * bit 7 - LIN break detection interrupt * bit 8 - LIN Sync detection interrupt */ this_uart->hw_reg->IEM |= (uint8_t)(((uint32_t)irq_mask >> 4u) & ((uint32_t)IIRF_MASK)); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_disable_irq ( mss_uart_instance_t * this_uart, mss_uart_irq_t irq_mask ) { /* irq_mask encoding: 1 - disable * bit 0 - Receive Data Available Interrupt * bit 1 - Transmitter Holding Register Empty Interrupt * bit 2 - Receiver Line Status Interrupt * bit 3 - Modem Status Interrupt */ this_uart->hw_reg->IER &= ((uint8_t)(~((uint32_t)irq_mask & (uint32_t)IIRF_MASK))); /* * bit 4 - Receiver time-out interrupt * bit 5 - NACK / ERR signal interrupt * bit 6 - PID parity error interrupt * bit 7 - LIN break detection interrupt * bit 8 - LIN Sync detection interrupt */ this_uart->hw_reg->IEM &= (uint8_t)(~(((uint32_t)irq_mask >> 4u) & ((uint32_t)IIRF_MASK))); disable_irq(this_uart); } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_rx_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler, mss_uart_rx_trig_level_t trigger_level ) { ASSERT(handler != INVALID_IRQ_HANDLER ); ASSERT(trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL); if ((handler != INVALID_IRQ_HANDLER) && (trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL)) { this_uart->rx_handler = handler; /* Set the receive interrupt trigger level. */ this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | (uint8_t)trigger_level; /* Enable receive interrupt. */ this_uart->hw_reg->IER |= ERBFI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_loopback ( mss_uart_instance_t * this_uart, mss_uart_loopback_t loopback ) { ASSERT(MSS_UART_INVALID_LOOPBACK > loopback); if (MSS_UART_INVALID_LOOPBACK > loopback) { switch (loopback) { case MSS_UART_LOCAL_LOOPBACK_OFF: /* Disable local loopback */ this_uart->hw_reg->MCR &= ~LOOP_MASK; break; case MSS_UART_LOCAL_LOOPBACK_ON: /* Enable local loopback */ this_uart->hw_reg->MCR |= LOOP_MASK; break; case MSS_UART_REMOTE_LOOPBACK_OFF: case MSS_UART_AUTO_ECHO_OFF: /* Disable remote loopback & automatic echo*/ this_uart->hw_reg->MCR &= ~(RLOOP_MASK|ECHO_MASK); break; case MSS_UART_REMOTE_LOOPBACK_ON: /* Enable remote loopback */ this_uart->hw_reg->MCR |= (1u << RLOOP); break; case MSS_UART_AUTO_ECHO_ON: /* Enable automatic echo */ this_uart->hw_reg->MCR |= (1u << ECHO); break; case MSS_UART_INVALID_LOOPBACK: /* Fall through to default. */ default: ASSERT(0); break; } } } /***************************************************************************//** * interrupt service routine. */ uint8_t mmuart0_plic_77_IRQHandler(void) { if (g_uart_axi_pos & 0x01u) { uart_isr(&g_mss_uart0_hi); } else { uart_isr(&g_mss_uart0_lo); } return EXT_IRQ_KEEP_ENABLED; } uint8_t mmuart1_plic_IRQHandler(void) { if (g_uart_axi_pos & 0x02u) { uart_isr(&g_mss_uart1_hi); } else { uart_isr(&g_mss_uart1_lo); } return EXT_IRQ_KEEP_ENABLED; } uint8_t mmuart2_plic_IRQHandler(void) { if (g_uart_axi_pos & 0x04u) { uart_isr(&g_mss_uart2_hi); } else { uart_isr(&g_mss_uart2_lo); } return EXT_IRQ_KEEP_ENABLED; } uint8_t mmuart3_plic_IRQHandler(void) { if (g_uart_axi_pos & 0x08u) { uart_isr(&g_mss_uart3_hi); } else { uart_isr(&g_mss_uart3_lo); } return EXT_IRQ_KEEP_ENABLED; } uint8_t mmuart4_plic_IRQHandler(void) { if (g_uart_axi_pos & 0x10u) { uart_isr(&g_mss_uart4_hi); } else { uart_isr(&g_mss_uart4_lo); } return EXT_IRQ_KEEP_ENABLED; } void mmuart0_e51_local_IRQHandler_11(void) { if (g_uart_axi_pos & 0x01u) { uart_isr(&g_mss_uart0_hi); } else { uart_isr(&g_mss_uart0_lo); } } void mmuart_u54_h1_local_IRQHandler_11(void) { if (g_uart_axi_pos & 0x01u) { uart_isr(&g_mss_uart1_hi); } else { uart_isr(&g_mss_uart1_lo); } } void mmuart_u54_h2_local_IRQHandler_11(void) { if (g_uart_axi_pos & 0x01u) { uart_isr(&g_mss_uart2_hi); } else { uart_isr(&g_mss_uart2_lo); } } void mmuart_u54_h3_local_IRQHandler_11(void) { if (g_uart_axi_pos & 0x01u) { uart_isr(&g_mss_uart3_hi); } else { uart_isr(&g_mss_uart3_lo); } } void mmuart_u54_h4_local_IRQHandler_11(void) { if (g_uart_axi_pos & 0x01u) { uart_isr(&g_mss_uart4_hi); } else { uart_isr(&g_mss_uart4_lo); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_rxstatus_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->linests_handler = handler; /* Enable receiver line status interrupt. */ this_uart->hw_reg->IER |= ELSI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_tx_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->tx_handler = handler; /* Make TX buffer info invalid */ this_uart->tx_buffer = (const uint8_t*)0; this_uart->tx_buff_size = 0u; /* Enable transmitter holding register Empty interrupt. */ this_uart->hw_reg->IER |= ETBEI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_modemstatus_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->modemsts_handler = handler; /* Enable modem status interrupt. */ this_uart->hw_reg->IER |= EDSSI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ size_t MSS_UART_fill_tx_fifo ( mss_uart_instance_t * this_uart, const uint8_t * tx_buffer, size_t tx_size ) { uint8_t status = 0u; uint32_t size_sent = 0u; ASSERT(tx_buffer != ( (uint8_t*)0)); ASSERT(tx_size > 0); /* Fill the UART's Tx FIFO until the FIFO is full or the complete input * buffer has been written. */ if ((tx_buffer != ((uint8_t*)0)) && (tx_size > 0u)) { status = this_uart->hw_reg->LSR; this_uart->status |= status; if (status & MSS_UART_THRE) { uint32_t fill_size = TX_FIFO_SIZE; if (tx_size < TX_FIFO_SIZE) { fill_size = tx_size; } /* Fill up FIFO */ for (size_sent = 0u; size_sent < fill_size; size_sent++) { /* Send next character in the buffer. */ this_uart->hw_reg->THR = tx_buffer[size_sent]; } } } return size_sent; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ uint8_t MSS_UART_get_rx_status ( mss_uart_instance_t * this_uart ) { uint8_t status = MSS_UART_INVALID_PARAM; /* * Extract UART receive error status. * Bit 1 - Overflow error status * Bit 2 - Parity error status * Bit 3 - Frame error status * Bit 4 - Break interrupt indicator * Bit 7 - FIFO data error status */ this_uart->status |= (this_uart->hw_reg->LSR); status = (this_uart->status & STATUS_ERROR_MASK); /* Clear the sticky status after reading */ this_uart->status = 0u; return status; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ uint8_t MSS_UART_get_modem_status ( const mss_uart_instance_t * this_uart ) { uint8_t status = MSS_UART_INVALID_PARAM; /* * Extract UART modem status and place in lower bits of "status". * Bit 0 - Delta Clear to Send Indicator * Bit 1 - Delta Clear to Receive Indicator * Bit 2 - Trailing edge of Ring Indicator detector * Bit 3 - Delta Data Carrier Detect indicator * Bit 4 - Clear To Send * Bit 5 - Data Set Ready * Bit 6 - Ring Indicator * Bit 7 - Data Carrier Detect */ status = this_uart->hw_reg->MSR; return status; } /***************************************************************************//** * MSS_UART_get_tx_status. * See mss_uart.h for details of how to use this function. */ uint8_t MSS_UART_get_tx_status ( mss_uart_instance_t * this_uart ) { uint8_t status = MSS_UART_TX_BUSY; /* Read the Line Status Register and update the sticky record. */ status = this_uart->hw_reg->LSR; this_uart->status |= status; /* * Extract the transmit status bits from the UART's Line Status Register. * Bit 5 - Transmitter Holding Register/FIFO Empty (THRE) status. (If = 1, TX FIFO is empty) * Bit 6 - Transmitter Empty (TEMT) status. (If = 1, both TX FIFO and shift register are empty) */ status &= (MSS_UART_THRE | MSS_UART_TEMT); return status; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_break ( mss_uart_instance_t * this_uart ) { /* set break character on Tx line */ this_uart->hw_reg->LCR |= SB_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_clear_break ( mss_uart_instance_t * this_uart ) { /* remove break character from Tx line */ this_uart->hw_reg->LCR &= ~SB_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_pidpei_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->pid_pei_handler = handler; /* Enable PID parity error interrupt. */ this_uart->hw_reg->IEM |= EPID_PEI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_linbreak_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->break_handler = handler; /* Enable LIN break detection interrupt. */ this_uart->hw_reg->IEM |= ELINBI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_linsync_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->sync_handler = handler; /* Enable LIN sync detection interrupt. */ this_uart->hw_reg->IEM |= ELINSI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_nack_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->nack_handler = handler; /* Enable LIN sync detection interrupt. */ this_uart->hw_reg->IEM |= ENACKI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_rx_timeout_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ) { ASSERT(handler != INVALID_IRQ_HANDLER); if (handler != INVALID_IRQ_HANDLER) { this_uart->rto_handler = handler; /* Enable receiver timeout interrupt. */ this_uart->hw_reg->IEM |= ERTOI_MASK; enable_irq(this_uart); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_half_duplex ( mss_uart_instance_t * this_uart ) { /* enable single wire half-duplex mode */ this_uart->hw_reg->MM2 |= ESWM_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_disable_half_duplex ( mss_uart_instance_t * this_uart ) { /* enable single wire half-duplex mode */ this_uart->hw_reg->MM2 &= ~ESWM_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_rx_endian ( mss_uart_instance_t * this_uart, mss_uart_endian_t endian ) { ASSERT(MSS_UART_INVALID_ENDIAN > endian); if (MSS_UART_INVALID_ENDIAN > endian) { /* Configure MSB first / LSB first for receiver */ ((MSS_UART_LITTLEEND == endian) ? (this_uart->hw_reg->MM1 &= ~E_MSB_RX_MASK) : (this_uart->hw_reg->MM1 |= E_MSB_RX_MASK)); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_tx_endian ( mss_uart_instance_t * this_uart, mss_uart_endian_t endian ) { ASSERT(MSS_UART_INVALID_ENDIAN > endian); if (MSS_UART_INVALID_ENDIAN > endian) { /* Configure MSB first / LSB first for transmitter */ ((MSS_UART_LITTLEEND == endian) ? (this_uart->hw_reg->MM1 &= ~E_MSB_TX_MASK) : (this_uart->hw_reg->MM1 |= E_MSB_TX_MASK)) ; } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_filter_length ( mss_uart_instance_t * this_uart, mss_uart_filter_length_t length ) { ASSERT(MSS_UART_INVALID_FILTER_LENGTH > length); if (MSS_UART_INVALID_FILTER_LENGTH > length) { /* Configure glitch filter length */ this_uart->hw_reg->GFR = (uint8_t)length; } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_afm ( mss_uart_instance_t * this_uart ) { /* Disable RX FIFO till address flag with correct address is received */ this_uart->hw_reg->MM2 |= EAFM_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_disable_afm ( mss_uart_instance_t * this_uart ) { /* Enable RX FIFO irrespective of address flag and correct address is received */ this_uart->hw_reg->MM2 &= ~EAFM_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_afclear ( mss_uart_instance_t * this_uart ) { /* Enable address flag clearing */ /* Disable RX FIFO till another address flag with correct address is received */ this_uart->hw_reg->MM2 |= EAFC_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_disable_afclear ( mss_uart_instance_t * this_uart ) { /* Disable address flag clearing */ this_uart->hw_reg->MM2 &= ~EAFC_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_rx_timeout ( mss_uart_instance_t * this_uart, uint8_t timeout ) { /* Load the receive timeout value */ this_uart->hw_reg->RTO = timeout; /*Enable receiver time-out */ this_uart->hw_reg->MM0 |= ERTO_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_disable_rx_timeout ( mss_uart_instance_t * this_uart ) { /*Disable receiver time-out */ this_uart->hw_reg->MM0 &= ~ERTO_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_tx_time_guard ( mss_uart_instance_t * this_uart, uint8_t timeguard ) { /* Load the transmitter time guard value */ this_uart->hw_reg->TTG = timeguard; /*Enable transmitter time guard */ this_uart->hw_reg->MM0 |= ETTG_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_disable_tx_time_guard ( mss_uart_instance_t * this_uart ) { /*Disable transmitter time guard */ this_uart->hw_reg->MM0 &= ~ETTG_MASK; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_address ( mss_uart_instance_t * this_uart, uint8_t address ) { this_uart->hw_reg->ADR = address; } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_ready_mode ( mss_uart_instance_t * this_uart, mss_uart_ready_mode_t mode ) { ASSERT(MSS_UART_INVALID_READY_MODE > mode); if (MSS_UART_INVALID_READY_MODE > mode ) { /* Configure mode 0 or mode 1 for TXRDY and RXRDY */ ((MSS_UART_READY_MODE0 == mode) ? (this_uart->hw_reg->FCR &= ~RDYMODE_MASK) : (this_uart->hw_reg->FCR |= RDYMODE_MASK) ); } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_set_usart_mode ( mss_uart_instance_t * this_uart, mss_uart_usart_mode_t mode ) { ASSERT(MSS_UART_INVALID_SYNC_MODE > mode); if (MSS_UART_INVALID_SYNC_MODE > mode) { /* Nothing to do for the baudrate: operates at PCLK / 2 + glitch filter length */ /* Clear the ESYN bits 2:0 */ this_uart->hw_reg->MM0 &= ~SYNC_ASYNC_MODE_MASK; this_uart->hw_reg->MM0 |= (uint8_t)mode; } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ void MSS_UART_enable_local_irq ( const mss_uart_instance_t * this_uart ) { /*Make sure to disable interrupt on PLIC as it might have been enabled * when application registered an interrupt handler function or * used MSS_UART_enable_irq() to enable PLIC interrupt */ disable_irq(this_uart); /* Enable local interrupt UART instance. * Local interrupt will be enabled on the HART on which the application * calling this API is being executed*/ __enable_local_irq((int8_t)MMUART0_E51_INT); } /******************************************************************************* * Local Functions *******************************************************************************/ /******************************************************************************* * Global initialization for all modes */ static void global_init ( mss_uart_instance_t * this_uart, uint32_t baud_rate, uint8_t line_config ) { if ((&g_mss_uart0_lo == this_uart)) { this_uart->hw_reg = MSS_UART0_LO_BASE; g_uart_axi_pos &= ~0x01u; } else if (&g_mss_uart1_lo == this_uart) { this_uart->hw_reg = MSS_UART1_LO_BASE; g_uart_axi_pos &= ~0x02u; } else if (&g_mss_uart2_lo == this_uart) { this_uart->hw_reg = MSS_UART2_LO_BASE; g_uart_axi_pos &= ~0x04u; } else if (&g_mss_uart3_lo == this_uart) { this_uart->hw_reg = MSS_UART3_LO_BASE; g_uart_axi_pos &= ~0x08u; } else if (&g_mss_uart4_lo == this_uart) { this_uart->hw_reg = MSS_UART4_LO_BASE; g_uart_axi_pos &= ~0x10u; } else if ((&g_mss_uart0_hi == this_uart)) { this_uart->hw_reg = MSS_UART0_HI_BASE; g_uart_axi_pos |= 0x01u; } else if (&g_mss_uart1_hi == this_uart) { this_uart->hw_reg = MSS_UART1_HI_BASE; g_uart_axi_pos |= 0x02u; } else if (&g_mss_uart2_hi == this_uart) { this_uart->hw_reg = MSS_UART2_HI_BASE; g_uart_axi_pos |= 0x04u; } else if (&g_mss_uart3_hi == this_uart) { this_uart->hw_reg = MSS_UART3_HI_BASE; g_uart_axi_pos |= 0x08u; } else if (&g_mss_uart4_hi == this_uart) { this_uart->hw_reg = MSS_UART4_HI_BASE; g_uart_axi_pos |= 0x10u; } else { ASSERT(0); /*Comment to avoid LDRA warning*/ } /* disable interrupts */ this_uart->hw_reg->IER = 0u; /* FIFO configuration */ this_uart->hw_reg->FCR = 0u; /* clear receiver FIFO */ this_uart->hw_reg->FCR |= CLEAR_RX_FIFO_MASK; /* clear transmitter FIFO */ this_uart->hw_reg->FCR |= CLEAR_TX_FIFO_MASK; /* set default READY mode : Mode 0*/ /* enable RXRDYN and TXRDYN pins. The earlier FCR write to set the TX FIFO * trigger level inadvertently disabled the FCR_RXRDY_TXRDYN_EN bit. */ this_uart->hw_reg->FCR |= RXRDY_TXRDYN_EN_MASK; /* disable loopback : local * remote */ this_uart->hw_reg->MCR &= ~LOOP_MASK; this_uart->hw_reg->MCR &= ~RLOOP_MASK; /* set default TX endian */ this_uart->hw_reg->MM1 &= ~E_MSB_TX_MASK; /* set default RX endian */ this_uart->hw_reg->MM1 &= ~E_MSB_RX_MASK; /* default AFM : disabled */ this_uart->hw_reg->MM2 &= ~EAFM_MASK; /* disable TX time guard */ this_uart->hw_reg->MM0 &= ~ETTG_MASK; /* set default RX timeout */ this_uart->hw_reg->MM0 &= ~ERTO_MASK; /* disable fractional baud-rate */ this_uart->hw_reg->MM0 &= ~EFBR_MASK; /* disable single wire mode */ this_uart->hw_reg->MM2 &= ~ESWM_MASK; /* set filter to minimum value */ this_uart->hw_reg->GFR = 0u; /* set default TX time guard */ this_uart->hw_reg->TTG = 0u; /* set default RX timeout */ this_uart->hw_reg->RTO = 0u; /* * Configure baud rate divisors. This uses the fractional baud rate divisor * where possible to provide the most accurate baud rat possible. */ config_baud_divisors(this_uart, baud_rate); /* set the line control register (bit length, stop bits, parity) */ this_uart->hw_reg->LCR = line_config; /* Instance setup */ this_uart->baudrate = baud_rate; this_uart->lineconfig = line_config; this_uart->tx_buff_size = TX_COMPLETE; this_uart->tx_buffer = (const uint8_t*)0; this_uart->tx_idx = 0u; /* Default handlers for MSS UART interrupts */ this_uart->rx_handler = NULL_HANDLER; this_uart->tx_handler = NULL_HANDLER; this_uart->linests_handler = NULL_HANDLER; this_uart->modemsts_handler = NULL_HANDLER; this_uart->rto_handler = NULL_HANDLER; this_uart->nack_handler = NULL_HANDLER; this_uart->pid_pei_handler = NULL_HANDLER; this_uart->break_handler = NULL_HANDLER; this_uart->sync_handler = NULL_HANDLER; /* Initialize the sticky status */ this_uart->status = 0u; } /***************************************************************************//** * Configure baud divisors using fractional baud rate if possible. */ static void config_baud_divisors ( mss_uart_instance_t * this_uart, uint32_t baudrate ) { uint32_t baud_value; uint32_t baud_value_by_64; uint32_t baud_value_by_128; uint32_t fractional_baud_value; uint64_t pclk_freq; this_uart->baudrate = baudrate; /* Use the system clock value from hw_platform.h */ pclk_freq = LIBERO_SETTING_MSS_APB_AHB_CLK; /* * Compute baud value based on requested baud rate and PCLK frequency. * The baud value is computed using the following equation: * baud_value = PCLK_Frequency / (baud_rate * 16) */ baud_value_by_128 = (uint32_t)((8UL * pclk_freq) / baudrate); baud_value_by_64 = baud_value_by_128 / 2u; baud_value = baud_value_by_64 / 64u; fractional_baud_value = baud_value_by_64 - (baud_value * 64u); fractional_baud_value += (baud_value_by_128 - (baud_value * 128u)) - (fractional_baud_value * 2u); /* Assert if integer baud value fits in 16-bit. */ ASSERT(baud_value <= UINT16_MAX); if (baud_value <= (uint32_t)UINT16_MAX) { if (baud_value > 1u) { /* * Use Fractional baud rate divisors */ /* set divisor latch */ this_uart->hw_reg->LCR |= DLAB_MASK; /* msb of baud value */ this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8); /* lsb of baud value */ this_uart->hw_reg->DLR = (uint8_t)baud_value; /* reset divisor latch */ this_uart->hw_reg->LCR &= ~DLAB_MASK; /* Enable Fractional baud rate */ this_uart->hw_reg->MM0 |= EFBR_MASK; /* Load the fractional baud rate register */ ASSERT(fractional_baud_value <= (uint32_t)UINT8_MAX); this_uart->hw_reg->DFR = (uint8_t)fractional_baud_value; } else { /* * Do NOT use Fractional baud rate divisors. */ /* set divisor latch */ this_uart->hw_reg->LCR |= DLAB_MASK; /* msb of baud value */ this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8u); /* lsb of baud value */ this_uart->hw_reg->DLR = (uint8_t)baud_value; /* reset divisor latch */ this_uart->hw_reg->LCR &= ~DLAB_MASK; /* Disable Fractional baud rate */ this_uart->hw_reg->MM0 &= ~EFBR_MASK; } } } /***************************************************************************//** * Interrupt service routine triggered by any MSS UART interrupt. This routine * will call the handler function appropriate to the interrupt from the * handlers previously registered with the driver through calls to the * MSS_UART_set_*_handler() functions, or it will call the default_tx_handler() * function in response to transmit interrupts if MSS_UART_irq_tx() is used to * transmit data. */ static void uart_isr ( mss_uart_instance_t * this_uart ) { uint8_t iirf; iirf = this_uart->hw_reg->IIR & IIRF_MASK; switch (iirf) { case IIRF_MODEM_STATUS: /* Modem status interrupt */ { ASSERT(NULL_HANDLER != this_uart->modemsts_handler); if (NULL_HANDLER != this_uart->modemsts_handler) { (*(this_uart->modemsts_handler))(this_uart); } } break; case IIRF_THRE: /* Transmitter Holding Register Empty */ { ASSERT(NULL_HANDLER != this_uart->tx_handler); if (NULL_HANDLER != this_uart->tx_handler) { (*(this_uart->tx_handler))(this_uart); } } break; case IIRF_RX_DATA: /* Received Data Available */ case IIRF_DATA_TIMEOUT: /* Received Data Timed-out */ { ASSERT(NULL_HANDLER != this_uart->rx_handler); if (NULL_HANDLER != this_uart->rx_handler) { (*(this_uart->rx_handler))(this_uart); } } break; case IIRF_RX_LINE_STATUS: /* Line Status Interrupt */ { ASSERT(NULL_HANDLER != this_uart->linests_handler); if (NULL_HANDLER != this_uart->linests_handler) { (*(this_uart->linests_handler))(this_uart); } } break; case IIRF_MMI: { /* Identify multi-mode interrupts and handle */ /* Receiver time-out interrupt */ if (this_uart->hw_reg->IIM & ERTOI_MASK) { ASSERT(NULL_HANDLER != this_uart->rto_handler); if (NULL_HANDLER != this_uart->rto_handler) { (*(this_uart->rto_handler))(this_uart); } } /* NACK interrupt */ if (this_uart->hw_reg->IIM &ENACKI) { ASSERT(NULL_HANDLER != this_uart->nack_handler); if (NULL_HANDLER != this_uart->nack_handler) { (*(this_uart->nack_handler))(this_uart); } } /* PID parity error interrupt */ if (this_uart->hw_reg->IIM & EPID_PEI) { ASSERT(NULL_HANDLER != this_uart->pid_pei_handler); if (NULL_HANDLER != this_uart->pid_pei_handler) { (*(this_uart->pid_pei_handler))(this_uart); } } /* LIN break detection interrupt */ if (this_uart->hw_reg->IIM & ELINBI) { ASSERT(NULL_HANDLER != this_uart->break_handler); if (NULL_HANDLER != this_uart->break_handler) { (*(this_uart->break_handler))(this_uart); } } /* LIN Sync detection interrupt */ if (this_uart->hw_reg->IIM & ELINSI) { ASSERT(NULL_HANDLER != this_uart->sync_handler); if (NULL_HANDLER != this_uart->sync_handler) { (*(this_uart->sync_handler))(this_uart); } } break; } default: { ASSERT(INVALID_INTERRUPT); /*Alternative case has been considered*/ } break; } } /***************************************************************************//** * See mss_uart.h for details of how to use this function. */ static void default_tx_handler ( mss_uart_instance_t * this_uart ) { uint8_t status; ASSERT(( (uint8_t*)0 ) != this_uart->tx_buffer); ASSERT(0u < this_uart->tx_buff_size); if ((((uint8_t*)0 ) != this_uart->tx_buffer) && (0u < this_uart->tx_buff_size)) { /* Read the Line Status Register and update the sticky record. */ status = this_uart->hw_reg->LSR; this_uart->status |= status; /* * This function should only be called as a result of a THRE interrupt. * Verify that this is true before proceeding to transmit data. */ if (status & MSS_UART_THRE) { uint32_t cnt; uint32_t fill_size = TX_FIFO_SIZE; uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx; /* Calculate the number of bytes to transmit. */ if (tx_remain < TX_FIFO_SIZE) { fill_size = tx_remain; } /* Fill the TX FIFO with the calculated the number of bytes. */ for (cnt = 0u; cnt < fill_size; ++cnt) { /* Send next character in the buffer. */ this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx]; ++this_uart->tx_idx; } } /* Flag Tx as complete if all data has been pushed into the Tx FIFO. */ if (this_uart->tx_idx == this_uart->tx_buff_size) { this_uart->tx_buff_size = TX_COMPLETE; /* disables TX interrupt */ this_uart->hw_reg->IER &= ~ETBEI_MASK; } } } static void enable_irq ( const mss_uart_instance_t * this_uart ) { PLIC_IRQn_Type plic_num = 0; if (((&g_mss_uart0_lo == this_uart)) || ((&g_mss_uart0_hi == this_uart))) { plic_num = MMUART0_PLIC_77; } else if (((&g_mss_uart1_lo == this_uart)) || ((&g_mss_uart1_hi == this_uart))) { plic_num = MMUART1_PLIC; } else if (((&g_mss_uart2_lo == this_uart)) || ((&g_mss_uart2_hi == this_uart))) { plic_num = MMUART2_PLIC; } else if (((&g_mss_uart3_lo == this_uart)) || ((&g_mss_uart3_hi == this_uart))) { plic_num = MMUART3_PLIC; } else if (((&g_mss_uart4_lo == this_uart)) || ((&g_mss_uart4_hi == this_uart))) { plic_num = MMUART4_PLIC; } else { ASSERT(0); /*Alternative case has been considered*/ } /* Enable UART instance interrupt in PLIC. */ PLIC_EnableIRQ(plic_num); } static void disable_irq ( const mss_uart_instance_t * this_uart ) { PLIC_IRQn_Type plic_num = 0; if (((&g_mss_uart0_lo == this_uart)) || ((&g_mss_uart0_hi == this_uart))) { plic_num = MMUART0_PLIC_77; } else if (((&g_mss_uart1_lo == this_uart)) || ((&g_mss_uart1_hi == this_uart))) { plic_num = MMUART1_PLIC; } else if (((&g_mss_uart2_lo == this_uart)) || ((&g_mss_uart2_hi == this_uart))) { plic_num = MMUART2_PLIC; } else if (((&g_mss_uart3_lo == this_uart)) || ((&g_mss_uart3_hi == this_uart))) { plic_num = MMUART3_PLIC; } else if (((&g_mss_uart4_lo == this_uart)) || ((&g_mss_uart4_hi == this_uart))) { plic_num = MMUART4_PLIC; } else { ASSERT(0); /*Alternative case has been considered*/ } /* Disable UART instance interrupt in PLIC. */ PLIC_DisableIRQ(plic_num); } #ifdef __cplusplus } #endif mss_uart.h000066400000000000000000003761001432224323300374570ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * PolarFire SoC Microprocessor Subsystem MMUART bare metal software driver * public API. * */ /*=========================================================================*//** @mainpage PolarFire SoC MSS UART Bare Metal Driver. ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor subsystem (MSS) includes five multi-mode UART (MMUART) peripherals for serial communication. This driver provides a set of functions for controlling the MSS MMUARTs as part of a bare metal system where no operating system is available. These drivers can be adapted for use as part of an operating system, but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. Note: MSS UART is synonymous with MSS MMUART in this document. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all features of the MSS MMUART peripherals is covered by this driver with the exception of the PolarFire SoC IOMUX configuration. PolarFire SoC allows multiple non-concurrent uses of some external pins through IOMUX configuration. This feature allows optimization of external pin usage by assigning external pins for use by either the microprocessor subsystem or the FPGA fabric. The MSS MMUART serial signals are routed through IOMUXs to the PolarFire SoC device external pins. The MSS MMUART serial signals may also be routed through IOMUXs to the PolarFire SoC FPGA fabric. For more information on IOMUX, refer to the IOMUX section of the PolarFire SoC Microprocessor Subsystem (MSS) User's Guide. The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You must ensure that the MSS MMUART peripherals are enabled and configured in the PolarFire SoC MSS configurator if you wish to use them. For more information on IOMUXs, refer to the IOMUX section of the PolarFire SoC microprocessor Subsystem (MSS) User's Guide. On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple masters and multiple slaves. Five RISC-V CPUs connect to the Master ports M10 to M14 of the AXI switch. By default, all the APB peripherals are accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB bridges (referred as main APB bus). However, to support logical separation in the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to APB bridges (referred as the AMP APB bus). Application must make sure that the desired MMUART instance is appropriately configured on one of the APB bus described above by configuring the PolarFire SoC system registers (SYSREG) as per the application need and that the appropriate data structures are provided to this driver as parameter to the functions provided by this driver. The base address and register addresses are defined in this driver as constants. The interrupt number assignment for the MSS MMUART peripherals are defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole tool chain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS MMUART driver functions are grouped into the following categories: - Initialization and configuration functions - Polled transmit and receive functions - Interrupt driven transmit and receive functions -------------------------------- Initialization and Configuration -------------------------------- The MSS MMUART supports the following four broad modes of operation: - UART or USART mode - LIN mode - IrDA mode - Smartcard or ISO 7816 mode The MSS MMUART driver provides the MSS_UART_init(), MSS_UART_lin_init(), MSS_UART_irda_init() and MSS_UART_smartcard_init() functions to initialize the MSS MMUARTs for operation in one of these modes. One of these initialization functions must be called before any other MSS MMUART driver functions can be called. The MSS MMUART operating modes are mutually exclusive; therefore only one of the initialization functions must be called. The first parameter of the initialization functions is a pointer to one of ten global data structures used to store state information for each MSS MMUART. A pointer to these data structures is also used as the first parameter to many of the driver functions to identify which MSS MMUART will be used by the called function. The names of these data structures are: - g_mss_uart0_lo - g_mss_uart1_lo - g_mss_uart2_lo - g_mss_uart3_lo - g_mss_uart4_lo - g_mss_uart0_hi - g_mss_uart1_hi - g_mss_uart2_hi - g_mss_uart3_hi - g_mss_uart4_hi Therefore, any call to an MSS MMUART function should be of the form MSS_UART_function_name( &g_mss_uart0_lo, ... ) or MSS_UART_function_name( &g_mss_uart1_hi, ... ). UART or USART Mode For the UART or USART modes of operation, the MSS MMUART driver is initialized through a call to the MSS_UART_init() function. This function takes the UART's configuration as its parameters. The MSS_UART_init() function must be called before any other MSS MMUART driver functions can be called. The MSS_UART_init() function configures the baud rate based on the input baud rate parameter and if possible uses a fractional baud rate for greater precision. This function disables the LIN, IrDA and SmartCard modes. LIN mode For the LIN mode of operation, the MSS MMUART driver is initialized through a call to the MSS_UART_lin_init() function. This function takes the LIN node's configuration as its parameters. The MSS_UART_lin_init() function must be called before any other MSS MMUART driver functions can be called. The MSS_UART_lin_init() function configures the baud rate based on the input baud rate parameter and if possible uses a fractional baud rate for greater precision. This function disables the IrDA and SmartCard modes. The driver also provides the following LIN mode configuration functions: - MSS_UART_set_break() - MSS_UART_clear_break() - MSS_UART_set_pidpei_handler() - MSS_UART_set_linbreak_handler() - MSS_UART_set_linsync_handler() Note: These LIN mode configuration functions can only be called after the MSS_UART_lin_init() function is called. IrDA mode For the IrDA mode of operation, the driver is initialized through a call to the MSS_UART_irda_init() function. This function takes the IrDA node's configuration as its parameters. The MSS_UART_irda_init() function must be called before any other MSS MMUART driver functions can be called. The MSS_UART_irda_init() function configures the baud rate based on the input baud rate parameter and if possible uses a fractional baud rate for greater precision. This function disables the LIN and SmartCard modes. Smartcard or ISO 7816 mode For the Smartcard or ISO 7816 mode of operation, the driver is initialized through a call to the MSS_UART_smartcard_init() function. This function takes the smartcard configuration as its parameters. The MSS_UART_smartcard_init() function must be called before any other MSS MMUART driver functions can be called. The MSS_UART_smartcard_init() function configures the baud rate based on the input baud rate parameter and if possible uses a fractional baud rate for greater precision. This function disables the LIN and IrDA modes. The driver also provides the following Smartcard mode configuration functions: - MSS_UART_enable_halfduplex() - MSS_UART_disable_halfduplex() - MSS_UART_set_nack_handler() Note: These Smartcard mode configuration functions can only be called after the MSS_UART_smartcard_init() function is called. Common Configuration Functions The driver also provides the configuration functions that can be used with all MSS MMUART operating modes. These common configuration functions are as follows: - MSS_UART_set_rx_endian() - MSS_UART_set_tx_endian() - MSS_UART_enable_afclear() - MSS_UART_disable_afclear() - MSS_UART_enable_rx_timeout() - MSS_UART_disable_rx_timeout() - MSS_UART_enable_tx_time_guard() - MSS_UART_disable_tx_time_guard() - MSS_UART_set_address() - MSS_UART_set_ready_mode() - MSS_UART_set_usart_mode() - MSS_UART_set_filter_length() - MSS_UART_enable_afm() - MSS_UART_disable_afm() Note: These configuration functions can only be called after one of the MSS_UART_init(), MSS_UART_lin_init(), MSS_UART_irda_init() or MSS_UART_smartcard_init() functions is called. -------------------------------------- Polled Transmit and Receive Operations -------------------------------------- The driver can be used to transmit and receive data once initialized. Data is transmitted using the MSS_UART_polled_tx() function. This function is blocking, meaning that it will only return once the data passed to the function has been sent to the MSS MMUART hardware transmitter. Data received by the MSS MMUART hardware receiver can be read by the MSS_UART_get_rx() function. The MSS_UART_polled_tx_string() function is provided to transmit a NULL ('\0') terminated string in polled mode. This function is blocking, meaning that it will only return once the data passed to the function has been sent to the MSS MMUART hardware transmitter. The MSS_UART_fill_tx_fifo() function fills the MSS MMUART hardware transmit FIFO with data from a buffer passed as a parameter and returns the number of bytes transferred to the FIFO. If the transmit FIFO is not empty when the MSS_UART_fill_tx_fifo() function is called it returns immediately without transferring any data to the FIFO. --------------------------- Interrupt Driven Operations --------------------------- The driver can also transmit or receive data under interrupt control, freeing your application to perform other tasks until an interrupt occurs indicating that the driver's attention is required. Local or PLIC interrupt: PolarFire SoC architecture provides flexibility in terms of how the MMUART interrupt is seen by the PolarFire SoC Core Complex. Each of the 5 MMUART instance interrupt line is connected to the PolarFire SoC Core Complex PLIC. The MMUART0 instance interrupt line is also available as local interrupt on E51 processor. The MMUART1 instance interrupt onwards are available as local interrupt on the U54_1 processor onwards. e.g. MMUART2 interrupt is available as local interrupt on U54_2. Interrupt Handlers The MSS MMUART driver supports all types of interrupt triggered by the MSS MMUART. The driver's internal top level interrupt handler identifies the source of the MSS MMUART interrupt and calls the corresponding lower level handler function that you previously registered with the driver through calls to the MSS_UART_set_rx_handler(), MSS_UART_set_tx_handler(), MSS_UART_set_rxstatus_handler(), and MSS_UART_set_modemstatus_handler() functions. You are responsible for creating these lower level interrupt handlers as part of your application program and registering them with the driver. Note: The PolarFire SoC HAL defines the interrupt handler functions for all 5 MMUART instances(with weak linkage) and assigns them as the interrupt service routines (ISR) for the MSS MMUART interrupt inputs to the PolarFire SoC Core Complex PLIC or the Local interrupts on each of the respective CPUs. The MSS MMUART driver provides the implementation functions all these ISRs from which it calls its own internal top level, interrupt handler function. The MSS_UART_enable_irq() and MSS_UART_disable_irq() functions are used to enable or disable the received line status, received data available/character time-out, transmit holding register empty and modem status interrupts at the MSS MMUART level. The MSS_UART_enable_irq() function also enables the MSS MMUART instance interrupt at the PolarFire SoC Core Complex level. Note that the MSS_UART_enable_irq() and MSS_UART_disable_irq() and all the calls to set the handler functions assume that the MMUART interrupt is connected to the PolarFire SoC Core Complex PLIC. If you want the MMUART interrupt to appear as a local interrupt to the corresponding HART then you must explicitly call the MSS_UART_enable_local_irq() function. This function will disable the PLIC interrupt (if it was previously enable) and enable the local interrupt on the HART on which this function is being executed. Transmitting Data Interrupt-driven transmit is initiated by a call to MSS_UART_irq_tx(), specifying the block of data to transmit. Your application is then free to perform other tasks and inquire later whether transmit has completed by calling the MSS_UART_tx_complete() function. The MSS_UART_irq_tx() function enables the UART's transmit holding register empty (THRE) interrupt and then, when the interrupt goes active, the driver's default THRE interrupt handler transfers the data block to the UART until the entire block is transmitted. Note: You can use the MSS_UART_set_tx_handler() function to assign an alternative handler to the THRE interrupt. In this case, you must not use the MSS_UART_irq_tx() function to initiate the transmit, as this will re-assign the driver's default THRE interrupt handler to the THRE interrupt. Instead, your alternative THRE interrupt handler must include a call to the MSS_UART_fill_tx_fifo() function to transfer the data to the UART. Receiving Data Interrupt-driven receive is performed by first calling MSS_UART_set_rx_handler() to register a receive handler function that will be called by the driver whenever receive data is available. You must provide this receive handler function which must include a call to the MSS_UART_get_rx() function to actually read the received data. ----------- UART Status ----------- The function MSS_UART_get_rx_status() is used to read the receiver error status. This function returns the overrun, parity, framing, break, and FIFO error status of the receiver. The function MSS_UART_get_tx_status() is used to read the transmitter status. This function returns the transmit empty (TEMT) and transmit holding register empty (THRE) status of the transmitter. The function MSS_UART_get_modem_status() is used to read the modem status flags. This function returns the current value of the modem status register. -------- Loopback -------- The MSS_UART_set_loopback() function can be used to locally loopback the Tx and Rx lines of a UART. This is not to be confused with the loopback of UART0 to UART1, which can be achieved through the microprocessor subsystem's system registers. *//*=========================================================================*/ #ifndef __MSS_UART_H_ #define __MSS_UART_H_ 1 #include #include #ifndef SIFIVE_HIFIVE_UNLEASHED #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** Baud rates ========== The following definitions are used to specify standard baud rates as a parameter to the MSS_UART_init() function. | Constant | Description | |----------------------|------------------| | MSS_UART_110_BAUD | 110 baud rate | | MSS_UART_300_BAUD | 300 baud rate | | MSS_UART_600_BAUD | 600 baud rate | | MSS_UART_1200_BAUD | 1200 baud rate | | MSS_UART_2400_BAUD | 2400 baud rate | | MSS_UART_4800_BAUD | 4800 baud rate | | MSS_UART_9600_BAUD | 9600 baud rate | | MSS_UART_19200_BAUD | 19200 baud rate | | MSS_UART_38400_BAUD | 38400 baud rate | | MSS_UART_57600_BAUD | 57600 baud rate | | MSS_UART_115200_BAUD | 115200 baud rate | | MSS_UART_230400_BAUD | 230400 baud rate | | MSS_UART_460800_BAUD | 460800 baud rate | | MSS_UART_921600_BAUD | 921600 baud rate | */ #define MSS_UART_110_BAUD 110U #define MSS_UART_300_BAUD 300U #define MSS_UART_600_BAUD 600U #define MSS_UART_1200_BAUD 1200U #define MSS_UART_2400_BAUD 2400U #define MSS_UART_4800_BAUD 4800U #define MSS_UART_9600_BAUD 9600U #define MSS_UART_19200_BAUD 19200U #define MSS_UART_38400_BAUD 38400U #define MSS_UART_57600_BAUD 57600U #define MSS_UART_115200_BAUD 115200U #define MSS_UART_230400_BAUD 230400U #define MSS_UART_460800_BAUD 460800U #define MSS_UART_921600_BAUD 921600U /***************************************************************************//** Data Bits Length ================ The following defines are used to build the value of the MSS_UART_init() function line_config parameter. | Constant | Description | |----------------------|----------------------------| | MSS_UART_DATA_5_BITS | 5 bits of data transmitted | | MSS_UART_DATA_6_BITS | 6 bits of data transmitted | | MSS_UART_DATA_7_BITS | 7 bits of data transmitted | | MSS_UART_DATA_8_BITS | 8 bits of data transmitted | */ #define MSS_UART_DATA_5_BITS ((uint8_t) 0x00) #define MSS_UART_DATA_6_BITS ((uint8_t) 0x01) #define MSS_UART_DATA_7_BITS ((uint8_t) 0x02) #define MSS_UART_DATA_8_BITS ((uint8_t) 0x03) /***************************************************************************//** Parity ====== The following defines are used to build the value of the MSS_UART_init() function line_config parameter. | Constant | Description | |-------------------------|--------------------------| | MSS_UART_NO_PARITY | No parity | | MSS_UART_ODD_PARITY | Odd Parity | | MSS_UART_EVEN_PARITY | Even parity | | MSS_UART_STICK_PARITY_0 | Stick parity bit to zero | | MSS_UART_STICK_PARITY_1 | Stick parity bit to one | */ #define MSS_UART_NO_PARITY ((uint8_t) 0x00) #define MSS_UART_ODD_PARITY ((uint8_t) 0x08) #define MSS_UART_EVEN_PARITY ((uint8_t) 0x18) #define MSS_UART_STICK_PARITY_0 ((uint8_t) 0x38) #define MSS_UART_STICK_PARITY_1 ((uint8_t) 0x28) /***************************************************************************//** Number of Stop Bits =================== The following defines are used to build the value of the MSS_UART_init() function line_config parameter. | Constant | Description | |---------------------------|--------------------------| | MSS_UART_ONE_STOP_BIT | One stop bit | | MSS_UART_ONEHALF_STOP_BIT | One and a half stop bits | | MSS_UART_TWO_STOP_BITS | Two stop bits | */ #define MSS_UART_ONE_STOP_BIT ((uint8_t) 0x00) #define MSS_UART_ONEHALF_STOP_BIT ((uint8_t) 0x04) #define MSS_UART_TWO_STOP_BITS ((uint8_t) 0x04) /***************************************************************************//** Receiver Error Status ===================== The following defines are used to determine the UART receiver error type. These bit mask constants are used with the return value of the MSS_UART_get_rx_status() function to find out if any errors occurred while receiving data. | Constant | Description | |------------------------|--------------------------------------------| | MSS_UART_NO_ERROR | No error bit mask (0x00) | | MSS_UART_OVERUN_ERROR | Overrun error bit mask (0x02) | | MSS_UART_PARITY_ERROR | Parity error bit mask (0x04) | | MSS_UART_FRAMING_ERROR | Framing error bit mask (0x08) | | MSS_UART_BREAK_ERROR | Break error bit mask (0x10) | | MSS_UART_FIFO_ERROR | FIFO error bit mask (0x80) | | MSS_UART_INVALID_PARAM | Invalid function parameter bit mask (0xFF) | */ #define MSS_UART_INVALID_PARAM ((uint8_t)0xFF) #define MSS_UART_NO_ERROR ((uint8_t)0x00 ) #define MSS_UART_OVERUN_ERROR ((uint8_t)0x02) #define MSS_UART_PARITY_ERROR ((uint8_t)0x04) #define MSS_UART_FRAMING_ERROR ((uint8_t)0x08) #define MSS_UART_BREAK_ERROR ((uint8_t)0x10) #define MSS_UART_FIFO_ERROR ((uint8_t)0x80) /***************************************************************************//** Transmitter Status ================== The following definitions are used to determine the UART transmitter status. These bit mask constants are used with the return value of the MSS_UART_get_tx_status() function to find out the status of the transmitter. | Constant | Description | |------------------|----------------------------------------------------| | MSS_UART_TX_BUSY | Transmitter busy (0x00) | | MSS_UART_THRE | Transmitter holding register empty bit mask (0x20) | | MSS_UART_TEMT | Transmitter empty bit mask (0x40) | */ #define MSS_UART_TX_BUSY ((uint8_t) 0x00) #define MSS_UART_THRE ((uint8_t) 0x20) #define MSS_UART_TEMT ((uint8_t) 0x40) /***************************************************************************//** Modem Status ============ The following defines are used to determine the modem status. These bit mask constants are used with the return value of the MSS_UART_get_modem_status() function to find out the modem status of the UART. | Constant | Description | |---------------|-------------------------------------------------| | MSS_UART_DCTS | Delta clear to send bit mask (0x01) | | MSS_UART_DDSR | Delta data set ready bit mask (0x02) | | MSS_UART_TERI | Trailing edge of ring indicator bit mask (0x04) | | MSS_UART_DDCD | Delta data carrier detect bit mask (0x08) | | MSS_UART_CTS | Clear to send bit mask (0x10) | | MSS_UART_DSR | Data set ready bit mask (0x20) | | MSS_UART_RI | Ring indicator bit mask (0x40) | | MSS_UART_DCD | Data carrier detect bit mask (0x80) | */ #define MSS_UART_DCTS ((uint8_t) 0x01) #define MSS_UART_DDSR ((uint8_t) 0x02) #define MSS_UART_TERI ((uint8_t) 0x04) #define MSS_UART_DDCD ((uint8_t) 0x08) #define MSS_UART_CTS ((uint8_t) 0x10) #define MSS_UART_DSR ((uint8_t) 0x20) #define MSS_UART_RI ((uint8_t) 0x40) #define MSS_UART_DCD ((uint8_t) 0x80) /***************************************************************************//** This typedef specifies the irq_mask parameter for the MSS_UART_enable_irq() and MSS_UART_disable_irq() functions. The driver defines a set of bit masks that are used to build the value of the irq_mask parameter. A bitwise OR of these bit masks is used to enable or disable multiple MSS MMUART interrupts. */ typedef uint16_t mss_uart_irq_t; /***************************************************************************//** MSS MMUART Interrupts ===================== The following defines specify the interrupt masks to enable and disable MSS MMUART interrupts. They are used to build the value of the irq_mask parameter for the MSS_UART_enable_irq() and MSS_UART_disable_irq() functions. A bitwise OR of these constants is used to enable or disable multiple interrupts. | Constant | Description | |--------------------|---------------------------------------------------------------| | MSS_UART_RBF_IRQ | Receive Data Available Interrupt bit mask (0x001) | | MSS_UART_TBE_IRQ | Transmitter Holding Register Empty interrupt bit mask (0x002) | | MSS_UART_LS_IRQ | Receiver Line Status interrupt bit mask (0x004) | | MSS_UART_MS_IRQ | Modem Status interrupt bit mask (0x008) | | MSS_UART_RTO_IRQ | Receiver time-out interrupt bit mask (0x010) | | MSS_UART_NACK_IRQ | NACK / ERR signal interrupt bit mask (0x020) | | MSS_UART_PIDPE_IRQ | PID parity error interrupt bit mask (0x040) | | MSS_UART_LINB_IRQ | LIN break detection interrupt bit mask (0x080) | | MSS_UART_LINS_IRQ | LIN Sync detection interrupt bit mask (0x100) | */ #define MSS_UART_RBF_IRQ 0x001 #define MSS_UART_TBE_IRQ 0x002 #define MSS_UART_LS_IRQ 0x004 #define MSS_UART_MS_IRQ 0x008 #define MSS_UART_RTO_IRQ 0x010 #define MSS_UART_NACK_IRQ 0x020 #define MSS_UART_PIDPE_IRQ 0x040 #define MSS_UART_LINB_IRQ 0x080 #define MSS_UART_LINS_IRQ 0x100 #define MSS_UART_INVALID_IRQ UINT16_MAX /***************************************************************************//** This enumeration specifies the receiver FIFO trigger level. This is the number of bytes that must be received before the UART generates a receive data available interrupt. It provides the allowed values for the MSS_UART_set_rx_handler() function trigger_level parameter. */ typedef enum { MSS_UART_FIFO_SINGLE_BYTE = 0x00, MSS_UART_FIFO_FOUR_BYTES = 0x40, MSS_UART_FIFO_EIGHT_BYTES = 0x80, MSS_UART_FIFO_FOURTEEN_BYTES = 0xC0, MSS_UART_FIFO_INVALID_TRIG_LEVEL } mss_uart_rx_trig_level_t; /***************************************************************************//** This enumeration specifies the loopback configuration of the UART. It provides the allowed values for the MSS_UART_set_loopback() function's loopback parameter. Use MSS_UART_LOCAL_LOOPBACK_ON to set up the UART to locally loopback its Tx and Rx lines. Use MSS_UART_REMOTE_LOOPBACK_ON to set up the UART in remote loopback mode. */ typedef enum { MSS_UART_LOCAL_LOOPBACK_OFF, MSS_UART_LOCAL_LOOPBACK_ON, MSS_UART_REMOTE_LOOPBACK_OFF, MSS_UART_REMOTE_LOOPBACK_ON, MSS_UART_AUTO_ECHO_OFF, MSS_UART_AUTO_ECHO_ON, MSS_UART_INVALID_LOOPBACK } mss_uart_loopback_t; /***************************************************************************//** IrDA input / output polarity. This enumeration specifies the RZI modem polarity for input and output signals. This is passed as parameters in MSS_UART_irda_init() function. */ typedef enum { MSS_UART_ACTIVE_LOW = 0u, MSS_UART_ACTIVE_HIGH = 1u, MSS_UART_INVALID_POLARITY } mss_uart_rzi_polarity_t; /***************************************************************************//** IrDA input / output pulse width. This enumeration specifies the RZI modem pulse width for input and output signals. This is passed as parameters in MSS_UART_irda_init() function. */ typedef enum { MSS_UART_3_BY_16 = 0u, MSS_UART_1_BY_4 = 1u, MSS_UART_INVALID_PW } mss_uart_rzi_pulsewidth_t; /***************************************************************************//** Tx / Rx endianess. This enumeration specifies the MSB first or LSB first for MSS UART transmitter and receiver. The parameter of this type shall be passed in MSS_UART_set_rx_endian()and MSS_UART_set_tx_endian() functions. */ typedef enum { MSS_UART_LITTLEEND, MSS_UART_BIGEND, MSS_UART_INVALID_ENDIAN } mss_uart_endian_t; /***************************************************************************//** Glitch filter length. This enumeration specifies the glitch filter length. The function MSS_UART_set_filter_length() accepts the parameter of this type. */ typedef enum { MSS_UART_LEN0 = 0, MSS_UART_LEN1 = 1, MSS_UART_LEN2 = 2, MSS_UART_LEN3 = 3, MSS_UART_LEN4 = 4, MSS_UART_LEN5 = 5, MSS_UART_LEN6 = 6, MSS_UART_LEN7 = 7, MSS_UART_INVALID_FILTER_LENGTH = 8 } mss_uart_filter_length_t; /***************************************************************************//** TXRDY and RXRDY mode. This enumeration specifies the TXRDY and RXRDY signal modes. The function MSS_UART_set_ready_mode() accepts the parameter of this type. */ typedef enum { MSS_UART_READY_MODE0, MSS_UART_READY_MODE1, MSS_UART_INVALID_READY_MODE } mss_uart_ready_mode_t; /***************************************************************************//** USART mode of operation. This enumeration specifies the mode of operation of MSS UART when operating as USART. The function MSS_UART_set_usart_mode() accepts the parameter of this type. */ typedef enum { MSS_UART_ASYNC_MODE = 0, MSS_UART_SYNC_SLAVE_POS_EDGE_CLK = 1, MSS_UART_SYNC_SLAVE_NEG_EDGE_CLK = 2, MSS_UART_SYNC_MASTER_POS_EDGE_CLK = 3, MSS_UART_SYNC_MASTER_NEG_EDGE_CLK = 4, MSS_UART_INVALID_SYNC_MODE = 5 } mss_uart_usart_mode_t; typedef enum { MSS_UART0_LO = 0, MSS_UART1_LO = 1, MSS_UART2_LO = 2, MSS_UART3_LO = 3, MSS_UART4_LO = 4, MSS_UART0_HI = 5, MSS_UART1_HI = 6, MSS_UART2_HI = 7, MSS_UART3_HI = 8, MSS_UAR4_HI = 9, } mss_uart_num_t; /***************************************************************************//** MSS UART instance type. This is type definition for MSS UART instance. You need to create and maintain a record of this type. This holds all data regarding the MSS UART instance */ typedef struct mss_uart_instance mss_uart_instance_t; /***************************************************************************//** Interrupt handler prototype. This typedef specifies the function prototype for MSS UART interrupt handlers. All interrupt handlers registered with the MSS UART driver must be of this type. The interrupt handlers are registered with the driver through the MSS_UART_set_rx_handler(), MSS_UART_set_tx_handler(), MSS_UART_set_rxstatus_handler(), and MSS_UART_set_modemstatus_handler() functions. The this_uart parameter is a pointer to either g_mss_uart0 or g_mss_uart1 to identify the MSS UART to associate with the handler function. */ typedef void (*mss_uart_irq_handler_t)( mss_uart_instance_t * this_uart ); /*----------------------------------------------------------------------------*/ /*----------------------------------- UART -----------------------------------*/ /*----------------------------------------------------------------------------*/ typedef struct { union { volatile const uint8_t RBR; volatile uint8_t THR; volatile uint8_t DLR; uint32_t RESERVED0; }; union { volatile uint8_t DMR; volatile uint8_t IER; uint32_t RESERVED1; }; union { volatile uint8_t IIR; volatile uint8_t FCR; uint32_t RESERVED2; }; volatile uint8_t LCR; uint8_t RESERVED3[3]; volatile uint8_t MCR; uint8_t RESERVED4[3]; volatile const uint8_t LSR; uint8_t RESERVED5[3]; volatile const uint8_t MSR; uint8_t RESERVED6[3]; volatile uint8_t SR; uint8_t RESERVED7[7]; volatile uint8_t IEM; uint8_t RESERVED8[3]; volatile uint8_t IIM; uint8_t RESERVED9[7]; volatile uint8_t MM0; uint8_t RESERVED10[3]; volatile uint8_t MM1; uint8_t RESERVED11[3]; volatile uint8_t MM2; uint8_t RESERVED12[3]; volatile uint8_t DFR; uint8_t RESERVED13[7]; volatile uint8_t GFR; uint8_t RESERVED14[3]; volatile uint8_t TTG; uint8_t RESERVED15[3]; volatile uint8_t RTO; uint8_t RESERVED16[3]; volatile uint8_t ADR; uint8_t RESERVED17[3]; } MSS_UART_TypeDef; /***************************************************************************//** mss_uart_instance. There is one instance of this structure for each instance of the microprocessor subsystem's UARTs. Instances of this structure are used to identify a specific UART. A pointer to an initialized instance of the mss_uart_instance_t structure is passed as the first parameter to MSS UART driver functions to identify which UART should perform the requested operation. */ struct mss_uart_instance{ /* CMSIS related defines identifying the UART hardware. */ MSS_UART_TypeDef * hw_reg; /*!< Pointer to UART registers. */ uint32_t baudrate; /*!< Operating baud rate. */ uint8_t lineconfig; /*!< Line configuration parameters. */ uint8_t status; /*!< Sticky line status. */ /* transmit related info (used with interrupt driven transmit): */ const uint8_t * tx_buffer; /*!< Pointer to transmit buffer. */ uint32_t tx_buff_size; /*!< Transmit buffer size. */ uint32_t tx_idx; /*!< Index within transmit buffer of next byte to transmit.*/ /* line status interrupt handler:*/ mss_uart_irq_handler_t linests_handler; /*!< Pointer to user registered line status handler. */ /* receive interrupt handler:*/ mss_uart_irq_handler_t rx_handler; /*!< Pointer to user registered receiver handler. */ /* transmit interrupt handler:*/ mss_uart_irq_handler_t tx_handler; /*!< Pointer to user registered transmit handler. */ /* modem status interrupt handler:*/ mss_uart_irq_handler_t modemsts_handler; /*!< Pointer to user registered modem status handler. */ /* receiver timeout interrupt handler */ mss_uart_irq_handler_t rto_handler; /*!< Pointer to user registered receiver timeout handler. */ /* NACK interrupt handler */ mss_uart_irq_handler_t nack_handler; /*!< Pointer to user registered NACK handler. */ /* PID parity perror interrupt handler */ mss_uart_irq_handler_t pid_pei_handler; /*!< Pointer to user registered PID parity error handler. */ /* LIN break interrupt handler */ mss_uart_irq_handler_t break_handler; /*!< Pointer to user registered LIN break handler. */ /* LIN sync detection interrupt handler */ mss_uart_irq_handler_t sync_handler; /*!< Pointer to user registered LIN sync detection handler. */ void* user_data; /*!< Pointer to user provided pointer for user specific use. */ }; /***************************************************************************//** This instance of mss_uart_instance_t holds all data related to the operations performed by the MMUART. The function MSS_UART_init() initializes this structure. A pointer to g_mss_uart0_lo is passed as the first parameter to MSS UART driver functions to indicate that MMUART0 should perform the requested operation. */ extern mss_uart_instance_t g_mss_uart0_lo; extern mss_uart_instance_t g_mss_uart1_lo; extern mss_uart_instance_t g_mss_uart2_lo; extern mss_uart_instance_t g_mss_uart3_lo; extern mss_uart_instance_t g_mss_uart4_lo; extern mss_uart_instance_t g_mss_uart0_hi; extern mss_uart_instance_t g_mss_uart1_hi; extern mss_uart_instance_t g_mss_uart2_hi; extern mss_uart_instance_t g_mss_uart3_hi; extern mss_uart_instance_t g_mss_uart4_hi; /***************************************************************************//** The MSS_UART_init() function initializes and configures one of the PolarFire SoC MSS UARTs with the configuration passed as a parameter. The configuration parameters are the baud_rate which is used to generate the baud value and the line_config which is used to specify the line configuration (bit length, stop bits and parity). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @param baud_rate The baud_rate parameter specifies the baud rate. It can be specified for common baud rates using the following defines: - MSS_UART_110_BAUD - MSS_UART_300_BAUD - MSS_UART_600_BAUD - MSS_UART_1200_BAUD - MSS_UART_2400_BAUD - MSS_UART_4800_BAUD - MSS_UART_9600_BAUD - MSS_UART_19200_BAUD - MSS_UART_38400_BAUD - MSS_UART_57600_BAUD - MSS_UART_115200_BAUD - MSS_UART_230400_BAUD - MSS_UART_460800_BAUD - MSS_UART_921600_BAUD Alternatively, any nonstandard baud rate can be specified by simply passing the actual required baud rate as the value for this parameter. @param line_config The line_config parameter is the line configuration specifying the bit length, number of stop bits and parity settings. This is a bitwise OR of one value from each of the following groups of allowed values: One of the following to specify the transmit/receive data bit length: - MSS_UART_DATA_5_BITS - MSS_UART_DATA_6_BITS, - MSS_UART_DATA_7_BITS - MSS_UART_DATA_8_BITS One of the following to specify the parity setting: - MSS_UART_NO_PARITY - MSS_UART_EVEN_PARITY - MSS_UART_ODD_PARITY - MSS_UART_STICK_PARITY_0 - MSS_UART_STICK_PARITY_1 One of the following to specify the number of stop bits: - MSS_UART_ONE_STOP_BIT - MSS_UART_ONEHALF_STOP_BIT - MSS_UART_TWO_STOP_BITS @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); return(0); } @endcode */ void MSS_UART_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config ); /***************************************************************************//** The MSS_UART_lin_init() function is used to initialize the MSS UART for LIN mode of operation. The configuration parameters are the baud_rate which is used to generate the baud value and the line_config which is used to specify the line configuration (bit length, stop bits and parity). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @param baud_rate The baud_rate parameter specifies the baud rate. It can be specified for common baud rates using the following defines: - MSS_UART_110_BAUD - MSS_UART_300_BAUD - MSS_UART_600_BAUD - MSS_UART_1200_BAUD - MSS_UART_2400_BAUD - MSS_UART_4800_BAUD - MSS_UART_9600_BAUD - MSS_UART_19200_BAUD - MSS_UART_38400_BAUD - MSS_UART_57600_BAUD - MSS_UART_115200_BAUD - MSS_UART_230400_BAUD - MSS_UART_460800_BAUD - MSS_UART_921600_BAUD Alternatively, any nonstandard baud rate can be specified by simply passing the actual required baud rate as the value for this parameter. @param line_config The line_config parameter is the line configuration specifying the bit length, number of stop bits and parity settings. This is a bitwise OR of one value from each of the following groups of allowed values: One of the following to specify the transmit/receive data bit length: - MSS_UART_DATA_5_BITS - MSS_UART_DATA_6_BITS, - MSS_UART_DATA_7_BITS - MSS_UART_DATA_8_BITS One of the following to specify the parity setting: - MSS_UART_NO_PARITY - MSS_UART_EVEN_PARITY - MSS_UART_ODD_PARITY - MSS_UART_STICK_PARITY_0 - MSS_UART_STICK_PARITY_1 One of the following to specify the number of stop bits: - MSS_UART_ONE_STOP_BIT - MSS_UART_ONEHALF_STOP_BIT - MSS_UART_TWO_STOP_BITS @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { MSS_UART_lin_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); return(0); } @endcode */ void MSS_UART_lin_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config ); /***************************************************************************//** The MSS_UART_irda_init() function is used to initialize the MSS UART instance referenced by the parameter this_uart for IrDA mode of operation. This function must be called before calling any other IrDA functionality specific functions. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @param baud_rate The baud_rate parameter specifies the baud rate. It can be specified for common baud rates using the following defines: - MSS_UART_110_BAUD - MSS_UART_300_BAUD - MSS_UART_600_BAUD - MSS_UART_1200_BAUD - MSS_UART_2400_BAUD - MSS_UART_4800_BAUD - MSS_UART_9600_BAUD - MSS_UART_19200_BAUD - MSS_UART_38400_BAUD - MSS_UART_57600_BAUD - MSS_UART_115200_BAUD - MSS_UART_230400_BAUD - MSS_UART_460800_BAUD - MSS_UART_921600_BAUD Alternatively, any nonstandard baud rate can be specified by simply passing the actual required baud rate as the value for this parameter. @param line_config The line_config parameter is the line configuration specifying the bit length, number of stop bits and parity settings. This is a bitwise OR of one value from each of the following groups of allowed values: One of the following to specify the transmit/receive data bit length: - MSS_UART_DATA_5_BITS - MSS_UART_DATA_6_BITS, - MSS_UART_DATA_7_BITS - MSS_UART_DATA_8_BITS One of the following to specify the parity setting: - MSS_UART_NO_PARITY - MSS_UART_EVEN_PARITY - MSS_UART_ODD_PARITY - MSS_UART_STICK_PARITY_0 - MSS_UART_STICK_PARITY_1 One of the following to specify the number of stop bits: - MSS_UART_ONE_STOP_BIT - MSS_UART_ONEHALF_STOP_BIT - MSS_UART_TWO_STOP_BITS @return This function does not return a value. Example: @code MSS_UART_irda_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT, MSS_UART_ACTIVE_LOW, MSS_UART_ACTIVE_LOW, MSS_UART_3_BY_16); @endcode */ void MSS_UART_irda_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config, mss_uart_rzi_polarity_t rxpol, mss_uart_rzi_polarity_t txpol, mss_uart_rzi_pulsewidth_t pw ); /***************************************************************************//** The MSS_UART_smartcard_init() function is used to initialize the MSS UART for ISO 7816 (smartcard) mode of operation. The configuration parameters are the baud_rate which is used to generate the baud value and the line_config which is used to specify the line configuration (bit length, stop bits and parity). This function disables all other modes of the MSS UART instance pointed by the parameter this_uart. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @param baud_rate The baud_rate parameter specifies the baud rate. It can be specified for common baud rates using the following defines: - MSS_UART_110_BAUD - MSS_UART_300_BAUD - MSS_UART_600_BAUD - MSS_UART_1200_BAUD - MSS_UART_2400_BAUD - MSS_UART_4800_BAUD - MSS_UART_9600_BAUD - MSS_UART_19200_BAUD - MSS_UART_38400_BAUD - MSS_UART_57600_BAUD - MSS_UART_115200_BAUD - MSS_UART_230400_BAUD - MSS_UART_460800_BAUD - MSS_UART_921600_BAUD Alternatively, any nonstandard baud rate can be specified by simply passing the actual required baud rate as the value for this parameter. @param line_config The line_config parameter is the line configuration specifying the bit length, number of stop bits and parity settings. This is a bitwise OR of one value from each of the following groups of allowed values: One of the following to specify the transmit/receive data bit length: - MSS_UART_DATA_5_BITS - MSS_UART_DATA_6_BITS, - MSS_UART_DATA_7_BITS - MSS_UART_DATA_8_BITS One of the following to specify the parity setting: - MSS_UART_NO_PARITY - MSS_UART_EVEN_PARITY - MSS_UART_ODD_PARITY - MSS_UART_STICK_PARITY_0 - MSS_UART_STICK_PARITY_1 One of the following to specify the number of stop bits: - MSS_UART_ONE_STOP_BIT - MSS_UART_ONEHALF_STOP_BIT - MSS_UART_TWO_STOP_BITS @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { MSS_UART_smartcard_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); return(0); } @endcode */ void MSS_UART_smartcard_init ( mss_uart_instance_t* this_uart, uint32_t baud_rate, uint8_t line_config ); /***************************************************************************//** The function MSS_UART_polled_tx() is used to transmit data. It transfers the contents of the transmitter data buffer, passed as a function parameter, into the UART's hardware transmitter FIFO. It returns when the full content of the transmit data buffer has been transferred to the UART's transmit FIFO. It is safe to release or reuse the memory used as the transmitter data buffer once this function returns. Note: This function reads the UART's line status register (LSR) to poll for the active state of the transmitter holding register empty (THRE) bit before transferring data from the data buffer to the transmitter FIFO. It transfers data to the transmitter FIFO in blocks of 16 bytes or less and allows the FIFO to empty before transferring the next block of data. Note: The actual transmission over the serial connection will still be in progress when this function returns. Use the MSS_UART_get_tx_status() function if you need to know when the transmitter is empty. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param pbuff The pbuff parameter is a pointer to a buffer containing the data to be transmitted. @param tx_size The tx_size parameter specifies the size, in bytes, of the data to be transmitted. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t message[12] = "Hello World"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, SS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_polled_tx(&g_mss_uart0_lo, message, sizeof(message)); return(0); } @endcode */ void MSS_UART_polled_tx ( mss_uart_instance_t * this_uart, const uint8_t * pbuff, uint32_t tx_size ); /***************************************************************************//** The function MSS_UART_polled_tx_string() is used to transmit a NULL ('\0') terminated string. It transfers the text string, from the buffer starting at the address pointed to by p_sz_string into the UART's hardware transmitter FIFO. It returns when the complete string has been transferred to the UART's transmit FIFO. It is safe to release or reuse the memory used as the string buffer once this function returns. Note: This function reads the UART's line status register (LSR) to poll for the active state of the transmitter holding register empty (THRE) bit before transferring data from the data buffer to the transmitter FIFO. It transfers data to the transmitter FIFO in blocks of 16 bytes or less and allows the FIFO to empty before transferring the next block of data. Note: The actual transmission over the serial connection will still be in progress when this function returns. Use the MSS_UART_get_tx_status() function if you need to know when the transmitter is empty. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param p_sz_string The p_sz_string parameter is a pointer to a buffer containing the NULL ('\0') terminated string to be transmitted. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t message[12] = "Hello World"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_polled_tx_string(&g_mss_uart0_lo, message); return(0); } @endcode */ void MSS_UART_polled_tx_string ( mss_uart_instance_t * this_uart, const uint8_t * p_sz_string ); /***************************************************************************//** The function MSS_UART_irq_tx() is used to initiate an interrupt-driven transmit. It returns immediately after making a note of the transmit buffer location and enabling transmit interrupts both at the UART and the PolarFire SoC Core Complex PLIC level. This function takes a pointer via the pbuff parameter to a memory buffer containing the data to transmit. The memory buffer specified through this pointer must remain allocated and contain the data to transmit until the transmit completion has been detected through calls to function MSS_UART_tx_complete(). The actual transmission over the serial connection is still in progress until calls to the MSS_UART_tx_complete() function indicate transmit completion. Note: The MSS_UART_irq_tx() function enables both the transmit holding register empty (THRE) interrupt in the UART and the MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: The MSS_UART_irq_tx() function assigns an internal default transmit interrupt handler function to the UART's THRE interrupt. This interrupt handler overrides any custom interrupt handler that you may have previously registered using the MSS_UART_set_tx_handler() function. Note: The MSS_UART_irq_tx() function's default transmit interrupt handler disables the UART's THRE interrupt when all of the data has been transferred to the UART's transmit FIFO. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param pbuff The pbuff parameter is a pointer to a buffer containing the data to be transmitted. @param tx_size The tx_size parameter specifies the size, in bytes, of the data to be transmitted. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_irq_tx(&g_mss_uart0_lo, tx_buff, sizeof(tx_buff)); while(0 == MSS_UART_tx_complete(&g_mss_uart0_lo)) { ; } return(0); } @endcode */ void MSS_UART_irq_tx ( mss_uart_instance_t * this_uart, const uint8_t * pbuff, uint32_t tx_size ); /***************************************************************************//** The MSS_UART_tx_complete() function is used to find out if the interrupt-driven transmit previously initiated through a call to MSS_UART_irq_tx() is complete. This is typically used to find out when it is safe to reuse or release the memory buffer holding transmit data. Note: The transfer of all of the data from the memory buffer to the UART's transmit FIFO and the actual transmission over the serial connection are both complete when a call to the MSS_UART_tx_complete() function indicates transmit completion. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function return a non-zero value if transmit has completed, otherwise it returns zero. Example: See the MSS_UART_irq_tx() function for an example that uses the MSS_UART_tx_complete() function. */ int8_t MSS_UART_tx_complete ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_get_rx() function reads the content of the UART receiver's FIFO and stores it in the receive buffer that is passed via the rx_buff function parameter. It copies either the full contents of the FIFO into the receive buffer, or just enough data from the FIFO to fill the receive buffer, dependent upon the size of the receive buffer passed by the buff_size parameter. The MSS_UART_get_rx() function returns the number of bytes copied into the receive buffer .This function is non-blocking and will return 0 immediately if no data has been received. Note: The MSS_UART_get_rx() function reads and accumulates the receiver status of the MSS UART instance before reading each byte from the receiver's data register/FIFO. This allows the driver to maintain a sticky record of any receiver errors that occur as the UART receives each data byte; receiver errors would otherwise be lost after each read from the receiver's data register. A call to the MSS_UART_get_rx_status() function returns any receiver errors accumulated during the execution of the MSS_UART_get_rx() function. Note: If you need to read the error status for each byte received, set the buff_size to 1 and read the receive line error status for each byte using the MSS_UART_get_rx_status() function. The MSS_UART_get_rx() function can be used in polled mode, where it is called at regular intervals to find out if any data has been received, or in interrupt driven-mode, where it is called as part of a receive handler that is called by the driver as a result of data being received. Note: In interrupt driven mode you should call the MSS_UART_get_rx() function as part of the receive handler function that you register with the MSS UART driver through a call to MSS_UART_set_rx_handler(). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param rx_buff The rx_buff parameter is a pointer to a buffer where the received data is copied. @param buff_size The buff_size parameter specifies the size of the receive buffer in bytes. @return This function returns the number of bytes that were copied into the rx_buff buffer. It returns 0 if no data has been received. Polled mode example: @code int main( void ) { uint8_t rx_buff[RX_BUFF_SIZE]; uint32_t rx_idx = 0; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); while(1) { rx_size = MSS_UART_get_rx(&g_mss_uart0_lo, rx_buff, sizeof(rx_buff)); if(rx_size > 0) { process_rx_data(rx_buff, rx_size); } task_a(); task_b(); } return 0; } @endcode Interrupt driven example: @code int main( void ) { MSS_UART_init(&g_mss_uart1, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_rx_handler(&g_mss_uart1, uart1_rx_handler, MSS_UART_FIFO_SINGLE_BYTE); while(1) { task_a(); task_b(); } return 0; } void uart1_rx_handler(mss_uart_instance_t * this_uart) { uint8_t rx_buff[RX_BUFF_SIZE]; uint32_t rx_idx = 0; rx_size = MSS_UART_get_rx(this_uart, rx_buff, sizeof(rx_buff)); process_rx_data(rx_buff, rx_size); } @endcode */ size_t MSS_UART_get_rx ( mss_uart_instance_t * this_uart, uint8_t * rx_buff, size_t buff_size ); /***************************************************************************//** The MSS_UART_set_rx_handler() function is used to register a receive handler function that is called by the driver when a UART receive data available (RDA) interrupt occurs. You must create and register the receive handler function to suit your application and it must include a call to the MSS_UART_get_rx() function to actually read the received data. Note: The MSS_UART_set_rx_handler() function enables both the RDA interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the RDA interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is a pointer to a receive interrupt handler function provided by your application that will be called as a result of a UART RDA interrupt. This handler function must be of type mss_uart_irq_handler_t. @param trigger_level The trigger_level parameter is the receive FIFO trigger level. This specifies the number of bytes that must be received before the UART triggers an RDA interrupt. @return This function does not return a value. Example: @code #include "mss_uart.h" #define RX_BUFF_SIZE 64 uint8_t g_rx_buff[RX_BUFF_SIZE]; void uart0_rx_handler(mss_uart_instance_t * this_uart) { MSS_UART_get_rx(this_uart, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff)); } int main(void) { MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_rx_handler(&g_mss_uart0_lo, uart0_rx_handler, MSS_UART_FIFO_SINGLE_BYTE); while(1) { ; } return(0); } @endcode */ void MSS_UART_set_rx_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler, mss_uart_rx_trig_level_t trigger_level ); /***************************************************************************//** The MSS_UART_set_loopback() function is used to locally loop-back the Tx and Rx lines of a UART. This is not to be confused with the loop-back of UART0 to UART1, which can be achieved through the microprocessor subsystem's system registers. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param loopback The loopback parameter indicates whether or not the UART's transmit and receive lines should be looped back. Allowed values are as follows: - MSS_UART_LOCAL_LOOPBACK_ON - MSS_UART_LOCAL_LOOPBACK_OFF - MSS_UART_REMOTE_LOOPBACK_ON - MSS_UART_REMOTE_LOOPBACK_OFF - MSS_UART_AUTO_ECHO_ON - MSS_UART_AUTO_ECHO_OFF @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_loopback(&g_mss_uart0_lo, MSS_UART_LOCAL_LOOPBACK_OFF); @endcode */ void MSS_UART_set_loopback ( mss_uart_instance_t * this_uart, mss_uart_loopback_t loopback ); /***************************************************************************//** The MSS_UART_enable_irq() function enables the MSS UART interrupts specified by the irq_mask parameter. The irq_mask parameter identifies the MSS UART interrupts by bit position, as defined in the interrupt enable register (IER) of MSS UART. The MSS UART interrupts and their identifying irq_mask bit positions are as follows: When an irq_mask bit position is set to 1, this function enables the corresponding MSS UART interrupt in the IER register. When an irq_mask bit position is set to 0, the state of the corresponding interrupt remains unchanged in the IER register. Note: The MSS_UART_enable_irq() function also enables the MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param irq_mask The irq_mask parameter is used to select which of the MSS UART's interrupts you want to enable. The allowed value for the irq_mask parameter is one of the following constants or a bitwise OR of more than one: - MSS_UART_RBF_IRQ (bit mask = 0x001) - MSS_UART_TBE_IRQ (bit mask = 0x002) - MSS_UART_LS_IRQ (bit mask = 0x004) - MSS_UART_MS_IRQ (bit mask = 0x008) - MSS_UART_RTO_IRQ (bit mask = 0x010) - MSS_UART_NACK_IRQ (bit mask = 0x020) - MSS_UART_PIDPE_IRQ (bit mask = 0x040) - MSS_UART_LINB_IRQ (bit mask = 0x080) - MSS_UART_LINS_IRQ (bit mask = 0x100) @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_enable_irq(&g_mss_uart0_lo,(MSS_UART_RBF_IRQ | MSS_UART_TBE_IRQ)); return(0); } @endcode */ void MSS_UART_enable_irq ( mss_uart_instance_t * this_uart, mss_uart_irq_t irq_mask ); /***************************************************************************//** The MSS_UART_disable_irq() function disables the MSS UART interrupts specified by the irq_mask parameter. The irq_mask parameter identifies the MSS UART interrupts by bit position, as defined in the interrupt enable register (IER) of MSS UART. The MSS UART interrupts and their identifying bit positions are as follows: When an irq_mask bit position is set to 1, this function disables the corresponding MSS UART interrupt in the IER register. When an irq_mask bit position is set to 0, the state of the corresponding interrupt remains unchanged in the IER register. Note: If you disable all four of the UART's interrupts, the MSS_UART_disable_irq() function also disables the MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param irq_mask The irq_mask parameter is used to select which of the MSS UART's interrupts you want to disable. The allowed value for the irq_mask parameter is one of the following constants or a bitwise OR of more than one: - MSS_UART_RBF_IRQ (bit mask = 0x001) - MSS_UART_TBE_IRQ (bit mask = 0x002) - MSS_UART_LS_IRQ (bit mask = 0x004) - MSS_UART_MS_IRQ (bit mask = 0x008) - MSS_UART_RTO_IRQ (bit mask = 0x010) - MSS_UART_NACK_IRQ (bit mask = 0x020) - MSS_UART_PIDPE_IRQ (bit mask = 0x040) - MSS_UART_LINB_IRQ (bit mask = 0x080) - MSS_UART_LINS_IRQ (bit mask = 0x100) @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_disable_irq(&g_mss_uart0_lo,(MSS_UART_RBF_IRQ | MSS_UART_TBE_IRQ)); return(0); } @endcode */ void MSS_UART_disable_irq ( mss_uart_instance_t * this_uart, mss_uart_irq_t irq_mask ); /***************************************************************************//** The MSS_UART_set_pidpei_handler() function is used assign a custom interrupt handler for the PIDPEI (PID parity error interrupt) when the MSS UART is operating in LIN mode. Note: The MSS_UART_set_pidpei_handler() function enables both the PIDPEI interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the PIDPEI interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is the pointer to the custom handler function. This parameter is of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_pidpei_handler(&g_mss_uart0_lo, my_pidpei_handler); return(0); } @endcode */ void MSS_UART_set_pidpei_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_linbreak_handler () function is used assign a custom interrupt handler for the LIN Break detection interrupt when the MSS UART is operating in LIN mode. Note: The MSS_UART_set_linbreak_handler() function enables both the LIN BREAK interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the LIN BREAK interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is the pointer to the custom handler function. This parameter is of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_linbreak_handler(&g_mss_uart0_lo, my_break_handler); return(0); } @endcode */ void MSS_UART_set_linbreak_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_linsync_handler() function is used assign a custom interrupt handler for the LIN Sync character detection interrupt when the MSS UART is operating in LIN mode. Note: The MSS_UART_set_linsync_handler() function enables both the LIN SYNC interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the LIN SYNC interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is the pointer to the custom handler function. This parameter is of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_linsync_handler(&g_mss_uart0_lo, my_linsync_handler); return(0); } @endcode */ void MSS_UART_set_linsync_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_nack_handler() function is used assign a custom interrupt handler for the NACK character detection interrupt when the MSS UART is operating in Smartcard mode. Note: The MSS_UART_set_nack_handler() function enables both the NAK interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the NAK interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is the pointer to the custom handler function. This parameter is of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_nack_handler(&g_mss_uart0_lo, my_nack_handler); return(0); } @endcode */ void MSS_UART_set_nack_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_rx_timeout_handler() function is used assign a custom interrupt handler for the receiver timeout interrupt when the MSS UART is operating in mode. It finds application in IrDA mode of operation. Note: The MSS_UART_set_rx_timeout_handler() function enables both the time-out interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the RX time-out interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is the pointer to the custom handler function. This parameter is of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" int main(void) { uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_rx_timeout_handler(&g_mss_uart0_lo, my_rxtimeout_handler); return(0); } @endcode */ void MSS_UART_set_rx_timeout_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_rxstatus_handler() function is used to register a receiver status handler function that is called by the driver when a UART receiver line status (RLS) interrupt occurs. You must create and register the handler function to suit your application. Note: The MSS_UART_set_rxstatus_handler() function enables both the RLS interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the RLS interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is a pointer to a receiver line status interrupt handler function provided by your application that will be called as a result of a UART RLS interrupt. This handler function must be of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" void uart_rxsts_handler(mss_uart_instance_t * this_uart) { uint8_t status; status = MSS_UART_get_rx_status(this_uart); if(status & MSS_UART_OVERUN_ERROR) { discard_rx_data(); } } int main(void) { MSS_UART_init( &g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_rxstatus_handler(&g_mss_uart0_lo, uart_rxsts_handler); while(1) { ; } return(0); } @endcode */ void MSS_UART_set_rxstatus_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_tx_handler() function is used to register a transmit handler function that is called by the driver when a UART transmit holding register empty (THRE) interrupt occurs. You must create and register the transmit handler function to suit your application. You can use the MSS_UART_fill_tx_fifo() function in your transmit handler function to write data to the transmitter. Note: The MSS_UART_set_tx_handler() function enables both the THRE interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the THRE interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. Note: The MSS_UART_irq_tx() function does not use the transmit handler function that you register with the MSS_UART_set_tx_handler() function. It uses its own internal THRE interrupt handler function that overrides any custom interrupt handler that you register using the MSS_UART_set_tx_handler() function. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is a pointer to a transmit interrupt handler function provided by your application that will be called as a result of a UART THRE interrupt. This handler function must be of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" uint8_t * g_tx_buffer; size_t g_tx_size = 0; void uart_tx_handler(mss_uart_instance_t * this_uart) { size_t size_in_fifo; size_in_fifo = MSS_UART_fill_tx_fifo(this_uart, (const uint8_t *)g_tx_buffer, g_tx_size); if(size_in_fifo == g_tx_size) { g_tx_size = 0; MSS_UART_disable_irq(this_uart, MSS_UART_TBE_IRQ); } else { g_tx_buffer = &g_tx_buffer[size_in_fifo]; g_tx_size = g_tx_size - size_in_fifo; } } int main(void) { uint8_t message[12] = "Hello world"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); g_tx_buffer = message; g_tx_size = sizeof(message); MSS_UART_set_tx_handler(&g_mss_uart0_lo, uart_tx_handler); while(1) { ; } return(0); } @endcode */ void MSS_UART_set_tx_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_set_modemstatus_handler() function is used to register a modem status handler function that is called by the driver when a UART modem status (MS) interrupt occurs. You must create and register the handler function to suit your application. Note: The MSS_UART_set_modemstatus_handler() function enables both the MS interrupt in the MSS UART instance. It also enables the corresponding MSS UART instance interrupt in the PolarFire SoC Core Complex PLIC as part of its implementation. Note: You can disable the MS interrupt when required by calling the MSS_UART_disable_irq() function. This is your choice and is dependent upon your application. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param handler The handler parameter is a pointer to a modem status interrupt handler function provided by your application that will be called as a result of a UART MS interrupt. This handler function must be of type mss_uart_irq_handler_t. @return This function does not return a value. Example: @code #include "mss_uart.h" void uart_modem_handler(mss_uart_instance_t * this_uart) { uint8_t status; status = MSS_UART_get_modem_status(this_uart); if(status & MSS_UART_CTS) { uart_cts_handler(); } } int main(void) { MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_modemstatus_handler(&g_mss_uart0_lo, uart_modem_handler); while(1) { ; } return(0); } @endcode */ void MSS_UART_set_modemstatus_handler ( mss_uart_instance_t * this_uart, mss_uart_irq_handler_t handler ); /***************************************************************************//** The MSS_UART_fill_tx_fifo() function fills the UART's hardware transmitter FIFO with the data found in the transmitter buffer that is passed via the tx_buffer function parameter. If the transmitter FIFO is not empty when the function is called, the function returns immediately without transferring any data to the FIFO; otherwise, the function transfers data from the transmitter buffer to the FIFO until it is full or until the complete contents of the transmitter buffer have been copied into the FIFO. The function returns the number of bytes copied into the UART's transmitter FIFO. Note: This function reads the UART's line status register (LSR) to check for the active state of the transmitter holding register empty (THRE) bit before transferring data from the data buffer to the transmitter FIFO. If THRE is 0, the function returns immediately, without transferring any data to the FIFO. If THRE is 1, the function transfers up to 16 bytes of data to the FIFO and then returns. Note: The actual transmission over the serial connection will still be in progress when this function returns. Use the MSS_UART_get_tx_status() function if you need to know when the transmitter is empty. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param tx_buffer The tx_buffer parameter is a pointer to a buffer containing the data to be transmitted. @param tx_size The tx_size parameter is the size in bytes, of the data to be transmitted. @return This function returns the number of bytes copied into the UART's transmitter FIFO. Example: @code void send_using_interrupt(uint8_t * pbuff, size_t tx_size) { size_t size_in_fifo; size_in_fifo = MSS_UART_fill_tx_fifo(&g_mss_uart0_lo, pbuff, tx_size); } @endcode */ size_t MSS_UART_fill_tx_fifo ( mss_uart_instance_t * this_uart, const uint8_t * tx_buffer, size_t tx_size ); /***************************************************************************//** The MSS_UART_get_rx_status() function returns the receiver error status of the MSS UART instance. It reads both the current error status of the receiver from the UART's line status register (LSR) and the accumulated error status from preceding calls to the MSS_UART_get_rx() function, and it combines them using a bitwise OR. It returns the cumulative overrun, parity, framing, break and FIFO error status of the receiver, since the previous call to MSS_UART_get_rx_status(), as an 8-bit encoded value. Note: The MSS_UART_get_rx() function reads and accumulates the receiver status of the MSS UART instance before reading each byte from the receiver's data register/FIFO. The driver maintains a sticky record of the cumulative receiver error status, which persists after the MSS_UART_get_rx() function returns. The MSS_UART_get_rx_status() function clears the driver's sticky receiver error record before returning. Note: The driver's transmit functions also read the line status register (LSR) as part of their implementation. When the driver reads the LSR, the UART clears any active receiver error bits in the LSR. This could result in the driver losing receiver errors. To avoid any loss of receiver errors, the transmit functions also update the driver's sticky record of the cumulative receiver error status whenever they read the LSR. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function returns the UART's receiver error status as an 8-bit unsigned integer. The returned value is 0 if no receiver errors occurred. The driver provides a set of bit mask constants that should be compared with and/or used to mask the returned value to determine the receiver error status. When the return value is compared to the following bit masks, a non-zero result indicates that the corresponding error occurred: - MSS_UART_OVERRUN_ERROR (bit mask = 0x02) - MSS_UART_PARITY_ERROR (bit mask = 0x04) - MSS_UART_FRAMING_ERROR (bit mask = 0x08) - MSS_UART_BREAK_ERROR (bit mask = 0x10) - MSS_UART_FIFO_ERROR (bit mask = 0x80) When the return value is compared to the following bit mask, a non-zero result indicates that no error occurred: - MSS_UART_NO_ERROR (bit mask = 0x00) Upon unsuccessful execution, this function returns: - MSS_UART_INVALID_PARAM (bit mask = 0xFF) Example: @code uint8_t rx_data[MAX_RX_DATA_SIZE]; uint8_t err_status; err_status = MSS_UART_get_rx_status(&g_mss_uart0); if(MSS_UART_NO_ERROR == err_status) { rx_size = MSS_UART_get_rx(&g_mss_uart0_lo, rx_data, MAX_RX_DATA_SIZE); } @endcode */ uint8_t MSS_UART_get_rx_status ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_get_modem_status() function returns the modem status of the MSS UART instance. It reads the modem status register (MSR) and returns the 8 bit value. The bit encoding of the returned value is exactly the same as the definition of the bits in the MSR. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function returns current state of the UART's MSR as an 8 bit unsigned integer. The driver provides the following set of bit mask constants that should be compared with and/or used to mask the returned value to determine the modem status: - MSS_UART_DCTS (bit mask = 0x01) - MSS_UART_DDSR (bit mask = 0x02) - MSS_UART_TERI (bit mask = 0x04) - MSS_UART_DDCD (bit mask = 0x08) - MSS_UART_CTS (bit mask = 0x10) - MSS_UART_DSR (bit mask = 0x20) - MSS_UART_RI (bit mask = 0x40) - MSS_UART_DCD (bit mask = 0x80) Example: @code void uart_modem_status_isr(mss_uart_instance_t * this_uart) { uint8_t status; status = MSS_UART_get_modem_status(this_uart); if( status & MSS_UART_DCTS ) { uart_dcts_handler(); } if( status & MSS_UART_CTS ) { uart_cts_handler(); } } @endcode */ uint8_t MSS_UART_get_modem_status ( const mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_get_tx_status() function returns the transmitter status of the MSS UART instance. It reads both the UART's line status register (LSR) and returns the status of the transmit holding register empty (THRE) and transmitter empty (TEMT) bits. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function returns the UART's transmitter status as an 8-bit unsigned integer. The returned value is 0 if the transmitter status bits are not set or the function execution failed. The driver provides a set of bit mask constants that should be compared with and/or used to mask the returned value to determine the transmitter status. When the return value is compared to the following bit mask, a non-zero result indicates that the corresponding transmitter status bit is set: - MSS_UART_THRE (bit mask = 0x20) - MSS_UART_TEMT (bit mask = 0x40) When the return value is compared to the following bit mask, a non-zero result indicates that the transmitter is busy or the function execution failed. - MSS_UART_TX_BUSY (bit mask = 0x00) Example: @code uint8_t tx_buff[10] = "abcdefghi"; MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_polled_tx(&g_mss_uart0_lo, tx_buff, sizeof(tx_buff)); while(!(MSS_UART_TEMT & MSS_UART_get_tx_status(&g_mss_uart0))) { ; } @endcode */ uint8_t MSS_UART_get_tx_status ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_set_break() function is used to send the break (9 zeros after stop bit) signal on the TX line. This function can be used only when the MSS UART is initialized in LIN mode by using MSS_UART_lin_init(). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code MSS_UART_lin_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_break(&g_mss_uart0); @endcode */ void MSS_UART_set_break ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_clear_break() function is used to remove the break signal on the TX line. This function can be used only when the MSS UART is initialized in LIN mode by using MSS_UART_lin_init(). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code MSS_UART_lin_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_clear_break(&g_mss_uart0_lo); @endcode */ void MSS_UART_clear_break ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_enable_half_duplex() function is used to enable the half-duplex (single wire) mode for the MSS UART. Though it finds application in Smartcard mode, half-duplex mode can be used in other modes as well. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_enable_half_duplex(&g_mss_uart0_lo); @endcode */ void MSS_UART_enable_half_duplex ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_disable_half_duplex() function is used to disable the half-duplex (single wire) mode for the MSS UART. Though it finds application in Smartcard mode, half-duplex mode can be used in other modes as well. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_disable_half_duplex(&g_mss_uart0_lo); @endcode */ void MSS_UART_disable_half_duplex ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_set_rx_endian() function is used to configure the LSB first or MSB first setting for MSS UART receiver @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param endian The endian parameter tells the LSB first or MSB first configuration. This parameter is of type mss_uart_endian_t. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_rx_endian(&g_mss_uart0_lo, MSS_UART_LITTLEEND); @endcode */ void MSS_UART_set_rx_endian ( mss_uart_instance_t * this_uart, mss_uart_endian_t endian ); /***************************************************************************//** The MSS_UART_set_tx_endian() function is used to configure the LSB first or MSB first setting for MSS UART transmitter. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param endian The endian parameter tells the LSB first or MSB first configuration. This parameter is of type mss_uart_endian_t. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_tx_endian(&g_mss_uart0_lo, MSS_UART_LITTLEEND); @endcode */ void MSS_UART_set_tx_endian ( mss_uart_instance_t * this_uart, mss_uart_endian_t endian ); /***************************************************************************//** The MSS_UART_set_filter_length () function is used to configure the glitch filter length of the MSS UART. This should be configured in accordance with the chosen baud rate. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param length The length parameter is of mss_uart_filter_length_t type that determines the length of the glitch filter. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_filter_length(&g_mss_uart0_lo, MSS_UART_LEN2); @endcode */ void MSS_UART_set_filter_length ( mss_uart_instance_t * this_uart, mss_uart_filter_length_t length ); /***************************************************************************//** The MSS_UART_enable_afm() function is used to enable address flag detection mode of the MSS UART @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_enable_afm(&g_mss_uart0_lo); @endcode */ void MSS_UART_enable_afm ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_disable_afm() function is used to disable address flag detection mode of the MSS UART. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_disable_afm(&g_mss_uart0_lo); @endcode */ void MSS_UART_disable_afm ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_enable_afclear () function is used to enable address flag clear of the MSS UART. This should be used in conjunction with address flag detection mode (AFM). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_enable_afclear(&g_mss_uart0_lo); @endcode */ void MSS_UART_enable_afclear ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_disable_afclear () function is used to disable address flag clear of the MSS UART. This should be used in conjunction with address flag detection mode (AFM). @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_disable_afclear(&g_mss_uart0_lo); @endcode */ void MSS_UART_disable_afclear ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_enable_rx_timeout() function is used to enable and configure the receiver timeout functionality of MSS UART. This function accepts the timeout parameter and applies the timeout based up on the baud rate as per the formula 4 x timeout x bit time. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param timeout The timeout parameter specifies the receiver timeout multiple. It should be configured according to the baud rate in use. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_enable_rx_timeout(&g_mss_uart0_lo, 24); @endcode */ void MSS_UART_enable_rx_timeout ( mss_uart_instance_t * this_uart, uint8_t timeout ); /***************************************************************************//** The MSS_UART_disable_rx_timeout() function is used to disable the receiver timeout functionality of MSS UART. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_disable_rx_timeout(&g_mss_uart0_lo); @endcode */ void MSS_UART_disable_rx_timeout ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_enable_tx_time_guard() function is used to enable and configure the transmitter time guard functionality of MSS UART. This function accepts the timeguard parameter and applies the timeguard based up on the baud rate as per the formula timeguard x bit time. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @param timeguard The timeguard parameter specifies the transmitter time guard multiple. It should be configured according to the baud rate in use. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_enable_tx_time_guard(&g_mss_uart0_lo, 24); @endcode */ void MSS_UART_enable_tx_time_guard ( mss_uart_instance_t * this_uart, uint8_t timeguard ); /***************************************************************************//** The MSS_UART_disable_tx_time_guard() function is used to disable the transmitter time guard functionality of MSS UART. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. Note that if you are using the UART on the AMP APB bus, the hardware configuration to connect UART on AMP APB bus must already be done by the application using SYSREG registers before initializing the UART instance structure. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_disable_tx_time_guard(&g_mss_uart0_lo); @endcode */ void MSS_UART_disable_tx_time_guard ( mss_uart_instance_t * this_uart ); /***************************************************************************//** The MSS_UART_set_address() function is used to set the 8-bit address for the MSS UART referenced by this_uart parameter. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param address The address parameter is the 8-bit address which is to be configured to the MSS UART referenced by this_uart parameter. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_address(&g_mss_uart0_lo, 0xAA); @endcode */ void MSS_UART_set_address ( mss_uart_instance_t * this_uart, uint8_t address ); /***************************************************************************//** The MSS_UART_set_ready_mode() function is used to configure the MODE0 or MODE1 to the TXRDY and RXRDY signals of the MSS UART referenced by this_uart parameter. The mode parameter is used to provide the mode to be configured. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param mode The mode parameter is the mss_uart_ready_mode_t type which is used to configure the TXRDY and RXRDY signal modes. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_ready_mode(&g_mss_uart0_lo, MSS_UART_READY_MODE0); @endcode */ void MSS_UART_set_ready_mode ( mss_uart_instance_t * this_uart, mss_uart_ready_mode_t mode ); /***************************************************************************//** The MSS_UART_set_usart_mode() function is used to configure the MSS UART referenced by the parameter this_uart in USART mode. Various USART modes are supported which can be configured by the parameter mode of type mss_uart_usart_mode_t. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @param mode The mode parameter is the USART mode to be configured. This parameter is of type mss_uart_usart_mode_t. @return This function does not return a value. Example: @code MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_usart_mode(&g_mss_uart0_lo, MSS_UART_SYNC_MASTER_POS_EDGE_CLK); @endcode */ void MSS_UART_set_usart_mode ( mss_uart_instance_t * this_uart, mss_uart_usart_mode_t mode ); /***************************************************************************//** The MSS_UART_enable_local_irq() function is used to enable the MMUART interrupt as a local interrupt to the hart rather than via PLIC. MMUART interrupt can be configured to trigger an interrupt via PLIC or it can be configured to trigger a local interrupt. The arrangement is such that the UART0 interrupt can appear as local interrupt on E51. The UART1 to UART4 interrupts can appear as local interrupt to U51_1 to U54_4 respectively. The UART0 to UART4 can appear as PLIC interrupt. Multiple HARTs can enable and receive the PLIC interrupt, the HART that claims the interrupt processes it. For rest of the HARTs the IRQ gets silently skipped as the interrupt claim has already been taken. By default, the PLIC interrupt is enabled by this driver when MSS_UART_enable_irq() or the APIs to set the interrupt handler is called. To enable the local interrupt application must explicitly call MSS_UART_enable_local_irq() function. Note that this function disables the interrupt over PLIC if it was previously enabled. This function must be called after the MMUART is initialized, the required interrupt hander functions are set and before initiating any data transfers. If you want to register multiple register handlers such as tx handler, rx handler etc. then this function must be called after all such handlers are set. Call to this function is treated as one time activity. The driver gives no option to disable the local interrupt and enable the PLIC interrupt again at runtime. @param this_uart The this_uart parameter is a pointer to an mss_uart_instance_t structure identifying the MSS UART hardware block that will perform the requested function. There are ten such data structures, g_mss_uart0_lo to g_mss_uart4_lo, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 5 (main APB bus) and g_mss_uart0_hi to g_mss_uart4_hi, associated with MSS UART0 to MSS UART4 when they are connected on the AXI switch slave 6 (AMP APB bus). This parameter must point to one of these ten global data structure defined within the UART driver. @return This function does not return a value. Example: @code __enable_irq(); MSS_UART_init(&g_mss_uart0_lo, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_set_rx_handler(&g_mss_uart0_lo, uart0_rx_handler, MSS_UART_FIFO_SINGLE_BYTE); MSS_UART_enable_local_irq(&g_mss_uart0_lo); @endcode */ void MSS_UART_enable_local_irq ( const mss_uart_instance_t * this_uart ); #ifdef __cplusplus } #endif #endif /* __MSS_UART_H_ */ #endif mss_uart_regs.h000066400000000000000000000170201432224323300404700ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC MSS MMUART * */ #ifndef MSS_UART_REGS_H_ #define MSS_UART_REGS_H_ #ifdef __cplusplus extern "C" { #endif /******************************************************************************* Register Bit definitions */ /* Line Control register bit definitions */ #define SB 6u /* Set break */ #define DLAB 7u /* Divisor latch access bit */ /* Line Control register bit masks */ #define SB_MASK (0x01u << SB) /* Set break */ #define DLAB_MASK (0x01u << DLAB) /* Divisor latch access bit */ /* FIFO Control register bit definitions */ #define RXRDY_TXRDYN_EN 0u /* Enable TXRDY and RXRDY signals */ #define CLEAR_RX_FIFO 1u /* Clear receiver FIFO */ #define CLEAR_TX_FIFO 2u /* Clear transmitter FIFO */ #define RDYMODE 3u /* Mode 0 or Mode 1 for TXRDY and RXRDY */ /* FIFO Control register bit MASKS */ #define RXRDY_TXRDYN_EN_MASK (0x01u << 0u) /* Enable TXRDY and RXRDY signals */ #define CLEAR_RX_FIFO_MASK (0x01u << 1u) /* Clear receiver FIFO */ #define CLEAR_TX_FIFO_MASK (0x01u << 2u) /* Clear transmitter FIFO */ #define RDYMODE_MASK (0x01u << 3u) /* Mode 0 or Mode 1 for TXRDY and RXRDY */ /* Modem Control register bit definitions */ #define LOOP 4u /* Local loopback */ #define RLOOP 5u /* Remote loopback */ #define ECHO 6u /* Automatic echo */ /* Modem Control register bit MASKS */ #define LOOP_MASK (0x01u << 4u) /* Local loopback */ #define RLOOP_MASK (0x01u << 5u) /* Remote loopback & Automatic echo*/ #define ECHO_MASK (0x01u << 6u) /* Automatic echo */ /* Line Status register bit definitions */ #define DR 0u /* Data ready */ #define THRE 5u /* Transmitter holding register empty */ #define TEMT 6u /* Transmitter empty */ /* Line Status register bit MASKS */ #define DR_MASK (0x01u << 0u) /* Data ready */ #define THRE_MASK (0x01u << 5u) /* Transmitter holding register empty */ #define TEMT_MASK (0x01u << 6u) /* Transmitter empty */ /* Interrupt Enable register bit definitions */ #define ERBFI 0u /* Enable receiver buffer full interrupt */ #define ETBEI 1u /* Enable transmitter buffer empty interrupt */ #define ELSI 2u /* Enable line status interrupt */ #define EDSSI 3u /* Enable modem status interrupt */ /* Interrupt Enable register bit MASKS */ #define ERBFI_MASK (0x01u << 0u) /* Enable receiver buffer full interrupt */ #define ETBEI_MASK (0x01u << 1u) /* Enable transmitter buffer empty interrupt */ #define ELSI_MASK (0x01u << 2u) /* Enable line status interrupt */ #define EDSSI_MASK (0x01u << 3u) /* Enable modem status interrupt */ /* Multimode register 0 bit definitions */ #define ELIN 3u /* Enable LIN header detection */ #define ETTG 5u /* Enable transmitter time guard */ #define ERTO 6u /* Enable receiver time-out */ #define EFBR 7u /* Enable fractional baud rate mode */ /* Multimode register 0 bit MASKS */ #define ELIN_MASK (0x01u << 3u) /* Enable LIN header detection */ #define ETTG_MASK (0x01u << 5u) /* Enable transmitter time guard */ #define ERTO_MASK (0x01u << 6u) /* Enable receiver time-out */ #define EFBR_MASK (0x01u << 7u) /* Enable fractional baud rate mode */ /* Multimode register 1 bit definitions */ #define E_MSB_RX 0u /* MSB / LSB first for receiver */ #define E_MSB_TX 1u /* MSB / LSB first for transmitter */ #define EIRD 2u /* Enable IrDA modem */ #define EIRX 3u /* Input polarity for IrDA modem */ #define EITX 4u /* Output polarity for IrDA modem */ #define EITP 5u /* Output pulse width for IrDA modem */ /* Multimode register 1 bit MASKS */ #define E_MSB_RX_MASK (0x01u << 0u) /* MSB / LSB first for receiver */ #define E_MSB_TX_MASK (0x01u << 1u) /* MSB / LSB first for transmitter */ #define EIRD_MASK (0x01u << 2u) /* Enable IrDA modem */ #define EIRX_MASK (0x01u << 3u) /* Input polarity for IrDA modem */ #define EITX_MASK (0x01u << 4u) /* Output polarity for IrDA modem */ #define EITP_MASK (0x01u << 5u) /* Output pulse width for IrDA modem */ /* Multimode register 2 bit definitions */ #define EERR 0u /* Enable ERR / NACK during stop time */ #define EAFM 1u /* Enable 9-bit address flag mode */ #define EAFC 2u /* Enable address flag clear */ #define ESWM 3u /* Enable single wire half-duplex mode */ /* Multimode register 2 bit MASKS */ #define EERR_MASK (0x01u << 0u) /* Enable ERR / NACK during stop time */ #define EAFM_MASK (0x01u << 1u) /* Enable 9-bit address flag mode */ #define EAFC_MASK (0x01u << 2u) /* Enable address flag clear */ #define ESWM_MASK (0x01u << 3u) /* Enable single wire half-duplex mode */ /* Multimode Interrupt Enable register and Multimode Interrupt Identification register definitions */ #define ERTOI 0u /* Enable receiver timeout interrupt */ #define ENACKI 1u /* Enable NACK / ERR interrupt */ #define EPID_PEI 2u /* Enable PID parity error interrupt */ #define ELINBI 3u /* Enable LIN break interrupt */ #define ELINSI 4u /* Enable LIN sync detection interrupt */ /* Multimode Interrupt Enable register and Multimode Interrupt Identification register MASKS */ #define ERTOI_MASK (0x01u << 0u) /* Enable receiver timeout interrupt */ #define ENACKI_MASK (0x01u << 1u) /* Enable NACK / ERR interrupt */ #define EPID_PEI_MASK (0x01u << 2u) /* Enable PID parity error interrupt */ #define ELINBI_MASK (0x01u << 3u) /* Enable LIN break interrupt */ #define ELINSI_MASK (0x01u << 4u) /* Enable LIN sync detection interrupt */ #ifdef __cplusplus } #endif #endif /* MSS_UART_REGS_H_ */ mss_pdma/000077500000000000000000000000001432224323300350565ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_pdma.c000066400000000000000000000277341432224323300370420ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_pdma/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PoalrFire SoC Microprocessor Subsystem PDMA bare metal driver implementation. * * SVN $Revision$ * SVN $Date$ */ #include "drivers/mss/mss_pdma/mss_pdma.h" #include "mss_hal.h" #ifdef __cplusplus extern "C" { #endif /* MACRO to set the correct channel memory offset for the memory mapped * configuration register. */ #define MSS_PDMA_REG_OFFSET(x) \ (uint64_t)(PDMA_REG_BASE + (PDMA_CHL_REG_OFFSET * (x))) /* Default is maximum transaction size for both write_size and read_size. */ uint8_t g_channel_nextcfg_wsize[MSS_PDMA_lAST_CHANNEL] = { 0x0Fu, 0x0Fu, 0x0Fu, 0x0Fu }; uint8_t g_channel_nextcfg_rsize[MSS_PDMA_lAST_CHANNEL] = { 0x0Fu, 0x0Fu, 0x0Fu, 0x0Fu }; /*-------------------------------------------------------------------------*//** * MSS_PDMA_init() * See pse_pdma.h for description of this function. */ void MSS_PDMA_init ( void ) { ; } /*-------------------------------------------------------------------------*//** * MSS_PDMA_setup_transfer() * See pse_pdma.h for description of this function. */ mss_pdma_error_id_t MSS_PDMA_setup_transfer ( mss_pdma_channel_id_t channel_id, mss_pdma_channel_config_t *channel_config ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return MSS_PDMA_ERROR_INVALID_CHANNEL_ID; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); /* Basic House Keeping, return if errors exist. */ if (channel_config->src_addr == 0u) { return MSS_PDMA_ERROR_INVALID_SRC_ADDR; } if (channel_config->dest_addr == 0u) { return MSS_PDMA_ERROR_INVALID_DEST_ADDR; } /* If a run transaction is in progress, return error. * Channel can only be claimed when run is low */ if (pdmareg->control_reg & MASK_PDMA_CONTROL_RUN) { return MSS_PDMA_ERROR_TRANSACTION_IN_PROGRESS; } /* Set or clear the interrupts for the transfer. */ if (channel_config->enable_done_int) { pdmareg->control_reg |= ((uint32_t)MASK_PDMA_ENABLE_DONE_INT); } else { pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT); } if (channel_config->enable_err_int) { pdmareg->control_reg |= ((uint32_t)MASK_PDMA_ENABLE_ERR_INT); } else { pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT); } /* clear Next registers. */ pdmareg->control_reg |= (uint32_t)MASK_CLAIM_PDMA_CHANNEL; /* Setup the source and destination addresses.*/ pdmareg->next_destination = channel_config->dest_addr; pdmareg->next_source = channel_config->src_addr; /* Set the transfer size. */ pdmareg->next_bytes = channel_config->num_bytes; /* Setup repeat and force order requirements. */ if (channel_config->repeat) { pdmareg->next_config |= MASK_REPEAT_TRANSCTION; } else { pdmareg->next_config &= ~((uint32_t)MASK_REPEAT_TRANSCTION); } if (channel_config->force_order) { pdmareg->next_config |= ((uint32_t)MASK_FORCE_ORDERING); } else { pdmareg->next_config &= ~((uint32_t)MASK_FORCE_ORDERING); } /* PDMA transaction size.. set to maximum. */ pdmareg->next_config |= (g_channel_nextcfg_wsize[channel_id] << SHIFT_CH_CONFIG_WSIZE); pdmareg->next_config |= (g_channel_nextcfg_rsize[channel_id] << SHIFT_CH_CONFIG_RSIZE); return MSS_PDMA_OK; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ mss_pdma_error_id_t MSS_PDMA_set_transction_size ( mss_pdma_channel_id_t channel_id, uint8_t write_size, uint8_t read_size ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return MSS_PDMA_ERROR_INVALID_CHANNEL_ID; } if (write_size > 0x0Fu) { return MSS_PDMA_ERROR_INVALID_NEXTCFG_WSIZE; } if (read_size > 0x0Fu) { return MSS_PDMA_ERROR_INVALID_NEXTCFG_RSIZE; } g_channel_nextcfg_wsize[channel_id] = write_size; g_channel_nextcfg_rsize[channel_id] = read_size; return MSS_PDMA_OK; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ mss_pdma_error_id_t MSS_PDMA_start_transfer ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return MSS_PDMA_ERROR_INVALID_CHANNEL_ID; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); /* If a run transaction is in progress, return error. * Channel can only be claimed when run is low */ pdmareg->control_reg |= ((uint32_t)MASK_PDMA_CONTROL_RUN); return MSS_PDMA_OK; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint32_t MSS_PDMA_get_active_transfer_type ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); return pdmareg->exec_config; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint64_t MSS_PDMA_get_number_bytes_remaining ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); return pdmareg->exec_bytes; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint64_t MSS_PDMA_get_destination_current_addr ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); return pdmareg->exec_destination; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint64_t MSS_PDMA_get_source_current_addr ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); return pdmareg->exec_source; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint8_t MSS_PDMA_get_transfer_complete_status ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); if (pdmareg->control_reg & MASK_PDMA_TRANSFER_DONE) { return 1u; } else { return 0u; } } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint8_t MSS_PDMA_get_transfer_error_status ( mss_pdma_channel_id_t channel_id ) { if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); if (pdmareg->control_reg & MASK_PDMA_TRANSFER_ERROR) { return 1u; } else { return 0u; } } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint8_t MSS_PDMA_clear_transfer_complete_status ( mss_pdma_channel_id_t channel_id ) { uint8_t intStatus = 0u; if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); if (pdmareg->control_reg & MASK_PDMA_TRANSFER_DONE) { intStatus = 1u; pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_TRANSFER_DONE); } return intStatus; } /***************************************************************************//** * See pse_pdma.h for description of this function. */ uint8_t MSS_PDMA_clear_transfer_error_status ( mss_pdma_channel_id_t channel_id ) { uint8_t intStatus = 0u; if (channel_id > MSS_PDMA_CHANNEL_3) { return 0u; } /* Set the register structure pointer for the PDMA channel. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id); if (pdmareg->control_reg & MASK_PDMA_TRANSFER_ERROR) { intStatus = 1u; pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_TRANSFER_ERROR); } return intStatus; } /***************************************************************************//** * Each DMA channel has two interrupts, one for transfer complete * and the other for the transfer error. */ uint8_t dma_ch0_DONE_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_0); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT); return 0u; } uint8_t dma_ch0_ERR_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_0); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT); return 0u; } uint8_t dma_ch1_DONE_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_1); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT); return 0u; } uint8_t dma_ch1_ERR_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_1); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT); return 0u; } uint8_t dma_ch2_DONE_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_2); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT); return 0u; } uint8_t dma_ch2_ERR_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_2); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT); return 0u; } uint8_t dma_ch3_DONE_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_3); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT); return 0u; } uint8_t dma_ch3_ERR_IRQHandler ( void ) { /* Clear the interrupt enable bit. */ volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET (MSS_PDMA_CHANNEL_3); pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT); return 0u; } #ifdef __cplusplus } #endif mss_pdma.h000066400000000000000000000541741432224323300370450ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_pdma/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC Microprocessor subsystem PDMA bare metal software driver public * APIs. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS PDMA Bare Metal Driver. ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor Subsystem (MSS) includes the MSS PDMA peripherals for autonomous data transfers. The MSS PDMA has memory-mapped control registers accessed over a TileLink slave interface to allow software to set up DMA transfers, and has a TileLink bus master port into the TileLink bus fabric to allow it to rapidly copy data between two locations in memory. The MSS PDMA can support multiple independent simultaneous DMA transfers using different PDMA channels and can generate PLIC interrupts on either a transfer has completed, or when a transfer error has occurred. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all features of the MSS PDMA driver is covered by this driver. There are no dependencies on the hardware flow when configuring MSS PDMA. The source and destination of the DMA transaction must be enabled, either in the hardware or by your application program. The source and destination addresses must be located at valid addresses in the PolarFire SoC MSS memory map and must be appropriate to the configuration that you specify the PDMA channel. The base address, register addresses, and interrupt numbers associated with MSS PDMA block are defined in the mpfs hal as constants. User must ensure that the latest mpfs hal is included in the example project. ============================================================================== Theory of Operation ============================================================================== The PDMA driver function are grouped into the following categories: - Initialization - Configuration - Transfer Control - Interrupt Control -------------------------------- Initialization -------------------------------- The PolarFire SoC MSS PDMA driver is initialized through the call to the MSS_PDMA_init() function. The MSS_PDMA_init() function must be called before any other MSS PDMA driver functions. -------------------------------- Configuration -------------------------------- Each PDMA channel is configured through the call to MSS_PDMA_setup_transfer() function. Configuration includes : - The PDMA channel for transaction. - Source and destination addresses. - The transfer sizes. - Repeat the transfer - Ordering requirements. - Set / Clear the interrupt for the transfer The PolarFire SoC MSS PDMA has four independent DMA channels which operate concurrently to support multiple simultaneous transfers. Each channel has an independent set of registers and interrupts. The PDMA channels can be configured through the call to MSS_PDMA_setup_transfer() function. Apart from selecting the channel the MSS_PDMA_setup_transfer() function will also setup the transfer size, source and destination addresses. MSS_PDMA_setup_transfer() function will also configure the repeat and force order requirements as the PoalrFire SoC MSS PDMA supports multiple simultaneous transfers. The PDMA has two interrupts per channel which are used to signal when either a transfer has completed or when a transfer error has occurred. These interrupts are enabled by the application software and are set / cleared by MSS_PDMA_setup_transfer() function. -------------------------------- Transfer Control -------------------------------- The PDMA transfers can be initiated by a call to the MSS_PDMA_start_transfer() function after a PDMA channel has been configured. The MSS_PDMA_start_transfer() function will write the config register in PDMA memory map. The write_size and read_size buffers are used to determine the size and alignment of individual PDMA transactions as a single PDMA transfers may require multiple transactions. The configuration of the currently selected PDMA channel can be read by calling the MSS_PDMA_get_active_transfer_type() function. -------------------------------- Interrupt Control -------------------------------- The PDMA has two interrupts per channel which are used to signal either a successful completion og the transfer, a transfer error. These interrupts are enabled by the application software by a call to MSS_PDMA_setup_transfer() function. The MSS_PDMA_get_transfer_complete_status() function will indicate the DMA transfer success status for selected DMA channel. The MSS_PDMA_get_transfer_error_status() function will indicate the DMA transfer failure status for selected DMA channel. The MSS_PDMA_clear_transfer_complete_status() function can be used to clear the DMA transfer success status. The MSS_PDMA_clear_transfer_error_status() function can be used to clear the DMA transfer error status. *//*==========================================================================*/ #ifndef MSS_PDMA_H #define MSS_PDMA_H #ifdef __cplusplus extern "C" { #endif #include /*---------------------------Public Data Structure----------------------------*/ /*----------------------------------PDMA--------------------------------------*/ /*----------------------------------------------------------------------------*//* The mss_pdma_channel_id_t enumeration is used to identify peripheral DMA channels. It is used as function parameter to specify the PDMA channel used. */ typedef enum __pdma_channel_id { MSS_PDMA_CHANNEL_0 = 0, MSS_PDMA_CHANNEL_1, MSS_PDMA_CHANNEL_2, MSS_PDMA_CHANNEL_3, MSS_PDMA_lAST_CHANNEL, } mss_pdma_channel_id_t; /*-------------------------------------------------------------------------*//** The mss_pdma_channel_config_t structure is used to configure the desired Platform DMA channel. PDMA channel configuration includes configuration of source, destination address and the number of bytes for the DMA transfer. Single DMA transfer may require multiple DMA transactions, the size and alignment of the individual DMA transaction can be forced. The PDMA can be programmed to automatically repeat a transfer. The MSS PDMA have two interrupts per channel, transfer complete interrupt and transfer error interrupt. The two interrupts can be enabled by configuring respective bits in the mss_pdma_channel_config_t structure. */ typedef struct _pdmachannelconfig { volatile uint64_t src_addr; /* source address */ volatile uint64_t dest_addr; /* destination address */ volatile uint64_t num_bytes; /* Number of bytes to be transfered. * Base 2 Logarithm */ volatile uint8_t enable_done_int; /* enable transfer complete interrupt */ volatile uint8_t enable_err_int; /* enable transfer error interrupt*/ volatile uint8_t repeat; /* repeat the transaction */ volatile uint8_t force_order; /* Enforces strict ordering by only allowing one of each transfer type in-flight at a time */ } mss_pdma_channel_config_t; /*------------------------Private data structures-----------------------------*/ /*----------------------------------- PDMA -----------------------------------*/ /*------------------------------------------------------------------------*//** * The mss_pdma_error_id_t enumeration is used to specify the error status from * MSS PDMA transfer / transaction functions. */ typedef enum __pdma_error_id_t { MSS_PDMA_OK = 0, //!< PDMA_OK MSS_PDMA_ERROR_INVALID_SRC_ADDR, //!< ERROR_INVALID_SRC_ADDR MSS_PDMA_ERROR_INVALID_DEST_ADDR, //!< ERROR_INVALID_DEST_ADDR MSS_PDMA_ERROR_TRANSACTION_IN_PROGRESS,//!< ERROR_TRANSACTION_IN_PROGRESS MSS_PDMA_ERROR_INVALID_CHANNEL_ID, //!< ERROR_INVALID_CHANNEL_ID MSS_PDMA_ERROR_INVALID_NEXTCFG_WSIZE, //!< ERROR_INVALID_NEXTCFG_WSIZE MSS_PDMA_ERROR_INVALID_NEXTCFG_RSIZE, //!< ERROR_INVALID_NEXTCFG_RSIZE MSS_PDMA_ERROR_LAST_ID, //!< ERROR_LAST_ID } mss_pdma_error_id_t; /*-------------------------------------------------------------------------*//** * The mss_pdma_t structure will describe the functionality of the memory mapped * registers in the Platform DMA Engine. */ typedef struct _pdmaregs { volatile uint32_t control_reg; /* Channel Control Register */ volatile uint32_t next_config; /* Next transfer type */ volatile uint64_t next_bytes; /* Number of bytes to be transfered. * Base 2 Logarithm */ volatile uint64_t next_destination; /* Destination Start Address */ volatile uint64_t next_source; /* Source start Address*/ const volatile uint32_t exec_config; /* Active transfer type */ const volatile uint64_t exec_bytes; /* Number of bytes remaining. */ const volatile uint64_t exec_destination;/* Destination current address. */ const volatile uint64_t exec_source; /* Source current address. */ } mss_pdma_t; /* PDMA Register base address. */ #define PDMA_REG_BASE 0x03000000U /* PDMA Channel Register offset.*/ #define PDMA_CHL_REG_OFFSET 0x1000U #define MASK_PDMA_CONTROL_RUN 0x02U #define MASK_CLAIM_PDMA_CHANNEL 0x01U #define MASK_PDMA_ENABLE_DONE_INT 0x00004000U #define MASK_PDMA_ENABLE_ERR_INT 0x00008000U #define SHIFT_CH_CONFIG_WSIZE 24U #define SHIFT_CH_CONFIG_RSIZE 28U #define MASK_MAXIUM_WSIZE 0x0F000000U #define MASK_MAXIUM_RSIZE 0xF0000000U #define MASK_REPEAT_TRANSCTION 0x04U #define MASK_FORCE_ORDERING 0x08U #define MASK_PDMA_TRANSFER_ERROR 0x80000000U #define MASK_PDMA_TRANSFER_DONE 0x40000000U /*--------------------------------Public APIs---------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_PDMA_init() function is used to initialize the PolarFire SoC MSS Platform DMA engine. It initializes the basic data structures required for driver functionality. @param This function does not need any parameters. @return This function does not return value. @endcode */ void MSS_PDMA_init ( void ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_setup_transfer() function is used to configure an individual DMA channel. Apart from selecting the DMA channel the MSS_PDMA_setup_transfer() function will also setup the transfer size, source and destination addresses. This function will also configure the repeat and force order requirements as the PolarFire SoC MSS Peripheral DMA supports multiple simultaneous transfers. Once transfer is setup, it can be started. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @param channel_config The channel_config parameter structure contains the data needed for a DMA transfer. - Source Address - Destination address - Number of Bytes - Enable the Done Interrupt - Enable the ErrorInterrupt - Set the active transfer type, single or repeat. - Force Order. @return pdma_error_id_t The function returns error signals of type mss_pdma_error_id_t. Example: The following call will configure channel 0 @code g_pdma_error_code = MSS_PDMA_setup_transfer(PDMA_CHANNEL_0, &pdma_config_ch0); @endcode */ mss_pdma_error_id_t MSS_PDMA_setup_transfer ( mss_pdma_channel_id_t channel_id, mss_pdma_channel_config_t *channel_config ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_start_transfer() function is used to initiate an individual transfer on selected DMA channel . The source and destination address of the transfer and the number of bytes to be transferred must be configured before calling this function. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return The function returns error signals of type mss_pdma_error_id_t. Example: The following call will configure channel 0 @code // Setup the PDMA channel for transfer g_pdma_error_code = MSS_PDMA_setup_transfer(PDMA_CHANNEL_0, &pdma_config_ch0); // Initiate the transfer for channel 0. MSS_PDMA_start_transfer(PDMA_CHANNEL_0); @endcode */ mss_pdma_error_id_t MSS_PDMA_start_transfer ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_set_transction_size() function is used to set a channel DMA transaction size. The write_size and read_size buffers are used to determine the size and alignment of individual PDMA transaction as a single PDMA transfer may require multiple transaction. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @param write_size The write_size parameter specifies the base 2 logarithm of PDMA transaction. e.g. 0 is 1 byte, 3 is 8 bytes, 5 is 32 bytes @param read_size The read_size parameter specifies the base 2 logarithm of PDMA transaction. e.g. 0 is 1 byte, 3 is 8 bytes, 5 is 32 bytes @return The function returns error signals of type mss_pdma_error_id_t. Example: The following call will configure channel 0 transaction to 32bytes. @code MSS_PDMA_set_transction_size(PDMA_CHANNEL_0, write_size, read_size) @endcode */ mss_pdma_error_id_t MSS_PDMA_set_transction_size ( mss_pdma_channel_id_t channel_id, uint8_t write_size, uint8_t read_size ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_get_active_transfer_type() function is used to request active transfer type for selected DMA channel. The transfer type for the DMA channel was configured during the channel configuration process, calling this function will read the transfer type from the configured DMA channel. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function returns a 32-bit value indicating the active transfer type of the DMA channel. Example: The following call will return the Channel (0) active transfer type. @code MSS_PDMA_get_active_transfer_type(PDMA_CHANNEL_0); @endcode */ uint32_t MSS_PDMA_get_active_transfer_type ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_get_number_bytes_remaining() function is used to request number of bytes remaining to be transfered. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 64-bit value indicating number of bytes remaining to be transferred. Example: The following call will return the number of bytes remaining Channel (0). @code MSS_PDMA_get_number_bytes_remaining(PDMA_CHANNEL_0); @endcode */ uint64_t MSS_PDMA_get_number_bytes_remaining ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_get_destination_current_addr() function is used to request the channel Destination address. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 64-bit value indicating destination address of the selected DMA channel. Example: The following call will return the Channel (0) Destination address register value. @code MSS_PDMA_get_destination_current_addr(PDMA_CHANNEL_0); @endcode */ uint64_t MSS_PDMA_get_destination_current_addr ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_get_source_current_addr() function is used to request the channel Source address. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 64-bit value indicating source address of the selected DMA channel. Example: The following call will return the Channel (0) Source address register value. @code MSS_PDMA_get_source_current_addr(PDMA_CHANNEL_0); @endcode */ uint64_t MSS_PDMA_get_source_current_addr ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_get_transfer_complete_status() function is used to request the completion status of last DMA transfer. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 8-bit value indicating completion status of the last DMA transfer. Example: The following call will return the Channel (0) transfer status. @code MSS_PDMA_get_transfer_complete_status(PDMA_CHANNEL_0); @endcode */ uint8_t MSS_PDMA_get_transfer_complete_status ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_get_transfer_error_status() function is used to request the error status of last DMA transfer. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 8-bit value indicating the error status of the last DMA transfer. Example: The following call will return the Channel (0) transfer error status. @code MSS_PDMA_get_transfer_error_status(PDMA_CHANNEL_0); @endcode */ uint8_t MSS_PDMA_get_transfer_error_status ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_clear_transfer_complete_status() function is used to request the transfer complete interrupt status. If the function returns one, that indicates that the transfer is complete and the transfer complete interrupt is cleared. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 8-bit value indicating the transfer complete interrupt status of the last DMA transfer. Example: The following call will return the Channel (0) transfer complete interrupt status of the last DMA transfer @code MSS_PDMA_clear_transfer_complete_status(PDMA_CHANNEL_0); @endcode */ uint8_t MSS_PDMA_clear_transfer_complete_status ( mss_pdma_channel_id_t channel_id ); /*-------------------------------------------------------------------------*//** The MSS_PDMA_clear_transfer_error_status() function is used to request the transfer error interrupt status. If the function returns one, that indicates that the transfer error has occurred and error interrupt is cleared. @param channel_id The channel_id parameter specifies the Platform DMA channel selected for DMA transaction. @return This function return 8-bit value indicating the transfer error interrupt status of the last DMA transfer. Example: The following call will return the Channel (0) transfer error interrupt status of the last DMA transfer @code MSS_PDMA_clear_transfer_complete_status(PDMA_CHANNEL_0); @endcode */ uint8_t MSS_PDMA_clear_transfer_error_status ( mss_pdma_channel_id_t channel_id ); #endif /* MSS_PDMA_H */ mss_qspi/000077500000000000000000000000001432224323300351115ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_qspi.c000066400000000000000000000236531432224323300371240ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_qspi/***************************************************************************//** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC (MPFS) Microprocessor SubSystem QSPI bare metal software driver * implementation. * */ #include "mss_qspi.h" #include "mss_plic.h" #ifdef __cplusplus extern "C" { #endif #define QSPI_BYTESUPPER_MASK ((uint32_t)0xFFFF0000u) static void default_status_handler(uint32_t value); static volatile uint32_t g_irq_rd_byte_size = 0u; static volatile uint8_t g_rx_complete = 0u; static void * g_rd_buffer; static volatile mss_qspi_status_handler_t g_handler; /***************************************************************************//** * See mss_qspi.h for details of how to use this function. */ void MSS_QSPI_init ( void ) { g_handler = default_status_handler; QSPI->CONTROL = CTRL_EN_MASK | CTRL_SAMPLE_SCK | (0x1u << CTRL_CLKRATE) | CTRL_CLKIDL_MASK ; QSPI->INTENABLE = 0x0u; } /***************************************************************************//** * See mss_qspi.h for details of how to use this function. */ void MSS_QSPI_configure ( const mss_qspi_config_t* config ) { QSPI->CONTROL = (uint32_t)(config->sample << CTRL_SAMPLE) | (uint32_t)(config->io_format << CTRL_QMODE0) | (uint32_t)(config->clk_div << CTRL_CLKRATE) | (uint32_t)(config->xip << CTRL_XIP) | (uint32_t)(config->xip_addr << CTRL_XIPADDR) | (uint32_t)(config->spi_mode << CTRL_CLKIDL) | CTRL_EN_MASK; } /***************************************************************************//** * See mss_qspi.h for details of how to use this function. */ void MSS_QSPI_get_config ( mss_qspi_config_t* config ) { volatile uint32_t reg =0; reg = QSPI->CONTROL; config->spi_mode = ((reg & CTRL_CLKIDL_MASK) >> CTRL_CLKIDL); reg = reg & (uint32_t )((uint32_t )CTRL_QMODE12_MASK | (uint32_t )CTRL_QMODE0_MASK); reg = reg >> CTRL_QMODE0; config->io_format = (mss_qspi_io_format)reg; config->clk_div = (mss_qspi_clk_div)((reg & CTRL_CLKRATE_MASK) >> CTRL_CLKRATE); config->xip = (uint8_t)((reg & CTRL_XIP_MASK) >> CTRL_XIP); config->xip_addr = (uint8_t)((reg & CTRL_XIPADDR_MASK) >> CTRL_XIPADDR); config->sample = (uint8_t)((reg & CTRL_SAMPLE_MASK) >> CTRL_SAMPLE); } /***************************************************************************//** * See mss_qspi.h for details of how to use this function. */ void MSS_QSPI_polled_transfer_block ( uint8_t num_addr_bytes, const void * const tx_buffer, uint32_t tx_byte_size, const void * const rd_buffer, uint32_t rd_byte_size, uint8_t num_idle_cycles ) { uint32_t idx; uint8_t* buf8 = (uint8_t*)tx_buffer; uint32_t* buf32 = (uint32_t*)tx_buffer; volatile uint32_t skips; uint32_t cbytes; uint32_t total_byte_cnt; uint32_t words = 0u; cbytes = 1u + tx_byte_size + num_addr_bytes; total_byte_cnt = 1u + tx_byte_size + num_addr_bytes + rd_byte_size; QSPI->INTENABLE = 0u; while ((QSPI->STATUS & STTS_READY_MASK) == 0u){}; /*bit16 to 31 define the number of Upper bytes when count is >65535 Write to lower 16 bit is ignored*/ QSPI->FRAMESUP = total_byte_cnt & QSPI_BYTESUPPER_MASK; num_idle_cycles = (num_idle_cycles << 3u); skips = (total_byte_cnt & 0x0000FFFFu); skips |= (cbytes << FRMS_CBYTES); skips |= (((QSPI->CONTROL & CTRL_QMODE12_MASK)? 1u:0u) << FRMS_QSPI); skips |= ((uint32_t)num_idle_cycles) << 23u; skips |= FRMS_FWORD_MASK; QSPI->FRAMES = (uint32_t)skips; QSPI->CONTROL |= CTRL_FLAGSX4_MASK; words = cbytes / (uint32_t)4u; for (idx = 0u; idx < words; ++idx) { while (QSPI->STATUS & STTS_TFFULL_MASK){}; QSPI->TXDATAX4 = (uint32_t)buf32[idx]; } QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK; for (idx = (cbytes - (cbytes % 4u)); idx < cbytes; ++idx) { while (QSPI->STATUS & STTS_TFFULL_MASK){}; QSPI->TXDATAX1 = (uint8_t)buf8[idx]; } buf32 = (uint32_t*)rd_buffer; buf8 = (uint8_t*)rd_buffer; if (rd_byte_size) { words = rd_byte_size / 4u; QSPI->CONTROL |= CTRL_FLAGSX4_MASK; for (idx = 0u; idx < words; ++idx) { while (QSPI->STATUS & STTS_RFEMPTY_MASK){}; buf32[idx] = QSPI->RXDATAX4; } QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK; for (idx = (rd_byte_size - (rd_byte_size % 4u)); idx < rd_byte_size; ++idx) { while (QSPI->STATUS & STTS_RFEMPTY_MASK){}; buf8[idx] = QSPI->RXDATAX1; } while (0u == (QSPI->STATUS & STTS_RDONE_MASK)) { skips = (uint64_t)((QSPI->STATUS & STTS_FLAGSX4_MASK) ? QSPI->RXDATAX4 : QSPI->RXDATAX1); } } } /***************************************************************************//** * See mss_qspi.h for details of how to use this function. */ uint8_t MSS_QSPI_irq_transfer_block ( uint8_t num_addr_bytes, const void * const tx_buffer, uint32_t tx_byte_size, const void * const rd_buffer, uint32_t rd_byte_size, uint8_t num_idle_cycles ) { uint32_t idx; uint32_t cbytes; uint32_t total_byte_cnt; const uint8_t* buf8 = tx_buffer; const uint32_t* buf32 = tx_buffer; uint8_t returnval = 0u; g_rd_buffer = (uint32_t*)rd_buffer; cbytes = 1u + tx_byte_size + num_addr_bytes; total_byte_cnt = 1u + tx_byte_size + num_addr_bytes + rd_byte_size; if ((QSPI->STATUS & STTS_READY_MASK) == 0u) { returnval = 1u; } else { volatile uint32_t skips=0; uint32_t enable = 0u; enable = INTE_TDONE_MASK; /*bit16 to 31 define the number of Upper bytes when count is >65535 Write to lower 16 bit is ignored*/ QSPI->FRAMESUP = total_byte_cnt & QSPI_BYTESUPPER_MASK; num_idle_cycles = (num_idle_cycles << 3u); skips = (total_byte_cnt & 0x0000FFFFu); skips |= (cbytes << FRMS_CBYTES); skips |= (((QSPI->CONTROL & CTRL_QMODE12_MASK)? 1u:0u) << FRMS_QSPI); skips |= ((uint32_t)num_idle_cycles) << 23u; skips |= FRMS_FWORD_MASK; QSPI->FRAMES = skips; QSPI->CONTROL |= CTRL_FLAGSX4_MASK; if (rd_byte_size) { g_rx_complete = 0u; g_irq_rd_byte_size = rd_byte_size; QSPI->CONTROL |= CTRL_FLAGSX4_MASK; enable |= (uint32_t )((uint32_t )INTE_RDONE_MASK | (uint32_t )INTE_RAVLB_MASK); } uint32_t words = 0u; words = cbytes / (uint32_t)4u; for (idx = 0u; idx < words; ++idx) { while (QSPI->STATUS & STTS_TFFULL_MASK){}; QSPI->TXDATAX4 = (uint32_t)buf32[idx]; } QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK; for (idx = (cbytes - (cbytes % 4u)); idx < cbytes; ++idx) { while (QSPI->STATUS & STTS_TFFULL_MASK){}; QSPI->TXDATAX1 = (uint8_t)buf8[idx]; } QSPI->INTENABLE = enable; returnval = 0u; } return(returnval); } /***************************************************************************//** * See mss_qspi.h for details of how to use this function. */ void MSS_QSPI_set_status_handler ( mss_qspi_status_handler_t handler ) { if ((mss_qspi_status_handler_t)0 != handler) { g_handler = handler; } } static void qspi_isr(void) { uint32_t idx; //static uint32_t empty = 0u; // unused //static uint32_t tx_fifo_full = 0u; // unused uint32_t status; status = QSPI->STATUS; if (STTS_TDONE_MASK == (uint32_t)(status & STTS_TDONE_MASK)) { g_handler(STTS_TDONE_MASK); QSPI->STATUS |= STTS_TDONE_MASK; } if (STTS_RAVLB_MASK == (uint32_t)(status & STTS_RAVLB_MASK)) { if (0u == g_rx_complete) { uint8_t* buf8 = g_rd_buffer; uint32_t* buf32 = g_rd_buffer; uint32_t words = 0u; words = g_irq_rd_byte_size / 4u; QSPI->CONTROL |= CTRL_FLAGSX4_MASK; for (idx = 0u; idx < words; ++idx) { while (status & STTS_RFEMPTY_MASK){}; buf32[idx] = QSPI->RXDATAX4; } QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK; for (idx = (g_irq_rd_byte_size - (g_irq_rd_byte_size % 4u)); idx < g_irq_rd_byte_size; ++idx) { while (status & STTS_RFEMPTY_MASK){}; buf8[idx] = QSPI->RXDATAX1; } uint32_t skips = 0; while (0u == (QSPI->STATUS & STTS_RFEMPTY_MASK)) { /*Make sure that the Receive FIFO is empty and any remaining data is read from it after desired bytes have been received.*/ skips = (uint32_t)((QSPI->STATUS & STTS_FLAGSX4_MASK) ? QSPI->RXDATAX4 : QSPI->RXDATAX1); (void) skips; /* use skips to avoid compiler warning */ } } } if (STTS_RDONE_MASK == (uint32_t)(status & STTS_RDONE_MASK)) { g_rx_complete = 1u; /*This means receive transfer is now complete. invoke the callback * function*/ g_handler(STTS_RDONE_MASK); /*disable RXDONE, RXEMPTY, RXAVLBL interrupt*/ QSPI->INTENABLE &= ~(INTE_RDONE_MASK | INTE_RAVLB_MASK); QSPI->STATUS |= STTS_RDONE_MASK; } } static void default_status_handler(uint32_t value) { /*Take some default interrupt handling action here*/ } /*QSPI interrupt handler function*/ uint8_t PLIC_qspi_IRQHandler(void) { qspi_isr(); return (uint8_t)EXT_IRQ_KEEP_ENABLED; } #ifdef __cplusplus } #endif mss_qspi.h000066400000000000000000000716471432224323300371370ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_qspi/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * PolarFire SoC (MPFS) Microprocessor SubSystem QSPI bare metal software * driver public API. * */ /*=========================================================================*//** @mainpage PolarFire SoC MSS QSPI Bare Metal Driver ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor SubSystem (MSS) includes a QSPI controller for fast SPI transfers. The MSS QSPI is designed as a SPI master to work specifically with the (Q)SPI memory devices. The PolarFire SoC MSS QSPI driver provides a set of functions for controlling the MSS QSPI as part of a bare metal system, where no operating system is available. This driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. -------------------------------- Features -------------------------------- The PolarFire SoC MSS QSPI driver provides the following features: - QSPI Master operations in 1-bit, 2-bit, 4-bit formats and extended operations - XIP operations - Configurable SPI mode0 and mode3 - Programmable SPI clock ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all the features of the MSS QSPI peripheral is covered by this driver, with the exception of the PolarFire SoC IOMUX configuration. The PolarFire SoC allows multiple non-concurrent uses of few external pins through IOMUX configuration. This feature allows optimization of external pin usage by assigning external pins for use by either the microprocessor subsystem or the FPGA fabric. The MSS QSPI serial signals are routed through IOMUXs to the PolarFire SoC device external pins. The MSS QSPI serial signals can also be routed through IOMUXs to the PolarFire SoC FPGA fabric. For more information on IOMUX, see the IOMUX section of the PolarFire SoC Microprocessor Subsystem (MSS) User's Guide. The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You must ensure that the MSS QSPI peripherals are enabled and configured in the PolarFire SoC MSS configurator if you wish to use them. For more information on IOMUXs, refer to the IOMUX section of the PolarFire SoC microprocessor Subsystem (MSS) User's Guide. The base address and the register addresses are defined in this driver as constants. The interrupt number assignment for the MSS QSPI peripherals is defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole toolchain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS QSPI driver functions are grouped into the following categories. - Initialization and configuration functions - Polled transmit and receive functions - Interrupt driven transmit and receive functions -------------------------------- Initialization and Configuration -------------------------------- The MSS QSPI supports the following operations. - Normal SPI operations (1 bit) - Dual SPI operations (2 bit) - Quad SPI operations (4 bit) The MSS QSPI driver provides the MSS_QSPI_init() function to initialize the MSS QSPI hardware block. This initialization function must be called before any other MSS QSPI driver functions can be called. The MSS QSPI driver provides the MSS_QSPI_config() function to configure the MSS QSPI with desired configuration values. It also provides the MSS_QSPI_get_config() function to read back the current configurations of the MSS QSPI. You can use this function to retrieve the current configurations and then overwrite them with the application specific values, such as SPI mode, SPI clock rate, SDI sampling, QSPI operation, XIP mode and XIP address bits. All these configuration options are explained in detail in the API function description of the respective function. -------------------------------------- SPI master block transfer control -------------------------------------- The driver can transmit and receive data when initialized and configured with the desired configuration values. The MSS QSPI is designed to specifically work with SPI flash memories. It supports a single, active-low slave-select output. Block transfers can be accomplished in the following ways. - Polled block transfer - Interrupt driven block transfer --------------------------- Polled block transfer --------------------------- The MSS_QSPI_polled_transfer_block() is provided to accomplish data transfers where no interrupt is used. This function polls the status register to know the current status of the on-going transfer. This is a blocking function. A MSS QSPI block transfer always has some amount of data to be transmitted (at least one command byte) but receiving useful data from target memory device is optional. So, if the scheduled block transfer is only transferring data (and not receiving any data), then this function will exit after transmitting the required bytes. In a given transfer, if there is data to be received from the target memory device, then this function will exit when the expected data is received from the target memory device. -------------------------------- Interrupt driven block transfer -------------------------------- This block transfer can be accomplished using interrupts instead of polling the status register. The Following functions are provided to support interrupt driven block transfers. - MSS_QSPI_irq_transfer_block() - MSS_QSPI_set_status_handler() The MSS_QSPI_set_status_handler() function must be used to set a status handler call-back function with the driver. This function will be called-back by the driver at two different stages of the transfer. At the first stage, it will be called when the required number of bytes are transmitted. At the second stage, if there is data to be received from the target memory device then it will be called again when the desired data is received. Appropriate status value is passed by the driver as a parameter of this call-back function, so that the application can infer the event occurred. ----------- QSPI Status ----------- The MSS_QSPI_read_status() function reads the current status of the MSS QSPI. This function can typically be used to know the status of the ongoing transfer. This function returns the status register value and can be called at any time after the MSS QSPI is initialized and configured. ------------- Direct Access ------------- MSS QSPI allows direct access to the QSPI interface pins to support access to non-standard SPI devices via direct CPU control. This driver provides following functions to read and write the direct access register of the MSS QSPI. - MSS_QSPI_read_direct_access_reg() - MSS_QSPI_write_direct_access_reg() Using these functions, you can generate any sequence of binary transitions on the QSPI pins which might be needed to communicate with non-standard target devices. *//*=========================================================================*/ #ifndef MSS_QSPI_H_ #define MSS_QSPI_H_ 1 #include "mss_plic.h" #include "drivers/mss/mss_qspi/mss_qspi_regs.h" #ifdef __cplusplus extern "C" { #endif /* The following constants can be used as input parameter value to configure the * event on which the SDI pin is sampled as shown below: * qspi_config.sample = MSS_QSPI_SAMPLE_POSAGE_SPICLK; * MSS_QSPI_configure(&qspi_config); * * */ /* The SDI pin is sampled at the rising edge off SPI CLOCK */ #define MSS_QSPI_SAMPLE_POSAGE_SPICLK 0x00u /* The SDI pin is sampled on the last falling HCLK edge in the SPI clock period */ #define MSS_QSPI_SAMPLE_ACTIVE_SPICLK 0x01u /* The SDI pin is sampled at the rising HCLK edge as SPICLK falls */ #define MSS_QSPI_SAMPLE_NEGAGE_SPICLK 0x02u /* Public constant definitions * The following constants can be used to configure the MSS QSPI where a zero * or non-zero value such as enable or disable is to be provided as input * parameter as shown below: * qspi_config.xip = MSS_QSPI_DISABLE; * MSS_QSPI_configure(&qspi_config); * * */ #define MSS_QSPI_ENABLE 0x01u #define MSS_QSPI_DISABLE 0x00u /***************************************************************************//** These values are used to program the io_format parameter of the configuration structure of this driver as shown below: qspi_config.io_format = MSS_QSPI_QUAD_FULL; MSS_QSPI_configure(&qspi_config); | Value | Description | |--------------------|----------------------------------------------------------| |MSS_QSPI_NORMAL | 1 bit Normal SPI operations | | | (single DQ0 TX and single DQ1 RX lines) | | | | |MSS_QSPI_DUAL_EX_RO | 2 bit SPI operations | | | (command and address bytes on DQ0 only. Data on DQ[1:0])| | | | |MSS_QSPI_QUAD_EX_RO | 4 bit SPI operations | | | (command and address bytes on DQ0 only. Data on DQ[3:0])| | | | |MSS_QSPI_DUAL_EX_RW | 2 bit SPI operations | | | (command byte on DQ0 only. Address and Data on DQ[1:0]) | | | | |MSS_QSPI_QUAD_EX_RW | 4 bit SPI operations | | | (command byte on DQ0 only. Address and Data on DQ[3:0]) | | | | |MSS_QSPI_DUAL_FULL | 2 bit SPI operations | | | (command, address and Data on DQ[1:0]) | | | | |MSS_QSPI_QUAD_FULL | 4 bit SPI operations | | | (command, address and Data on DQ[3:0]) | | | | */ typedef enum mss_qspi_io_format_t { MSS_QSPI_NORMAL = 0u, MSS_QSPI_DUAL_EX_RO = 2u, MSS_QSPI_QUAD_EX_RO = 3u, MSS_QSPI_DUAL_EX_RW = 4u, MSS_QSPI_QUAD_EX_RW = 5u, MSS_QSPI_DUAL_FULL = 6u, MSS_QSPI_QUAD_FULL = 7u } mss_qspi_io_format; /***************************************************************************//** These values are used to program the spi_mode parameter of the configuration structure of this driver as shown below: qspi_config.spi_mode = MSS_QSPI_MODE0; MSS_QSPI_configure(&qspi_config); | Value | Description | |-------------------|----------------------------------------------------------| | MSS_QSPI_MODE0 | Set clock IDLE to low (0) | | MSS_QSPI_MODE0 | Set clock IDLE to high (1) | */ typedef enum mss_qspi_protocol_mode_t { MSS_QSPI_MODE0 = 0x0u, MSS_QSPI_MODE3 = 0x1u } mss_qspi_protocol_mode; /***************************************************************************//** These values are used to program the spi_mode parameter of the configuration structure of this driver as shown below: qspi_config.clk_div = MSS_QSPI_CLK_DIV_2; MSS_QSPI_configure(&qspi_config); | Value | Description | |-----------------------|---------------------------| | MSS_QSPI_CLK_DIV_2 | Set SPI clock to HCLK/2 | | MSS_QSPI_CLK_DIV_4 | Set SPI clock to HCLK/4 | | MSS_QSPI_CLK_DIV_6 | Set SPI clock to HCLK/6 | | MSS_QSPI_CLK_DIV_8 | Set SPI clock to HCLK/8 | | MSS_QSPI_CLK_DIV_10 | Set SPI clock to HCLK/10 | | MSS_QSPI_CLK_DIV_12 | Set SPI clock to HCLK/12 | | MSS_QSPI_CLK_DIV_14 | Set SPI clock to HCLK/14 | | MSS_QSPI_CLK_DIV_16 | Set SPI clock to HCLK/16 | | MSS_QSPI_CLK_DIV_18 | Set SPI clock to HCLK/18 | | MSS_QSPI_CLK_DIV_20 | Set SPI clock to HCLK/20 | | MSS_QSPI_CLK_DIV_22 | Set SPI clock to HCLK/22 | | MSS_QSPI_CLK_DIV_24 | Set SPI clock to HCLK/24 | | MSS_QSPI_CLK_DIV_26 | Set SPI clock to HCLK/26 | | MSS_QSPI_CLK_DIV_28 | Set SPI clock to HCLK/28 | | MSS_QSPI_CLK_DIV_30 | Set SPI clock to HCLK/30 | */ typedef enum mss_qspi_clk_div_t { MSS_QSPI_CLK_DIV_2 = 0x1u, MSS_QSPI_CLK_DIV_4 = 0x2u, MSS_QSPI_CLK_DIV_6 = 0x3u, MSS_QSPI_CLK_DIV_8 = 0x4u, MSS_QSPI_CLK_DIV_10 = 0x5u, MSS_QSPI_CLK_DIV_12 = 0x6u, MSS_QSPI_CLK_DIV_14 = 0x7u, MSS_QSPI_CLK_DIV_16 = 0x8u, MSS_QSPI_CLK_DIV_18 = 0x9u, MSS_QSPI_CLK_DIV_20 = 0xAu, MSS_QSPI_CLK_DIV_22 = 0xBu, MSS_QSPI_CLK_DIV_24 = 0xCu, MSS_QSPI_CLK_DIV_26 = 0xDu, MSS_QSPI_CLK_DIV_28 = 0xEu, MSS_QSPI_CLK_DIV_30 = 0xFu } mss_qspi_clk_div; /***************************************************************************//** This prototype defines the function prototype that must be followed by MSS QSPI status handler functions. This function is registered with the MSS QSPI driver through a call to the MSS_QSPI_set_status_handler() function. Declaring and Implementing Status Handler Function: Slave frame receive handler functions should follow the following prototype. void transfer_status_handler(uint32_t status); The actual name of the status handler is unimportant. You can use any name of your choice. The status parameter will contain a value indicating which of the TX-DONE, RX-DONE event has caused the interrupt. */ typedef void (*mss_qspi_status_handler_t)(uint32_t status); /***************************************************************************//** MSS QSPI configuration structure. This is structure definition for MSS QSPI configuration instance. It defines the configuration data to be exchanged by the application with the driver. Configuration options for MSS QSPI | Parameter | Description | |-------------|----------------------------------------------------------------| | xip | Enable or disable XIP mode | | xip_addr | Number of address bytes used in XIP mode | | spi_mode | Select either Motorola mode0 or mode3 | | clk_div | HCLK Clock divider for generating SPI clock | | io_format | QSPI transfer format, extended,dual,quad etc. | | sample | Select the event on which the QSPI samples the incoming data | */ typedef struct mss_qspi_config{ uint8_t xip; uint8_t xip_addr; mss_qspi_protocol_mode spi_mode; /*clkidl mode0 or mode3*/ mss_qspi_clk_div clk_div; mss_qspi_io_format io_format; uint8_t sample; }mss_qspi_config_t; /*----------------------------------------------------------------------------*/ /*------------------------MSS QSPI internal structures ---------------------*/ /*----------------------------------------------------------------------------*/ /*Register map of the PolarFire SoC MSS QSPI*/ typedef struct { volatile uint32_t CONTROL; volatile uint32_t FRAMES; volatile uint32_t RESERVED1; volatile uint32_t INTENABLE; volatile uint32_t STATUS; volatile uint32_t DIRECT; volatile uint8_t ADDRUP; volatile uint8_t ADDRUP_R1; volatile uint8_t ADDRUP_R2; volatile uint8_t ADDRUP_R3; volatile uint32_t RESERVED2[9]; volatile uint8_t RXDATAX1; volatile uint8_t RXDATAX1_R1; volatile uint8_t RXDATAX1_R2; volatile uint8_t RXDATAX1_R3; volatile uint8_t TXDATAX1; volatile uint8_t TXDATAX1_R1; volatile uint8_t TXDATAX1_R2; volatile uint8_t TXDATAX1_R3; volatile uint32_t RXDATAX4; volatile uint32_t TXDATAX4; volatile uint32_t FRAMESUP; } QSPI_TypeDef; /*PolarFire SoC MSS QSPI base memory address*/ #define QSPI_BASE 0x21000000u /*PolarFire SoC MSS QSPI hardware instance*/ #define QSPI ((QSPI_TypeDef *) QSPI_BASE) /*----------------------------------------------------------------------------*/ /*------------------------MSS QSPI Public APIs--------------------------------*/ /*----------------------------------------------------------------------------*/ /***************************************************************************//** The MSS_QSPI_init() function initializes and enables the PolarFireSoC MSS QSPI. It enables the MSS QSPI hardware block, and configures it with the default values. @param This function takes no function parameters. @return This function does not return a value. Example: @code @endcode */ void MSS_QSPI_init(void); /***************************************************************************//** The MSS_QSPI_enable() function enables the MSS QSPI hardware block. @param This function takes no function parameters. @return This function does not return a value. Example: @code @endcode */ static inline void MSS_QSPI_enable(void) { QSPI->CONTROL |= CTRL_EN_MASK; } /***************************************************************************//** The MSS_QSPI_disable() function disables the MSS QSPI hardware block. @param This function takes no function parameters. @return This function does not return a value. Example: @code @endcode */ static inline void MSS_QSPI_disable(void) { QSPI->CONTROL &= ~CTRL_EN_MASK; } /***************************************************************************//** The MSS_QSPI_configure() function configures the MSS QSPI to desired configuration values. @param config The config parameter is a pointer to the mss_qspi_config_t structure, which provides new configuration values. See the mss_qspi_config_t section for details. @return This function does not return a value. Example: @code @endcode */ void MSS_QSPI_configure(const mss_qspi_config_t* config); /***************************************************************************//** The MSS_QSPI_get_config() function reads-back the current configurations of the MSS QSPI. This function can be used when you want to read the current configurations, modify the configuration values of your choice and reconfigure the MSS QSPI hardware, using MSS_QSPI_configure() function. @param config The config parameter is a pointer to an mss_qspi_config_t structure in which the current configuration values of the MSS QSPI are returned. Please see description of mss_qspi_config_t for more details. @return This function does not return a value. Example: @code @endcode */ void MSS_QSPI_get_config(mss_qspi_config_t* config); /***************************************************************************//** The MSS_QSPI_polled_transfer_block() function is used to carry out a QSPI transfer with the target memory device using polling method of data transfer. The QSPI transfer characteristics are configured every time a new transfer is initiated. This is a blocking function. @param num_addr_bytes The num_addr_bytes parameter indicates the number of address bytes to be used while transacting with the target memory device. Depending on the target memory device, the address within the target memory device can be either 3 or 4 bytes long. You must make sure that you provide the exact same number with which the target memory device is configured. Note: Few command opcodes do not require specified addresses. For example READ_ID. For such commands the num_addr_bytes parameter must be set to 0x0. @param tx_buffer The tx_buffer parameter is the pointer to the buffer from which the data needs to transmitted to the target memory device. @param tx_byte_size The tx_byte_size parameter is the exact number of bytes that needs to be transmitted to the target memory device. Note: This parameter must not consider the command opcode and address bytes as part of the data that needs to be transmitted. @param rd_buffer The rd_buffer parameter is the pointer to the buffer where the data returned by the target memory device is to be stored. @param rd_byte_size The rd_byte_size parameter is the exact number of bytes that needs to be received from the target memory device. @param num_idle_cycles The num_idle_cycles parameter indicates the number of Idle cycles/dummy clock edges that must be generated after the address bytes are transmitted and before target memory device starts sending data. This must be correctly set based on the target memory device and the SPI command being used - this may also vary based on SPI clock and the way the target memory device is configured. @return This function does not return a value. Example: @code @endcode */ void MSS_QSPI_polled_transfer_block(uint8_t num_addr_bytes, const void * const tx_buffer, uint32_t tx_byte_size, const void * const rd_buffer, uint32_t rd_byte_size, uint8_t num_idle_cycles); /***************************************************************************//** The MSS_QSPI_irq_transfer_block() function is used to carry out a QSPI transfer with the target memory device using interrupt method of data transfers. The QSPI transfer characteristics are configured every time a new transfer is initiated. This is non-blocking function. You must configure the interrupt handler function, before calling this function.It will enable the interrupts and start transmitting as many bytes as requested. You will get an indication when the actual SPI transmit operation is complete when The transmit-done interrupt event occurs and this driver calls-back the interrupt handler function that you previously provided. If the transfer includes receiving data from the target memory device then the receive-available and receive-done interrupts are also enabled by this function. The data will be received in the interrupt routine. The interrupt handler provided by you will be called-back again when the receive-done interrupt event occurs. @param num_addr_bytes The num_addr_bytes parameter indicates the number of address bytes to be used while transacting with the target memory device. Depending on the the target memory device, the address within the target memory device can be either 3 or 4 bytes long. You must make sure that you provide the exact same number with which the target memory device is configured. Note: There will be some command opcodes for which no address needs to be specified. e.g. READ_ID. For such commands the num_addr_bytes parameter must be set to 0x0. @param target_mem_addr The target_mem_addr parameter is the memory address in the target memory device on which the read/write operation is to be carried out. @param tx_buffer The tx_buffer parameter is the pointer to the buffer from which the data needs to transmitted to the target QSPI memory. @param tx_byte_size The tx_byte_size parameter is the exact number of bytes that needs to be transmitted to target memory device. Note: This parameter must not consider the command opcode and address bytes as part of the data that needs to be transmitted. @param rd_buffer The rd_buffer parameter is the pointer to the buffer where the data returned by the target memory device is to be stored. @param rd_byte_size The rd_byte_size parameter is the exact number of bytes that needs to be received from the target memory device. @param num_idle_cycles The num_idle_cycles parameter indicates the The number of IDLE/dummy clock edges that must be generated after the address bytes are transmitted and before target memory device starts sending data. This must be correctly set based on the target memory device and the SPI command being used - this may also vary based on SPI clock and the way the target memory device is configured. @return This function a non-zero value if the MSS QSPI is busy completing the previous transfer and can not accept a new transfer. A zero return value indicates successful execution of this function. Example: @code @endcode */ uint8_t MSS_QSPI_irq_transfer_block(uint8_t num_addr_bytes, const void * const tx_buffer, uint32_t tx_byte_size, const void * const rd_buffer, uint32_t rd_byte_size, uint8_t num_idle_cycles); /***************************************************************************//** The MSS_QSPI_set_status_handler() function registers an interrupt handler function with this driver which is used to indicate the interrupt status back to the application. This status handler function is called by this driver in two events. First, when the transmission of required bytes is completed (Transmit-Done). Second, if data is to be received from the target memory device then this function is called again when required data is received (Receive-Done). @param handler The handler parameter is the interrupt handler function of the type mss_qspi_status_handler_t which needs to be registered. @return This function does not return a value. Example: @code @endcode */ void MSS_QSPI_set_status_handler(mss_qspi_status_handler_t handler); /***************************************************************************//** The MSS_QSPI_read_direct_access_reg() reads the current value of the direct access register(DAR) of the MSS QSPI. DAR allows direct access to the QSPI interface pins to support access to non-standard SPI devices through direct CPU control. @param This function takes no function parameters. @return This function returns the current value of the DAR of the MSS QSPI. Example: @code @endcode */ static inline uint32_t MSS_QSPI_read_direct_access_reg(void) { return(QSPI->DIRECT); } /***************************************************************************//** The MSS_QSPI_write_direct_access_reg() to write a value of the DAR of the MSS QSPI. DAR allows direct access to the QSPI interface pins, to support access to non-standard SPI devices through direct CPU control. @param value The value parameter is the value that needs to be set into the direct access register of the MSS QSPI. @return This function does not return a value. Example: @code @endcode */ static inline void MSS_QSPI_write_direct_access_reg(uint32_t value) { QSPI->DIRECT = value; } /***************************************************************************//** The function MSS_QSPI_read_status() is used to read the status of the MSS QSPI. This function returns the status register value and can be called any time after the MSS QSPI is initialized and configured. @param This function takes no function parameters. @return This function returns the the current value of the status register of the MSS QSPI. Example: @code @endcode */ static inline uint32_t MSS_QSPI_read_status(void) { return(QSPI->STATUS); } #ifdef __cplusplus } #endif #endif /* MSS_QSPI_H_*/ mss_qspi_regs.h000066400000000000000000000142371432224323300401470ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_qspi /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC(MPFS) MSS QSPI. * * */ #ifndef MSS_QSPI_REGS_H_ #define MSS_QSPI_REGS_H_ #ifdef __cplusplus extern "C" { #endif /******************************************************************************* Register Bit definitions */ #define CTRL_EN 0u #define CTRL_XIP 2u #define CTRL_XIPADDR 3u #define CTRL_CLKIDL 10u #define CTRL_SAMPLE 11u #define CTRL_QMODE0 13u #define CTRL_QMODE12 14u #define CTRL_FLAGSX4 16u #define CTRL_CLKRATE 24u #define CTRL_EN_MASK (0x1u << CTRL_EN) #define CTRL_XIP_MASK (0x1u << CTRL_XIP) #define CTRL_XIPADDR_MASK (0x1u << CTRL_XIPADDR) #define CTRL_CLKIDL_MASK (0x1u << CTRL_CLKIDL) #define CTRL_SAMPLE_MASK (0x3u << CTRL_SAMPLE) #define CTRL_QMODE0_MASK (0x1u << CTRL_QMODE0) #define CTRL_QMODE12_MASK (0x3u << CTRL_QMODE12) #define CTRL_FLAGSX4_MASK (0x1u << CTRL_FLAGSX4) #define CTRL_CLKRATE_MASK (0xFu << CTRL_CLKRATE) #define CTRL_SAMPLE_SCK (0x0u << CTRL_SAMPLE) #define CTRL_SAMPLE_HCLKF (0x1u << CTRL_SAMPLE) #define CTRL_SAMPLE_HCLKR (0x2u << CTRL_SAMPLE) #define FRMS_TBYTES 0u #define FRMS_CBYTES 16u #define FRMS_QSPI 25u #define FRMS_IDLE 26u #define FRMS_FBYTE 30u #define FRMS_FWORD 31u #define FRMS_TBYTES_MASK (0xFFFFu << FRMS_TBYTES) #define FRMS_CBYTES_MASK (0x1FFu << FRMS_CBYTES) #define FRMS_QXIP_MASK (0x1u << FRMS_QXIP) #define FRMS_IDLE_MASK (0xFu << FRMS_IDLE) #define FRMS_FBYTE_MASK (0x1u << FRMS_FBYTE) #define FRMS_FWORD_MASK (0x1u << FRMS_FWORD) #define INTE_TDONE 0u #define INTE_RDONE 1u #define INTE_RAVLB 2u #define INTE_TAVLB 3u #define INTE_RFEMPTY 4u #define INTE_TFFULL 5u #define INTE_TDONE_MASK (0x1u << INTE_TDONE) #define INTE_RDONE_MASK (0x1u << INTE_RDONE) #define INTE_RAVLB_MASK (0x1u << INTE_RAVLB) #define INTE_TAVLB_MASK (0x1u << INTE_TAVLB) #define INTE_RFEMPTY_MASK (0x1u << INTE_RFEMPTY) #define INTE_TFFULL_MASK (0x1u << INTE_TFFULL) #define STTS_TDONE 0u #define STTS_RDONE 1u #define STTS_RAVLB 2u #define STTS_TAVLB 3u #define STTS_RFEMPTY 4u #define STTS_TFFULL 5u #define STTS_READY 7u #define STTS_FLAGSX4 8u #define STTS_TDONE_MASK (0x1u << STTS_TDONE) #define STTS_RDONE_MASK (0x1u << STTS_RDONE) #define STTS_RAVLB_MASK (0x1u << STTS_RAVLB) #define STTS_TAVLB_MASK (0x1u << STTS_TAVLB) #define STTS_RFEMPTY_MASK (0x1u << STTS_RFEMPTY) #define STTS_TFFULL_MASK (0x1u << STTS_TFFULL) #define STTS_READY_MASK (0x1u << STTS_READY) #define STTS_FLAGSX4_MASK (0x1u << STTS_FLAGSX4) #define RDAT 0u #define RDAT_MASK 0xFFu #define TDAT 0u #define TDAT_MASK 0xFFu #define X4RDAT 0u #define X4RDAT_MASK 0xFFFFFFFFu #define X4TDAT 0u #define X4TDAT_MASK 0xFFFFFFFFu #define DIRECT_EN_SSEL 0u #define DIRECT_OP_SSEL 1u #define DIRECT_EN_SCLK 2u #define DIRECT_OP_SCLK 3u #define DIRECT_EN_SDO 4u #define DIRECT_OP_SDO 8u #define DIRECT_OP_SDOE 12u #define DIRECT_IP_SDI 16u #define DIRECT_Reserved 20u #define DIRECT_IP_SCLK 21u #define DIRECT_IP_SSEL 22u #define DIRECT_IDLE 23u #define DIRECT_EN_SSEL_MASK (0x1u << DIRECT_EN_SSEL) #define DIRECT_OP_SSEL_MASK (0x1u << DIRECT_OP_SSEL) #define DIRECT_EN_SCLK_MASK (0x1u << DIRECT_EN_SCLK) #define DIRECT_OP_SCLK_MASK (0x1u << DIRECT_OP_SCLK) #define DIRECT_EN_SDO_MASK (0xFu << DIRECT_EN_SDO) #define DIRECT_OP_SDO_MASK (0xFu << DIRECT_OP_SDO) #define DIRECT_OP_SDOE_MASK (0xFu << DIRECT_OP_SDOE) #define DIRECT_IP_SDI_MASK (0xFu << DIRECT_IP_SDI) #define DIRECT_Reserved_MASK (0x1u << DIRECT_Reserved) #define DIRECT_IP_SCLK_MASK (0x1u << DIRECT_IP_SCLK) #define DIRECT_IP_SSEL_MASK (0x1u << DIRECT_IP_SSEL) #define DIRECT_IDLE_MASK (0x1u << DIRECT_IDLE) #define UADDAR 0u #define UADDAR_MASK 0xFFu #ifdef __cplusplus } #endif #endif /* MSS_QSPI_REGS_H_ */ mss_rtc/000077500000000000000000000000001432224323300347255ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_rtc.c000066400000000000000000000505201432224323300365450ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_rtc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PoalrFire SoC Microprocessor Subsystem RTC bare metal driver implementation. * * SVN $Revision$ * SVN $Date$ */ #include #include "mss_rtc.h" #include "mss_rtc_regs.h" #include "mss_hal.h" #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** * CONTROL_REG register masks. */ #define CONTROL_RUNNING_MASK 0x00000001u #define CONTROL_RTC_START_MASK 0x00000001u #define CONTROL_RTC_STOP_MASK 0x00000002u #define CONTROL_ALARM_ON_MASK 0x00000004u #define CONTROL_ALARM_OFF_MASK 0x00000008u #define CONTROL_RESET_MASK 0x00000010u #define CONTROL_UPLOAD_MASK 0x00000020u #define CONTROL_WAKEUP_CLR_MASK 0x00000100u #define CONTROL_UPDATED_MASK 0x00000400u /*-------------------------------------------------------------------------*//** * MODE_REG register masks. */ #define MODE_CLK_MODE_MASK 0x00000001u #define MODE_WAKEUP_EN_MASK 0x00000002u #define MODE_WAKEUP_RESET_MASK 0x00000004u #define MODE_WAKEUP_CONTINUE_MASK 0x00000008u /*-------------------------------------------------------------------------*//** * Other masks. */ #define MAX_BINARY_HIGHER_COUNT 0x7FFu #define MASK_32_BIT 0xFFFFFFFFu #define MAX_PRESCALAR_COUNT 0x03FFFFFFu #define CALENDAR_SHIFT 8u /*-------------------------------------------------------------------------*//** * Index into look-up table. */ #define SECONDS 0 #define MINUTES 1 #define HOURS 2 #define DAYS 3 #define MONTHS 4 #define YEARS 5 #define WEEKDAYS 6 #define WEEKS 7 /*-------------------------------------------------------------------------*//** * A pointer to the RTC_TypeDef structure is used to configure the user selected * RTC. This pointer is used by all the mss RTC driver function to carry out the * required functionality. */ RTC_TypeDef * mss_rtc; static uint8_t get_clock_mode ( void ); static void set_rtc_mode ( uint8_t requested_mode ); static void add_alarm_cfg_values ( uint8_t calendar_item, uint32_t * p_calendar_value, uint32_t * p_compare_mask ); /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_init ( RTC_TypeDef *base_address, uint8_t mode, uint32_t prescaler ) { ASSERT(prescaler <= MAX_PRESCALAR_COUNT); /* Assigning the user selected MSS RTC base address to global RTC structure * pointer so that the other driver functions can use it. */ mss_rtc = base_address; if (prescaler <= MAX_PRESCALAR_COUNT) { /* Stop the RTC. */ MSS_RTC_stop(); /* Disable alarm. */ mss_rtc->CONTROL_REG = CONTROL_ALARM_OFF_MASK; /* Disable Interrupt */ MSS_RTC_disable_irq(); /* Clear RTC wake up interrupt signal */ MSS_RTC_clear_irq(); /* Select mode of operation, including the wake configuration. */ if (MSS_RTC_CALENDAR_MODE == mode) { mss_rtc->MODE_REG = MODE_CLK_MODE_MASK; } else { mss_rtc->MODE_REG = 0u; } /* Reset the alarm and compare registers to a known value. */ mss_rtc->ALARM_LOWER_REG = 0u; mss_rtc->ALARM_UPPER_REG = 0u; mss_rtc->COMPARE_LOWER_REG = 0u; mss_rtc->COMPARE_UPPER_REG = 0u; /* Reset the calendar counters */ MSS_RTC_reset_counter(); /* Set new Prescaler value */ mss_rtc->PRESCALER_REG = prescaler; } } /*-------------------------------------------------------------------------*//** See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_set_calendar_count ( const mss_rtc_calender_t *new_rtc_value ) { uint8_t error = 0u; uint8_t clock_mode; const uint8_t g_rtc_max_count_lut[] = { /* Calendar mode */ 59u, /* Seconds */ 59u, /* Minutes */ 23u, /* Hours */ 31u, /* Days */ 12u, /* Months */ 254u, /* Years */ 7u, /* Weekdays*/ 52u /* Week */ }; const uint8_t g_rtc_min_count_lut[] = { /* Calendar mode */ 0u, /* Seconds */ 0u, /* Minutes */ 0u, /* Hours */ 1u, /* Days */ 1u, /* Months */ 0u, /* Years */ 1u, /* Weekdays*/ 1u /* Week */ }; /* Assert if the values cross the limit */ ASSERT(new_rtc_value->second >= g_rtc_min_count_lut[SECONDS]); ASSERT(new_rtc_value->second <= g_rtc_max_count_lut[SECONDS]); ASSERT(new_rtc_value->minute >= g_rtc_min_count_lut[MINUTES]); ASSERT(new_rtc_value->minute <= g_rtc_max_count_lut[MINUTES]); ASSERT(new_rtc_value->hour >= g_rtc_min_count_lut[HOURS]); ASSERT(new_rtc_value->hour <= g_rtc_max_count_lut[HOURS]); ASSERT(new_rtc_value->day >= g_rtc_min_count_lut[DAYS]); ASSERT(new_rtc_value->day <= g_rtc_max_count_lut[DAYS]); ASSERT(new_rtc_value->month >= g_rtc_min_count_lut[MONTHS]); ASSERT(new_rtc_value->month <= g_rtc_max_count_lut[MONTHS]); ASSERT(new_rtc_value->year >= g_rtc_min_count_lut[YEARS]); ASSERT(new_rtc_value->year <= g_rtc_max_count_lut[YEARS]); ASSERT(new_rtc_value->weekday >= g_rtc_min_count_lut[WEEKDAYS]); ASSERT(new_rtc_value->weekday <= g_rtc_max_count_lut[WEEKDAYS]); ASSERT(new_rtc_value->week >= g_rtc_min_count_lut[WEEKS]); ASSERT(new_rtc_value->week <= g_rtc_max_count_lut[WEEKS]); if (new_rtc_value->second < g_rtc_min_count_lut[SECONDS]) {error = 1u;} if (new_rtc_value->second > g_rtc_max_count_lut[SECONDS]) {error = 1u;} if (new_rtc_value->minute < g_rtc_min_count_lut[MINUTES]) {error = 1u;} if (new_rtc_value->minute > g_rtc_max_count_lut[MINUTES]) {error = 1u;} if (new_rtc_value->hour < g_rtc_min_count_lut[HOURS]) {error = 1u;} if (new_rtc_value->hour > g_rtc_max_count_lut[HOURS]) {error = 1u;} if (new_rtc_value->day < g_rtc_min_count_lut[DAYS]) {error = 1u;} if (new_rtc_value->day > g_rtc_max_count_lut[DAYS]) {error = 1u;} if (new_rtc_value->month < g_rtc_min_count_lut[MONTHS]) {error = 1u;} if (new_rtc_value->month > g_rtc_max_count_lut[MONTHS]) {error = 1u;} if (new_rtc_value->year < g_rtc_min_count_lut[YEARS]) {error = 1u;} if (new_rtc_value->year > g_rtc_max_count_lut[YEARS]) {error = 1u;} if (new_rtc_value->weekday < g_rtc_min_count_lut[WEEKDAYS]) {error = 1u;} if (new_rtc_value->weekday > g_rtc_max_count_lut[WEEKDAYS]) {error = 1u;} if (new_rtc_value->week < g_rtc_min_count_lut[WEEKS]) {error = 1u;} if (new_rtc_value->week > g_rtc_max_count_lut[WEEKS]) {error = 1u;} /* * This function can only be used when the RTC is configured to operate in * calendar counter mode. */ clock_mode = get_clock_mode(); ASSERT(MSS_RTC_CALENDAR_MODE == clock_mode); if ((0u == error) && (MSS_RTC_CALENDAR_MODE == clock_mode)) { uint32_t upload_in_progress; /* Write the RTC new value. */ mss_rtc->SECONDS_REG = new_rtc_value->second; mss_rtc->MINUTES_REG = new_rtc_value->minute; mss_rtc->HOURS_REG = new_rtc_value->hour; mss_rtc->DAY_REG = new_rtc_value->day; mss_rtc->MONTH_REG = new_rtc_value->month; mss_rtc->YEAR_REG = new_rtc_value->year; mss_rtc->WEEKDAY_REG = new_rtc_value->weekday; mss_rtc->WEEK_REG = new_rtc_value->week; /* Data is copied, now issue upload command */ mss_rtc->CONTROL_REG = CONTROL_UPLOAD_MASK ; /* Wait for the upload to complete. */ do { upload_in_progress = mss_rtc->CONTROL_REG & CONTROL_UPLOAD_MASK; } while (upload_in_progress); } } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_set_binary_count ( uint64_t new_rtc_value ) { uint8_t clock_mode; /* * This function can only be used when the RTC is configured to operate in * binary counter mode. */ clock_mode = get_clock_mode(); ASSERT(MSS_RTC_BINARY_MODE == clock_mode); if (MSS_RTC_BINARY_MODE == clock_mode) { uint32_t rtc_upper_32_bit_value; rtc_upper_32_bit_value = (uint32_t)(new_rtc_value >> 32u) & MASK_32_BIT; /* Assert if the values cross the limit */ ASSERT(rtc_upper_32_bit_value <= MAX_BINARY_HIGHER_COUNT); if (rtc_upper_32_bit_value <= MAX_BINARY_HIGHER_COUNT) { uint32_t upload_in_progress; /* * Write the RTC new value. */ mss_rtc->DATE_TIME_LOWER_REG = (uint32_t)new_rtc_value; mss_rtc->DATE_TIME_UPPER_REG = (uint32_t)(( new_rtc_value >> 32u) & MAX_BINARY_HIGHER_COUNT); /* Data is copied, now issue upload command */ mss_rtc->CONTROL_REG = CONTROL_UPLOAD_MASK; /* Wait for the upload to complete. */ do { upload_in_progress = mss_rtc->CONTROL_REG & CONTROL_UPLOAD_MASK; } while (upload_in_progress); } } } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_get_calendar_count ( mss_rtc_calender_t *p_rtc_calendar ) { uint8_t clock_mode; /* * This function can only be used when the RTC is configured to operate in * calendar counter mode. */ clock_mode = get_clock_mode(); ASSERT(MSS_RTC_CALENDAR_MODE == clock_mode); if (MSS_RTC_CALENDAR_MODE == clock_mode) { p_rtc_calendar->second = (uint8_t)mss_rtc->SECONDS_REG; p_rtc_calendar->minute = (uint8_t)mss_rtc->MINUTES_REG; p_rtc_calendar->hour = (uint8_t)mss_rtc->HOURS_REG; p_rtc_calendar->day = (uint8_t)mss_rtc->DAY_REG; p_rtc_calendar->month = (uint8_t)mss_rtc->MONTH_REG; p_rtc_calendar->year = (uint8_t)mss_rtc->YEAR_REG; p_rtc_calendar->weekday = (uint8_t)mss_rtc->WEEKDAY_REG; p_rtc_calendar->week = (uint8_t)mss_rtc->WEEK_REG; } else { /* * Set returned calendar count to zero if the RTC is not configured for * calendar counter mode. This should make incorrect release application * code behave consistently and help application debugging. */ memset(p_rtc_calendar, 0, sizeof(mss_rtc_calender_t)); } } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ uint64_t MSS_RTC_get_binary_count ( void ) { uint64_t rtc_count; uint8_t clock_mode; /* * This function can only be used when the RTC is configured to operate in * binary counter mode. */ clock_mode = get_clock_mode(); ASSERT(MSS_RTC_BINARY_MODE == clock_mode); if (MSS_RTC_BINARY_MODE == clock_mode) { rtc_count = mss_rtc->DATE_TIME_LOWER_REG; rtc_count = rtc_count | ((uint64_t)mss_rtc->DATE_TIME_UPPER_REG << 32u) ; } else { /* * Set returned binary count to zero if the RTC is not configured for * binary counter mode. This should make incorrect release application * code behave consistently and help application debugging. */ rtc_count = 0u; } return rtc_count; } /*-------------------------------------------------------------------------*//** * */ static void add_alarm_cfg_values ( uint8_t calendar_item, uint32_t * p_calendar_value, uint32_t * p_compare_mask ) { if (MSS_RTC_CALENDAR_DONT_CARE == calendar_item) { *p_calendar_value = (uint32_t)(*p_calendar_value << CALENDAR_SHIFT); *p_compare_mask = (uint32_t)(*p_compare_mask << CALENDAR_SHIFT); } else { *p_calendar_value = (uint32_t)((*p_calendar_value << CALENDAR_SHIFT) | (uint32_t)calendar_item); *p_compare_mask = (uint32_t)((*p_compare_mask << CALENDAR_SHIFT) | (uint32_t)0xFFu); } } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_set_calendar_count_alarm ( const mss_rtc_calender_t * alarm_value ) { uint32_t calendar_value; uint32_t compare_mask; uint8_t mode; mode = (uint8_t)(mss_rtc->MODE_REG & MODE_CLK_MODE_MASK); /* * This function can only be used with the RTC set to operate in calendar * mode. */ ASSERT(MSS_RTC_CALENDAR_MODE == mode); if (MSS_RTC_CALENDAR_MODE == mode) { uint8_t required_mode_reg; /* Disable the alarm before updating*/ mss_rtc->CONTROL_REG = CONTROL_ALARM_OFF_MASK; /* Set alarm and compare lower registers. */ calendar_value = 0u; compare_mask = 0u; add_alarm_cfg_values(alarm_value->day, &calendar_value, &compare_mask); add_alarm_cfg_values(alarm_value->hour, &calendar_value, &compare_mask); add_alarm_cfg_values(alarm_value->minute, &calendar_value, &compare_mask); add_alarm_cfg_values(alarm_value->second, &calendar_value, &compare_mask); mss_rtc->ALARM_LOWER_REG = calendar_value; mss_rtc->COMPARE_LOWER_REG = compare_mask; /* Set alarm and compare upper registers. */ calendar_value = 0u; compare_mask = 0u; add_alarm_cfg_values(alarm_value->week, &calendar_value, &compare_mask); add_alarm_cfg_values(alarm_value->weekday, &calendar_value, &compare_mask); add_alarm_cfg_values(alarm_value->year, &calendar_value, &compare_mask); add_alarm_cfg_values(alarm_value->month, &calendar_value, &compare_mask); mss_rtc->ALARM_UPPER_REG = calendar_value; mss_rtc->COMPARE_UPPER_REG = compare_mask; /* Configure the RTC to enable the alarm. */ required_mode_reg = mode | MODE_WAKEUP_EN_MASK | MODE_WAKEUP_CONTINUE_MASK; set_rtc_mode(required_mode_reg); /* Enable the alarm */ mss_rtc->CONTROL_REG = CONTROL_ALARM_ON_MASK ; } } /*-------------------------------------------------------------------------*//** We only write the RTC mode register if really required because the RTC needs to be stopped for the mode register to be written. Stopping the RTC every time the wakeup alarm configuration is set might induce drift on the RTC time. This function is intended to be used when setting alarms. */ static void set_rtc_mode ( uint8_t requested_mode ) { if (mss_rtc->MODE_REG != requested_mode) { uint32_t rtc_running; rtc_running = mss_rtc->CONTROL_REG & CONTROL_RUNNING_MASK; if (rtc_running) { /* Stop the RTC in order to change the mode register content.*/ MSS_RTC_stop(); mss_rtc->MODE_REG = requested_mode; MSS_RTC_start(); } else { mss_rtc->MODE_REG = requested_mode; } } } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_set_binary_count_alarm ( uint64_t alarm_value, mss_rtc_alarm_type_t alarm_type ) { uint8_t mode; mode = (uint8_t)(mss_rtc->MODE_REG & MODE_CLK_MODE_MASK); /* * This function can only be used with the RTC set to operate in binary * counter mode. */ ASSERT(MSS_RTC_BINARY_MODE == mode); if (MSS_RTC_BINARY_MODE == mode) { uint8_t required_mode_reg; /* Disable the alarm before updating*/ mss_rtc->CONTROL_REG = CONTROL_ALARM_OFF_MASK; /* Set the alarm value. */ mss_rtc->COMPARE_LOWER_REG = COMPARE_ALL_BITS; mss_rtc->COMPARE_UPPER_REG = COMPARE_ALL_BITS; mss_rtc->ALARM_LOWER_REG = (uint32_t)alarm_value; mss_rtc->ALARM_UPPER_REG = (uint32_t)(alarm_value >> 32u); /* * Configure the RTC to enable the alarm. */ required_mode_reg = mode | MODE_WAKEUP_EN_MASK | MODE_WAKEUP_CONTINUE_MASK; if (MSS_RTC_PERIODIC_ALARM == alarm_type) { /* * The RTC binary counter will be fully reset when the alarm occurs. * The counter will continue counting while the wake-up interrupt is * active. */ required_mode_reg |= MODE_WAKEUP_RESET_MASK; } set_rtc_mode(required_mode_reg); /* Enable the alarm */ mss_rtc->CONTROL_REG = CONTROL_ALARM_ON_MASK; uint8_t test = get_clock_mode(); } } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_start ( void ) { mss_rtc->CONTROL_REG = CONTROL_RTC_START_MASK; } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_stop ( void ) { uint32_t rtc_running; /* * Send command to stop RTC. */ mss_rtc->CONTROL_REG = CONTROL_RTC_STOP_MASK; /* * Wait for RTC internal synchronization to take place and RTC to actually * stop. */ do { rtc_running = mss_rtc->CONTROL_REG & CONTROL_RUNNING_MASK; } while(rtc_running); } /*-------------------------------------------------------------------------*//** See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_reset_counter ( void ) { uint32_t upload_in_progress; mss_rtc->CONTROL_REG = CONTROL_RESET_MASK; /* Wait for the upload to complete. */ do { upload_in_progress = mss_rtc->CONTROL_REG & CONTROL_UPLOAD_MASK; } while (upload_in_progress); } /*-------------------------------------------------------------------------*//** See "mss_rtc.h" for details of how to use this function. */ uint32_t MSS_RTC_get_update_flag ( void ) { uint32_t updated; updated = mss_rtc->CONTROL_REG & CONTROL_UPDATED_MASK; return updated; } /*-------------------------------------------------------------------------*//** See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_clear_update_flag ( void ) { /* Clear the "updated" control bit. */ mss_rtc->CONTROL_REG = CONTROL_UPDATED_MASK; } /*-------------------------------------------------------------------------*//** See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_enable_irq ( void ) { /* * Only the PLIC level interrupt enable is performed within this function. * The RTC level interrupt enable is performed within the alarm setting * functions. * This avoid the MODE register being modified whenever RTC * interrupts are enabled/disabled. */ PLIC_EnableIRQ(RTC_WAKEUP_PLIC); } /*-------------------------------------------------------------------------*//** See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_disable_irq ( void ) { /* * Only the PLIC level interrupt disable is performed within this function. * This avoid the MODE register being modified whenever RTC * interrupts are enabled/disabled. */ PLIC_DisableIRQ(RTC_WAKEUP_PLIC); } /*-------------------------------------------------------------------------*//** * See "mss_rtc.h" for details of how to use this function. */ void MSS_RTC_clear_irq ( void ) { volatile uint32_t dummy_read; /* Clear wake up interrupt signal */ mss_rtc->CONTROL_REG = CONTROL_WAKEUP_CLR_MASK; /* * Ensure that the posted write to the CONTROL_REG register completed before * returning from this function. Not doing this may result in the interrupt * only being cleared some time after this function returns. */ dummy_read = mss_rtc->CONTROL_REG; /* Dummy operation to avoid warning message */ ++dummy_read; } /*-------------------------------------------------------------------------*//** The get_clock_mode() function gets the clock mode of RTC hardware. Possible clock modes are: MSS_RTC_CALENDAR_MODE MSS_RTC_BINARY_MODE */ static uint8_t get_clock_mode ( void ) { uint8_t clock_mode; clock_mode = (uint8_t)(mss_rtc->MODE_REG & MODE_CLK_MODE_MASK); return(clock_mode); } #ifdef __cplusplus } #endif mss_rtc.h000066400000000000000000001017211432224323300365520ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_rtc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC Microprocessor subsystem RTC bare metal software driver public * APIs. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire MSS RTC Bare Metal Driver. ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor Subsystem (MSS) includes a real time counter (RTC) that can generate alarms and wakeup functions in real time. The RTC core also provides the feature of real time clock. This software driver provides a set of functions for controlling the MSS RTC as part of a bare metal system where no operating system is available. The driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of the driver. The MSS RTC driver provides support for the following features: - Initialization of the RTC - Configuration of the RTC time-base - Configuration as a calendar or binary mode counter - Set the current calendar or binary mode count - Get the current calendar or binary mode count - Start and stop the RTC counting - Set alarm conditions - Enable, disable and clear the wakeup interrupt ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all features of the MSS RTC driver is covered by this driver except for the clock source driving the MSS RTC clock(RTCCLK) input. The PolarFire SoC MSS clock controller supplies single clock source of 1 MHz to the MSS RTC clock input. On PolarFire SoC an AXI switch forms a bus matrix interconnect among multiple masters and multiple slaves. Five RISC-V CPUs connect to the Master ports M10 to M14 of the AXI switch. By default, all the APB peripherals are accessible on AXI-Slave 5 of the AXI switch via the AXI to AHB and AHB to APB bridges (referred as main APB bus). However, to support logical separation in the Asymmetric Multi-Processing (AMP) mode of operation, the APB peripherals can alternatively be accessed on the AXI-Slave 6 via the AXI to AHB and AHB to APB bridges (referred as the AMP APB bus). Application must make sure that the RTC is appropriately configured on one of the APB bus described above by configuring the PolarFire SoC system registers (SYSREG) as per the application need and that the appropriate data structures are provided to this driver as parameter to the functions provided by this driver. The base address and register addresses and interrupt number assignment for the MSS RTC block are defined as constants in the PolarFire SoC MPFS HAL. You must ensure that the latest PolarFire SoC MPFS HAL is included in the project settings of the software tool chain used to build your project and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The MSS RTC driver functions are grouped into the following categories: - Initialization of the RTC driver and hardware - Setting and reading the RTC counter current value - Setting RTC alarm values - Starting and stopping the RTC - Interrupt Control -------------------------------- Initialization of the RTC driver and hardware -------------------------------- The MSS RTC driver is initialized through a call to the MSS_RTC_init() function. The MSS_RTC_init() function must be called before any other MSS RTC driver functions are called. The MSS_RTC_init() function: * Stops the RTC counters and disables the RTC alarm * Disables the RTC wakeup interrupt in the RTC and in the Platform Level Interrupt Controller (PLIC). * Clears any pending RTC wakeup interrupt in the RTC and in the Platform Level Interrupt Controller (PLIC). * Enables the RTC_WAKEUP_CR[0] mask bit in the MSS System Register to connect the RTC wakeup interrupt to the Platform Level Interrupt Controller. * Resets the RTC counters, alarm and the compare registers * Sets the RTC's operating mode to binary counter mode or calendar counter mode, as specified by the mode parameter * Sets the RTC's prescaler register to the value specified by the prescaler parameter. The frequency of the clock source driving the MSS RTC clock (RTCCLK) input is required to calculate the prescaler value. -------------------------------------------- Setting and Reading the RTC Counter Value -------------------------------------------- The MSS RTC supports two mode of operation - binary mode and calendar mode. The following functions are used to set and read the current value of the counter when the MSS RTC is configured to operate in binary mode: * MSS_RTC_set_binary_count() - This function is used to set the current value of the RTC binary counter. * MSS_RTC_get_binary_count() - This function is used to read the current value of the RTC binary counter. The following functions are used to set and read the current value of the counter the MSS RTC is configured to operate in calendar mode: * MSS_RTC_set_calendar_count() - This function is used to set the current value of the RTC calendar counter. * MSS_RTC_get_calendar_count() - This function is used to read the current value of the RTC calendar counter. The following functions resets the RTC counter in either binary or calendar operating mode: * MSS_RTC_reset_counter() - This function resets the RTC counter. -------------------------------------------- Setting RTC Alarms -------------------------------------------- The MSS RTC can generate alarms when the counter matches a specified count value in binary mode or a date and time in calendar mode. The following functions are used to set up alarms: * MSS_RTC_set_binary_count_alarm() - This function sets up one-shot or periodic alarms when the MSS RTC is configured to operate in binary mode. * MSS_RTC_set_calendar_count_alarm() - This function sets up one-shot or periodic alarms when the MSS RTC is configured to operate in calendar mode. Note: The alarm asserts a wakeup interrupt to the RISC-V Core. This function enables the RTC's wakeup interrupt output, however the RTC wakeup interrupt input to the RISC-V PLIC must be enabled separately by calling the MSS_RTC_enable_irq() function. The alarm can be disabled at any time by calling the MSS_RTC_disable_irq() function. -------------------------------------------- Starting and Stopping the RTC Counter -------------------------------------------- The following functions start and stop the RTC counter: - MSS_RTC_start() - This function starts the RTC counter. - MSS_RTC_stop() - This function stops the RTC counter. ------------------------------------------- Interrupt Control ------------------------------------------- The MSS_RTC_enable_irq () function enables the RTC_WAKEUP_CR[0] mask bit in the MSS System Register to connect the RTC wakeup interrupt to the Platform Level Interrupt Controller. An rtc_wakeup_plic_IRQHandler () default implementation is defined, with weak linkage, in the PolarFire SoC MPFS HAL. You must provide your own implementation of the rtc_wakeup_plic_IRQHandler () function, which will override the default implementation, to suit your application. The function prototype for the RTC wakeup interrupt handler is as follows: uint8_t rtc_wakeup_plic_IRQHandler(void); The RTC wakeup interrupt is controlled using the following functions: * MSS_RTC_enable_irq() - The MSS_RTC_enable_irq() function enables the RTC to interrupt the MSS when a wakeup alarm occurs. * MSS_RTC_disable_irq() - The MSS_RTC_disable_irq() function disables the RTC from interrupting the MSS when a wakeup alarm occurs. * MSS_RTC_clear_irq() - The MSS_RTC_clear_irq() function clears a pending RTC wakeup interrupt at the RTC wakeup output. You must call the MSS_RTC_clear_irq() function as part of your implementation of the rtc_wakeup_plic_IRQHandler() interrupt service routine (ISR) in order to prevent the same interrupt event retriggering a call to the ISR. *//*=========================================================================*/ #ifndef MSS_RTC_H_ #define MSS_RTC_H_ #include "mss_rtc_regs.h" #include "hal/cpu_types.h" #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** The MSS_RTC_BINARY_MODE constant is used to specify the mode parameter to the MSS_RTC_init() function. The RTC will run in binary mode if this constant is used. In binary mode, the calendar counter counts consecutively from 0 all the way to 2^43. */ #define MSS_RTC_BINARY_MODE 0u /*-------------------------------------------------------------------------*//** The MSS_RTC_CALENDAR_MODE constant is used to specify the mode parameter to the MSS_RTC_init() function. The RTC will run in calendar mode if this constant is used. In calendar mode, the calendar counter counts seconds, minutes, hours, days, months, years, weekdays and weeks. */ #define MSS_RTC_CALENDAR_MODE 1u /*-------------------------------------------------------------------------*//** The alarm_value parameter of the MSS_RTC_set_calendar_count_alarm() function is a pointer to an mss_rtc_calender_t data structure specifying the date and time at which the alarm is to occur. You must assign the required date and time values to the mss_rtc_calender_t structure before calling the function. Any of the fields of the mss_rtc_calender_t structure can be set to MSS_RTC_CALENDAR_DONT_CARE, to indicate that they are not to be considered in deciding when the alarm will occur; this is necessary when setting periodic alarms. */ #define MSS_RTC_CALENDAR_DONT_CARE 0xFFu /*-------------------------------------------------------------------------*//** Days of the week. */ #define MSS_RTC_SUNDAY 1u #define MSS_RTC_MONDAY 2u #define MSS_RTC_TUESDAY 3u #define MSS_RTC_WEDNESDAY 4u #define MSS_RTC_THRUSDAY 5u #define MSS_RTC_FRIDAY 6u #define MSS_RTC_SATURDAY 7u /***************************************************************************//** MSS RTC base addresses. These definitions provides access to the MSS RTC mapped at two different memory regions. User can provide one of these constants to the MSS_RTC_init() function for configuring the MSS RTC block. */ #define MSS_RTC_LO_BASE (RTC_TypeDef *)MSS_RTC_LO_ADDR #define MSS_RTC_HI_BASE (RTC_TypeDef *)MSS_RTC_HI_ADDR /*-------------------------------------------------------------------------*//** The mss_rtc_alarm_type_t enumeration is used as the alarm_type parameter for the MSS_RTC_set_calendar_count_alarm() and MSS_RTC_set_binary_count_alarm() functions to specify whether the requested alarm should occur only one time or periodically. */ typedef enum { MSS_RTC_SINGLE_SHOT_ALARM, MSS_RTC_PERIODIC_ALARM } mss_rtc_alarm_type_t; /*-------------------------------------------------------------------------*//** A pointer to an instance of the mss_rtc_calender_t data structure is used to write new date and time values to the RTC using the MSS_RTC_set_rtc_calendar_count() and MSS_RTC_set_calendar_count_alarm() functions. The MSS_RTC_get_calendar_count() function also uses a pointer to an instance of the mss_rtc_calender_t data structure to read the current date and time value from the RTC. */ typedef struct mss_rtc_calender { uint8_t second; uint8_t minute; uint8_t hour; uint8_t day; uint8_t month; uint8_t year; uint8_t weekday; uint8_t week; } mss_rtc_calender_t ; /*-------------------------------------------------------------------------*//** The MSS_RTC_init() function initializes the RTC driver and hardware to a known state. To initialize the RTC hardware, this function: * Stops the RTC counters and disables the RTC alarm * Disables the RTC wakeup interrupt in the RTC and in the PolarFire SoC MSS Platform Level Interrupt Controller (PLIC). * Clears any pending RTC wakeup interrupt in the RTC and in the PolarFire SoC MSS Platform Level Interrupt Controller (PLIC). * Resets the RTC counters and the alarm and compare registers * Sets the RTC's operating mode to binary counter mode or calendar counter mode, as specified by the mode parameter * Sets the RTC's prescaler register to the value specified by the prescaler parameter * The MSS clock controller can supply one of three clock sources to the RTC clock input (RTCCLK): - Crystal Oscillator 32.768 kHz - 1MHz Oscillator - 50MHz Oscillator. (25 MHz in a 1.0v part). For calendar mode, program the prescaler register to generate a 1Hz signal from the active RTCCLK according to the following equation: prescaler = RTCCLK - 1 (where RTCCLK unit is Hz) For a 32.768 kHz clock, set the prescaler to 32768 - 1 = 32767. The prescaler register is 26 bits wide, allowing clock sources of up to 67 MHz to generate the 1Hz time base. For binary mode, the prescaler register can be programmed to generate a 1Hz time base or a different time base, as required. @param base_address The base address parameter provides the base address of the MSS RTC peripheral. The MSS RTC can appear on either the AXI slave 5 or slave 6 per SYSREG configurations. The corresponding base address of this peripheral must be provided per your configuration. @param mode The mode parameter is used to specify the operating mode of the RTC. The allowed values for mode are: - MSS_RTC_BINARY_MODE - MSS_RTC_CALENDAR_MODE @param prescaler The prescaler parameter specifies the value to divide the incoming RTC clock by, to generate the RTC time base signal. For calendar mode, set the prescaler value to generate a 1Hz time base from the incoming RTC clock according to the following equation: prescaler = RTCCLK - 1 (where the RTCCLK unit is Hz) For binary mode, set the prescaler value to generate a 1Hz time base or a different time base, as required. The prescaler parameter can be any integer value in the range 2 to 2^26. @return This function does not return any value. Example: The example code below shows how the RTC can be initialized only after a power-on reset. @code #define PO_RESET_DETECT_MASK 0x00000001u void e51(void) { uint32_t power_on_reset; power_on_reset = SYSREG->RESET_SOURCE_CR & PO_RESET_DETECT_MASK; if(power_on_reset) { MSS_RTC_init(MSS_RTC_LO_BASE, MSS_RTC_BINARY_MODE, RTC_PERIPH_PRESCALER/ 10u ); SYSREG->RESET_SOURCE_CR = PO_RESET_DETECT_MASK; } } @endcode */ void MSS_RTC_init ( RTC_TypeDef *base_address, uint8_t mode, uint32_t prescaler ); /*-------------------------------------------------------------------------*//** The MSS_RTC_set_binary_count() function sets the current value of the RTC binary counter. Note: This function must only be used when the RTC is configured to operate in binary counter mode. @param new_rtc_value The new_rtc_value parameter specifies the new count value from which the RTC will increment. The binary counter is 43 bits wide, so the maximum allowed binary value is 2^43. @return This function does not return a value. */ void MSS_RTC_set_binary_count ( uint64_t new_rtc_value ); /*-------------------------------------------------------------------------*//** The MSS_RTC_set_rtc_calendar_count() function sets the current value of the RTC calendar counter. Note: This function must only be used when the RTC is configured to operate in calendar counter mode. @param new_rtc_value The new_rtc_value parameter is a pointer to an mss_rtc_calender_t data structure specifying the new date and time value from which the RTC will increment. You must populate the mss_rtc_calender_t structure with the required date and time values before calling this function. @return This function does not return a value. */ void MSS_RTC_set_calendar_count ( const mss_rtc_calender_t *new_rtc_value ); /*-------------------------------------------------------------------------*//** The MSS_RTC_get_calendar_count() function returns the current value of the RTC calendar counter via the data structure pointed to by the p_rtc_calendar parameter. Note: This function must only be used when the RTC is configured to operate in calendar counter mode. @param p_rtc_calendar The p_rtc_calendar parameter is a pointer to an mss_rtc_calender_t data structure where the current value of the calendar counter will be written by the MSS_RTC_get_calendar_count() function @return This function does not return a value. */ void MSS_RTC_get_calendar_count ( mss_rtc_calender_t *p_rtc_calendar ); /*-------------------------------------------------------------------------*//** The MSS_RTC_get_binary_count() function returns the current value of the RTC binary counter. Note: This function must only be used when the RTC is configured to operate in binary counter mode. @param This function takes no parameters. @return This function returns the current value of the RTC binary counter as an unsigned 64-bit integer. */ uint64_t MSS_RTC_get_binary_count ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_start() function starts the RTC incrementing. @param This function takes no parameters. @return This function does not return a value. */ void MSS_RTC_start ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_stop() function stops the RTC from incrementing. @param This function takes no parameters. @return This function does not return a value. */ void MSS_RTC_stop ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_reset_counter() function resets the RTC counters. If the counter was running before calling this function, then it continues incrementing from the counter's reset value. @param This function takes no parameters. @return This function does not return a value. */ void MSS_RTC_reset_counter ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_enable_irq() function enables the RTC wakeup output to interrupt the MSS when an alarm occurs. It enables the RTC wakeup interrupt (RTC_Wakeup_IRQn) in the PoalrFire SoC PLIC. The rtc_wakeup_plic_IRQHandler() function will be called when an RTC wakeup interrupt occurs. Note: The rtc_wakeup_plic_IRQHandler() default implementation is defined, with weak linkage, in the PoalrFire SoC MPFS HAL. You must provide your own implementation of the rtc_wakeup_plic_IRQHandler() function, which will override the default implementation, to suit your application. Note: This function only enables the RTC wakeup interrupt at the PolarFire SoC PLIC level. The alarm setting functions enable the wakeup interrupt output from the RTC. @param This function takes no parameters. @return This function does not return a value. */ void MSS_RTC_enable_irq ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_disable_irq() function disables the RTC wakeup interrupt (RTC_WAKEUP_PLIC)in the PolarFire SoC MSS PLIC. Note: This function only disables the RTC wakeup interrupt at the PolarFire SoC PLIC level. It does not disable the wakeup interrupt output from the RTC. @param This function takes no parameters. @return This function does not return a value. */ void MSS_RTC_disable_irq ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_clear_irq() function clears a pending wakeup interrupt from the RTC. This function does not clear the interrupt in the PolarFire SoC PLIC; it only clears the wakeup output from the RTC. Note: You must call the MSS_RTC_clear_irq() function as part of your implementation of the rtc_wakeup_plic_IRQHandler() RTC wakeup interrupt service routine (ISR) in order to prevent the same interrupt event retriggering a call to the ISR. @param This function takes no parameters. @return This function does not return a value. Example: The example code below demonstrates how the MSS_RTC_clear_irq() function is intended to be used as part of the RTC wakeup interrupt service routine used by an application to handle RTC alarms. @code #if defined(__GNUC__) __attribute__((__interrupt__)) void rtc_wakeup_plic_IRQHandler( void ) #else void rtc_wakeup_plic_IRQHandler( void ) #endif { process_alarm(); MSS_RTC_clear_irq(); } @endcode */ void MSS_RTC_clear_irq ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_set_calendar_count_alarm() function sets up the RTC to generate an alarm when the RTC count reaches the time/date specified by the alarm_value parameter. The alarm asserts a wakeup interrupt to the MSS. This function enables the RTC's wakeup interrupt output, however the RTC wakeup interrupt input to the PolarFire SoC PLIC must be enabled separately by calling the MSS_RTC_enable_irq() function. The alarm can be disabled at any time by calling the MSS_RTC_disable_irq() function. Single-shot alarm The alarm can be a single-shot alarm, which will generate a single wakeup interrupt the first time the RTC count reaches the time/date specified by alarm_value. A single shot alarm is achieved by specifying a value for every field of the mss_rtc_calender_t data structure pointed to by the alarm_value parameter. The RTC counter will keep incrementing after a single shot alarm occurs. Periodic alarm The alarm can also be a periodic alarm, which will generate a wakeup interrupt every time the RTC count reaches the time/date specified by alarm_value, with the counter running in a continuous loop. The periodic alarm can be set to occur every minute, hour, day, month, year, week, day of the week, or any valid combination of these. This is achieved by setting some of the fields of the mss_rtc_calender_t data structure pointed to by the alarm_value parameter, to MSS_RTC_CALENDAR_DONT_CARE. For example, setting the weekday field to MSS_RTC_MONDAY and all other fields to MSS_RTC_CALENDAR_DONT_CARE will result in an alarm occurring every Monday. You can refine the time at which the alarm will occur by specifying values for the hour, minute and second fields. Note: This function must only be used when the RTC is configured to operate in calendar counter mode. @param alarm_value The alarm_value parameter is a pointer to an mss_rtc_calender_t data structure specifying the date and time at which the alarm is to occur. You must assign the required date and time values to the mss_rtc_calender_t structure before calling this function. Some of the fields within the mss_rtc_calender_t structure can be set to MSS_RTC_CALENDAR_DONT_CARE, to indicate that they are not to be considered in deciding when the alarm will occur; this is necessary when setting periodic alarms. @return This function does not return a value. Examples: The following example code demonstrates how to configure the RTC to generate a single calendar alarm at a specific date and time. The alarm will only occur once and the RTC will keep incrementing regardless of the alarm taking place. @code const mss_rtc_calender_t initial_calendar_count = { 15u, second 30u, minute 6u, hour 6u, day 9u, month 12u, year 5u, weekday 37u week }; mss_rtc_calender_t alarm_calendar_count = { 17u, second 30u, minute 6u, hour 6u, day 9u, month 12u, year 5u, weekday 37u week }; MSS_RTC_init(MSS_RTC_LO_BASE, MSS_RTC_BINARY_MODE, RTC_PERIPH_PRESCALER/ 10u ); MSS_RTC_clear_irq(); MSS_RTC_set_calendar_count(&initial_calendar_count); MSS_RTC_enable_irq(); MSS_RTC_start(); MSS_RTC_set_calendar_count_alarm(&alarm_calendar_count); @endcode The following example code demonstrates how to configure the RTC to generate a periodic calendar alarm. The RTC is configured to generate an alarm every Tuesday at 16:45:00. The alarm will reoccur every week until the RTC wakeup interrupt is disabled using a call to MSS_RTC_disable_irq(). @code mss_rtc_calender_t initial_calendar_count = { 58u, <--second 59u, <--minute 23u, <--hour 10u, <--day 9u, <--month 12u, <--year MSS_RTC_MONDAY, <--weekday 37u <--week }; mss_rtc_calender_t alarm_calendar_count = { MSS_RTC_CALENDAR_DONT_CARE, <--second 45u, <--minute 16u, <--hour MSS_RTC_CALENDAR_DONT_CARE, <--day MSS_RTC_CALENDAR_DONT_CARE, <--month MSS_RTC_CALENDAR_DONT_CARE, <--year MSS_RTC_TUESDAY, <--weekday MSS_RTC_CALENDAR_DONT_CARE <--week }; MSS_RTC_init(MSS_RTC_LO_BASE, MSS_RTC_BINARY_MODE, RTC_PERIPH_PRESCALER/ 10u ); MSS_RTC_set_calendar_count(&initial_calendar_count); MSS_RTC_enable_irq(); MSS_RTC_start(); MSS_RTC_set_calendar_count_alarm(&alarm_calendar_count); @endcode The following example code demonstrates the code that you need to include in your application to handle alarms. It is the interrupt service routine for the RTC wakeup interrupt input to the PolarFire SoC PLIC. You need to add your application code in this function in place of the process_alarm() function but you must retain the call to MSS_RTC_clear_irq() to ensure that the same alarm does not retrigger the interrupt. @code #if defined(__GNUC__) __attribute__((__interrupt__)) void rtc_wakeup_plic_IRQHandler( void ) #else void rtc_wakeup_plic_IRQHandler( void ) #endif { process_alarm(); MSS_RTC_clear_irq(); } @endcode */ void MSS_RTC_set_calendar_count_alarm ( const mss_rtc_calender_t * alarm_value ); /*-------------------------------------------------------------------------*//** The MSS_RTC_set_binary_count_alarm() function sets up the RTC to generate an alarm when the RTC count reaches the value specified by the alarm_value parameter. The alarm asserts a wakeup interrupt to the MSS. This function enables the RTC's wakeup interrupt output, however the RTC wakeup interrupt input to the PolarFire SoC PLIC must be enabled separately by calling the MSS_RTC_enable_irq() function. The alarm can be disabled at any time by calling the MSS_RTC_disable_irq() function. Single-shot alarm The alarm can be a single-shot alarm, which will generate a single wakeup interrupt the first time the RTC count reaches the value specified by the alarm_value parameter. Setting the alarm_value parameter to MSS_RTC_PERIODIC_ALARM produces a single-shot alarm. The RTC counter continues incrementing when a single shot alarm occurs. Periodic alarm The alarm can also be a periodic alarm, which will generate a wakeup interrupt every time the RTC count reaches the value specified by the alarm_value parameter. Setting the alarm_value parameter to MSS_RTC_SINGLE_SHOT_ALARM produces a periodic alarm. The RTC counter automatically wraps around to zero and continues incrementing when a periodic alarm occurs. Note: This function must only be used when the RTC is configured to operate in binary counter mode. @param alarm_value The alarm_value parameter is a 64-bit unsigned value specifying the RTC counter value that must be reached for the requested alarm to occur. @param alarm_type The alarm_type parameter specifies whether the requested alarm is a single shot or periodic alarm. It can only take one of these two values: - MSS_RTC_SINGLE_SHOT_ALARM, - MSS_RTC_PERIODIC_ALARM @return This function does not return a value. */ void MSS_RTC_set_binary_count_alarm ( uint64_t alarm_value, mss_rtc_alarm_type_t alarm_type ); /*-------------------------------------------------------------------------*//** The MSS_RTC_get_update_flag() function indicates if the RTC counter has incremented since the last call to MSS_RTC_clear_update_flag(). It returns zero if no RTC counter increment has occurred. It returns a non-zero value if the RTC counter has incremented. This function can be used whether the RTC is configured to operate in calendar or binary counter mode. @return This function returns, |Value | Description | |---------|-----------------------------------------------------------| |zero: | if the RTC has not incremented since the last call to | | | MSS_RTC_clear_update_flag(), | |---------|-----------------------------------------------------------| |non-zero:| if the RTC has incremented since the last call to | | | MSS_RTC_clear_update_flag(). | | | | Example This example waits for the RTC timer to increment by one second. @code void wait_start_of_second(void) { uint32_t rtc_count_updated; MSS_RTC_clear_update_flag(); do { rtc_count_updated = MSS_RTC_get_update_flag(); } while(!rtc_count_updated) } @endcode */ uint32_t MSS_RTC_get_update_flag ( void ); /*-------------------------------------------------------------------------*//** The MSS_RTC_clear_update_flag() function clears the CONTROL register flag that is set when the RTC counter increments. It is used alongside function MSS_RTC_get_update_flag() to detect RTC counter increments. @return This function does not return a value. Example The example below will wait for the RTC timer to increment by one second. @code void wait_start_of_second(void) { uint32_t rtc_count_updated; MSS_RTC_clear_update_flag(); do { rtc_count_updated = MSS_RTC_get_update_flag(); } while(!rtc_count_updated) } @endcode */ void MSS_RTC_clear_update_flag ( void ); #ifdef __cplusplus } #endif #endif /* MSS_RTC_H_ */ mss_rtc_regs.h000066400000000000000000000046261432224323300376000ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_rtc /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC MSS RTC Driver. * * SVN $Revision$ * SVN $Date$ */ #ifndef MSS_RTC_REG_H__ #define MSS_RTC_REG_H__ #ifdef __cplusplus extern "C" { #endif #include "mss_hal.h" /******************************************************************************/ /* Device Specific Peripheral registers structures */ /******************************************************************************/ typedef struct { volatile uint32_t CONTROL_REG ; volatile uint32_t MODE_REG ; volatile uint32_t PRESCALER_REG ; volatile uint32_t ALARM_LOWER_REG ; volatile uint32_t ALARM_UPPER_REG ; volatile uint32_t COMPARE_LOWER_REG ; volatile uint32_t COMPARE_UPPER_REG ; uint32_t RESERVED0 ; volatile uint32_t DATE_TIME_LOWER_REG ; volatile uint32_t DATE_TIME_UPPER_REG ; uint32_t RESERVED1[2] ; volatile uint32_t SECONDS_REG ; volatile uint32_t MINUTES_REG ; volatile uint32_t HOURS_REG ; volatile uint32_t DAY_REG ; volatile uint32_t MONTH_REG ; volatile uint32_t YEAR_REG ; volatile uint32_t WEEKDAY_REG ; volatile uint32_t WEEK_REG ; volatile uint32_t SECONDS_CNT_REG ; volatile uint32_t MINUTES_CNT_REG ; volatile uint32_t HOURS_CNT_REG ; volatile uint32_t DAY_CNT_REG ; volatile uint32_t MONTH_CNT_REG ; volatile uint32_t YEAR_CNT_REG ; volatile uint32_t WEEKDAY_CNT_REG ; volatile uint32_t WEEK_CNT_REG ; } RTC_TypeDef; /******************************************************************************/ /* Peripheral declaration */ /******************************************************************************/ #define MSS_RTC_LO_ADDR 0x20124000u #define MSS_RTC_HI_ADDR 0x28124000u #define COMPARE_ALL_BITS 0xFFFFFFFFu #ifdef __cplusplus } #endif #endif /* MSS_RTC_REG_H__ */ mss_spi/000077500000000000000000000000001432224323300347305ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_spi.c000066400000000000000000001347141432224323300365630ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_spi/***************************************************************************//** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire SoC(PSE) microcontroller subsystem SPI bare metal software driver * implementation. * * SVN $Revision$ * SVN $Date$ */ #include "mss_spi.h" #include "mss_assert.h" #include "mss_sysreg.h" #include "mss_ints.h" #include "mss_plic.h" #include #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * Mask of transfer protocol and SPO, SPH bits within control register. */ #define PROTOCOL_MODE_MASK ((uint32_t) 0x0300000Cu) /***************************************************************************//** * Mask of the frame count bits within the SPI control register. */ #define TXRXDFCOUNT_MASK ((uint32_t) 0x00FFFF00u) #define TXRXDFCOUNT_SHIFT ((uint32_t) 8u) #define BYTESUPPER_MASK ((uint32_t) 0xFFFF0000u) /***************************************************************************//** * SPI hardware FIFO depth. */ #define RX_FIFO_SIZE 4u #define BIG_FIFO_SIZE 32u /***************************************************************************//** * CONTROL register bit masks */ #define CTRL_ENABLE_MASK 0x00000001u #define CTRL_MASTER_MASK 0x00000002u /***************************************************************************//** Registers bit masks */ /* CONTROL register. */ #define MASTER_MODE_MASK 0x00000002u #define CTRL_RX_IRQ_EN_MASK 0x00000010u #define CTRL_TX_IRQ_EN_MASK 0x00000020u #define CTRL_OVFLOW_IRQ_EN_MASK 0x00000040u #define CTRL_URUN_IRQ_EN_MASK 0x00000080u #define CTRL_REG_RESET_MASK 0x80000000u #define BIGFIFO_MASK 0x20000000u #define CTRL_CLKMODE_MASK 0x10000000u #define SPS_MASK 0x04000000u /* CONTROL2 register */ #define C2_ENABLE_CMD_IRQ_MASK 0x00000010u #define C2_ENABLE_SSEND_IRQ_MASK 0x00000020u /* STATUS register */ #define TX_DONE_MASK 0x00000001u #define RX_DATA_READY_MASK 0x00000002u #define RX_OVERFLOW_MASK 0x00000004u #define RX_FIFO_EMPTY_MASK 0x00000040u #define TX_FIFO_FULL_MASK 0x00000100u #define TX_FIFO_EMPTY_MASK 0x00000400u /* MIS register. */ #define TXDONE_IRQ_MASK 0x00000001u #define RXDONE_IRQ_MASK 0x00000002u #define RXOVFLOW_IRQ_MASK 0x00000004u #define TXURUN_IRQ_MASK 0x00000008u #define CMD_IRQ_MASK 0x00000010u #define SSEND_IRQ_MASK 0x00000020u /* COMMAND register */ #define AUTOFILL_MASK 0x00000001u #define TX_FIFO_RESET_MASK 0x00000008u #define RX_FIFO_RESET_MASK 0x00000004u /***************************************************************************//** * */ #define RX_IRQ_THRESHOLD (BIG_FIFO_SIZE / 2u) /***************************************************************************//** Marker used to detect that the configuration has not been selected for a specific slave when operating as a master. */ #define NOT_CONFIGURED 0xFFFFFFFFu /***************************************************************************//** Maximum frame length */ #define MAX_FRAME_LENGTH 32u /***************************************************************************//** * SPI instance data structures for SPI0 and SPI1. A pointer to these data * structures must be used as first parameter to any of the SPI driver functions * to identify the SPI hardware block that will perform the requested operation. */ mss_spi_instance_t g_mss_spi0_lo; mss_spi_instance_t g_mss_spi1_lo; mss_spi_instance_t g_mss_spi0_hi; mss_spi_instance_t g_mss_spi1_hi; /***************************************************************************//* * This peripheral tracks if the SPI peripheral is located on S5 or S6 on AXI * switch. This will be used to determine which SPI instance is to be passed * to SPI interrupt handler. Value 0 = S5(SPI_LO) value 1 = S6(SPI_HI). * Bit positions * 0 -> SPI0 * 1 -> SPI1 */ static uint8_t g_spi_axi_pos = 0u; /***************************************************************************//** local functions */ static void recover_from_rx_overflow(mss_spi_instance_t * this_spi); static void fill_slave_tx_fifo(mss_spi_instance_t * this_spi); static void read_slave_rx_fifo(mss_spi_instance_t * this_spi); static void mss_spi_isr(mss_spi_instance_t * this_spi); /***************************************************************************//** * MSS_SPI_init() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_init ( mss_spi_instance_t * this_spi ) { uint16_t slave; ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi1_lo)); /* * Initialize SPI driver instance data. Relies on the majority * of data requiring 0 for initial state so we just need to fill * with 0s and finish off with a small number of non zero values. */ /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ( this_spi->irqn ); memset(this_spi, 0, sizeof(mss_spi_instance_t)); this_spi->cmd_done = 1u; for (slave = 0u; slave < (uint16_t)MSS_SPI_MAX_NB_OF_SLAVES; slave++) { this_spi->slaves_cfg[slave].ctrl_reg = NOT_CONFIGURED; } if (&g_mss_spi0_lo == this_spi) { this_spi->hw_reg = MSS_SPI0_LO_BASE; this_spi->irqn = SPI0_PLIC; g_spi_axi_pos &= ~0x01u; } else if (&g_mss_spi1_lo == this_spi) { this_spi->hw_reg = MSS_SPI1_LO_BASE; this_spi->irqn = SPI1_PLIC; g_spi_axi_pos &= ~0x02u; } else if (&g_mss_spi0_hi == this_spi) { this_spi->hw_reg = MSS_SPI0_HI_BASE; this_spi->irqn = SPI0_PLIC; g_spi_axi_pos |= 0x01u; } else if (&g_mss_spi1_hi == this_spi) { this_spi->hw_reg = MSS_SPI1_HI_BASE; this_spi->irqn = SPI1_PLIC; g_spi_axi_pos |= 0x02u; } else { ASSERT(0); } /* De-assert reset bit. */ this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; } /***************************************************************************//** * MSS_SPI_configure_slave_mode() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_configure_slave_mode ( mss_spi_instance_t * this_spi, mss_spi_protocol_mode_t protocol_mode, uint8_t frame_bit_length, mss_spi_oveflow_handler_t recieve_buffer_overflow_handler ) { ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); ASSERT(frame_bit_length <= MAX_FRAME_LENGTH); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ(this_spi->irqn); /* * Registering MSS SPI overflow handler to the SPI instance * */ this_spi->buffer_overflow_handler = recieve_buffer_overflow_handler; /* Don't yet know what slave transfer mode will be used */ this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_NONE; /* Set the mode. */ this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_MASTER_MASK; /* Set the protocol mode */ this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~PROTOCOL_MODE_MASK) | (uint32_t)protocol_mode | BIGFIFO_MASK; /* Set number of data frames to 1 by default */ this_spi->hw_reg->FRAMESUP = 0u; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1 << TXRXDFCOUNT_SHIFT); this_spi->hw_reg->FRAMESIZE = frame_bit_length; this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; /* Re-enable interrupts */ PLIC_EnableIRQ(this_spi->irqn); } /***************************************************************************//** * MSS_SPI_configure_master_mode() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_configure_master_mode ( mss_spi_instance_t * this_spi, mss_spi_slave_t slave, mss_spi_protocol_mode_t protocol_mode, uint32_t clk_div, uint8_t frame_bit_length, mss_spi_oveflow_handler_t recieve_buffer_overflow_handler ) { ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); ASSERT(slave < MSS_SPI_MAX_NB_OF_SLAVES); ASSERT(frame_bit_length <= MAX_FRAME_LENGTH); /* Check that the requested clock divider is within range and even number */ ASSERT(clk_div >= 2u); ASSERT(clk_div <= 512u); ASSERT(0u == (clk_div & 0x00000001U)); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ( this_spi->irqn ); /* * Registering MSS SPI overflow handler to the SPI instance * */ this_spi->buffer_overflow_handler = recieve_buffer_overflow_handler; /* Reset slave transfer mode to unknown to wipe slate clean */ this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_NONE; /* Set the mode. */ this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK; this_spi->hw_reg->CONTROL |= CTRL_MASTER_MASK; this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; /* * Keep track of the required register configuration for this slave. These * values will be used by the MSS_SPI_set_slave_select() function to * configure the master to match the slave being selected. */ if (slave < MSS_SPI_MAX_NB_OF_SLAVES) { uint32_t clk_gen; /* * Setting the SPS bit ensures the slave select remains asserted even * if we don't keep the TX FIFO filled in block mode. We only do it for * Motorola modes and if you need the slave selected deselected between * frames in modes 0 or 2 then remove SPS_MASK from below. */ if ((MSS_SPI_MODE0 == protocol_mode) || (MSS_SPI_MODE1 == protocol_mode) || (MSS_SPI_MODE2 == protocol_mode) || (MSS_SPI_MODE3 == protocol_mode)) { this_spi->slaves_cfg[slave].ctrl_reg = MASTER_MODE_MASK | SPS_MASK | BIGFIFO_MASK | CTRL_CLKMODE_MASK | (uint32_t)protocol_mode | ((uint32_t)1 << TXRXDFCOUNT_SHIFT); } else { this_spi->slaves_cfg[slave].ctrl_reg = MASTER_MODE_MASK | BIGFIFO_MASK | CTRL_CLKMODE_MASK | (uint32_t)protocol_mode | ((uint32_t)1 << TXRXDFCOUNT_SHIFT); } this_spi->slaves_cfg[slave].txrxdf_size_reg = frame_bit_length; clk_gen = (clk_div / 2u) - (uint32_t)1u; this_spi->slaves_cfg[slave].clk_gen = (uint8_t)clk_gen; } /* Re enable interrupts */ PLIC_EnableIRQ( this_spi->irqn ); } /***************************************************************************//** * MSS_SPI_set_slave_select() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_set_slave_select ( mss_spi_instance_t * this_spi, mss_spi_slave_t slave ) { uint32_t rx_overflow; ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI master. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); ASSERT(this_spi->slaves_cfg[slave].ctrl_reg != NOT_CONFIGURED); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ( this_spi->irqn ); /* Recover from receive overflow. */ rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK; if (rx_overflow > 0U) { recover_from_rx_overflow(this_spi); } /* Set the clock rate. */ this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK; this_spi->hw_reg->CONTROL = this_spi->slaves_cfg[slave].ctrl_reg; this_spi->hw_reg->CLK_GEN = (uint32_t)(this_spi->slaves_cfg[slave].clk_gen); this_spi->hw_reg->FRAMESIZE = (uint32_t)(this_spi->slaves_cfg[slave].txrxdf_size_reg); this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; /* Set slave select */ this_spi->hw_reg->SLAVE_SELECT |= ((uint32_t)1 << (uint32_t)slave); /* Re enable interrupts */ PLIC_EnableIRQ( this_spi->irqn); } /***************************************************************************//** * MSS_SPI_clear_slave_select() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_clear_slave_select ( mss_spi_instance_t * this_spi, mss_spi_slave_t slave ) { uint32_t rx_overflow; ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI master. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ( this_spi->irqn ); /* Recover from receive overflow. */ rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK; if (rx_overflow > 0U) { recover_from_rx_overflow(this_spi); } this_spi->hw_reg->SLAVE_SELECT &= ~((uint32_t)1 << (uint32_t)slave); /* Re enable interrupts */ PLIC_EnableIRQ( this_spi->irqn ); } /***************************************************************************//** * MSS_SPI_transfer_frame() * See "mss_spi.h" for details of how to use this function. */ uint32_t MSS_SPI_transfer_frame ( mss_spi_instance_t * this_spi, uint32_t tx_bits ) { uint32_t rx_ready; uint32_t tx_done; ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI master. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); /* Ensure single frame transfer selected so interrupts work correctly */ this_spi->hw_reg->FRAMESUP = 0u; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1u << TXRXDFCOUNT_SHIFT); /* Flush the Tx and Rx FIFOs. */ this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK | (uint32_t)RX_FIFO_RESET_MASK); /* Send frame. */ this_spi->hw_reg->TX_DATA = tx_bits; /* Wait for frame Tx to complete. */ tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK; while (0u == tx_done) { tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK; } /* Read received frame. */ /* Wait for Rx complete. */ rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK; while (0u == rx_ready) { rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK; } /* Return Rx data. */ return( this_spi->hw_reg->RX_DATA ); } /***************************************************************************//** * MSS_SPI_transfer_block() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_transfer_block ( mss_spi_instance_t * this_spi, const uint8_t cmd_buffer[], uint32_t cmd_byte_size, uint8_t rd_buffer[], uint32_t rd_byte_size ) { uint32_t transfer_idx = 0u; uint32_t tx_idx; uint32_t rx_idx; uint32_t frame_count; volatile uint32_t rx_raw; uint32_t transit = 0u; uint32_t tx_fifo_full; uint32_t rx_overflow; uint32_t rx_fifo_empty; uint32_t transfer_size; /* Total number of bytes transfered. */ ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI master. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); /* Compute number of bytes to transfer. */ transfer_size = cmd_byte_size + rd_byte_size; /* Adjust to 1 byte transfer to cater for DMA transfers. */ if (0u == transfer_size) { frame_count = 1u; } else { frame_count = transfer_size; } /* Flush the Tx and Rx FIFOs. */ this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK | (uint32_t)RX_FIFO_RESET_MASK); /* Recover from receive overflow. */ rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK; if (rx_overflow > 0U) { recover_from_rx_overflow(this_spi); } /* Set frame size to 8 bits and the frame count to the transfer size. */ this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK; this_spi->hw_reg->FRAMESUP = frame_count & BYTESUPPER_MASK; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((frame_count << TXRXDFCOUNT_SHIFT) & TXRXDFCOUNT_MASK); this_spi->hw_reg->FRAMESIZE = MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE; this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; /* Flush the receive FIFO. */ rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; while (0u == rx_fifo_empty) { rx_raw = this_spi->hw_reg->RX_DATA; rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; } tx_idx = 0u; rx_idx = 0u; if (tx_idx < cmd_byte_size) { this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx]; ++tx_idx; ++transit; } else { if (tx_idx < transfer_size) { this_spi->hw_reg->TX_DATA = 0x00u; ++tx_idx; ++transit; } } /* Perform the remainder of the transfer by sending a byte every time a byte * has been received. This should ensure that no Rx overflow can happen in * case of an interrupt occurs during this function. */ while (transfer_idx < transfer_size) { rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; if (0u == rx_fifo_empty) { /* Process received byte. */ rx_raw = this_spi->hw_reg->RX_DATA; if (transfer_idx >= cmd_byte_size) { if (rx_idx < rd_byte_size) { rd_buffer[rx_idx] = (uint8_t)rx_raw; } ++rx_idx; } ++transfer_idx; --transit; } tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK; if (0u == tx_fifo_full) { if (transit < RX_FIFO_SIZE) { /* Send another byte. */ if (tx_idx < cmd_byte_size) { this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx]; ++tx_idx; ++transit; } else { if (tx_idx < transfer_size) { this_spi->hw_reg->TX_DATA = 0x00u; ++tx_idx; ++transit; } } } } } } /***************************************************************************//** * MSS_SPI_set_frame_rx_handler() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_set_frame_rx_handler ( mss_spi_instance_t * this_spi, mss_spi_frame_rx_handler_t rx_handler ) { uint32_t tx_fifo_empty; ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI slave. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ( this_spi->irqn ); /* Disable block Rx handlers as they are mutually exclusive. */ this_spi->block_rx_handler = 0u; this_spi->cmd_handler = 0u; /* Keep a copy of the pointer to the rx handler function. */ this_spi->frame_rx_handler = rx_handler; /* Make sure correct mode is selected */ this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_FRAME; /* Automatically fill the TX FIFO with zeroes if no slave tx frame set.*/ tx_fifo_empty = this_spi->hw_reg->STATUS & TX_FIFO_EMPTY_MASK; if (tx_fifo_empty > 0U) { this_spi->hw_reg->COMMAND |= AUTOFILL_MASK; } /* Ensure single frame transfer selected so interrupts work correctly */ this_spi->hw_reg->FRAMESUP = 0u; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1u << TXRXDFCOUNT_SHIFT); /* Disable block specific interrupts */ this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK; this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_SSEND_IRQ_MASK; /* Clear down interrupts to avoid stale interrupts triggering when we * enable them below */ this_spi->hw_reg->INT_CLEAR = ((uint32_t)TXURUN_IRQ_MASK | (uint32_t)RXOVFLOW_IRQ_MASK | (uint32_t)RXDONE_IRQ_MASK); /* * Enable TX underrun and RX overflow interrupts to improve error * recovery and the Rx interrupt. */ this_spi->hw_reg->CONTROL |= ((uint32_t)CTRL_URUN_IRQ_EN_MASK | (uint32_t)CTRL_OVFLOW_IRQ_EN_MASK | (uint32_t)CTRL_RX_IRQ_EN_MASK); PLIC_EnableIRQ(this_spi->irqn); } /***************************************************************************//** * MSS_SPI_set_slave_tx_frame() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_set_slave_tx_frame ( mss_spi_instance_t * this_spi, uint32_t frame_value ) { ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI slave. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ(this_spi->irqn); /* Make sure correct mode is selected */ this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_FRAME; /* Disable block Rx handlers as they are mutually exclusive. */ this_spi->block_rx_handler = 0u; this_spi->cmd_handler = 0u; /* Disable slave block tx buffer as it is mutually exclusive with frame * level handling. */ this_spi->slave_tx_buffer = 0u; this_spi->slave_tx_size = 0u; this_spi->slave_tx_idx = 0u; /* Keep a copy of the slave tx frame value. */ this_spi->slave_tx_frame = frame_value; /* Disable automatic fill of the TX FIFO with zeroes.*/ this_spi->hw_reg->COMMAND &= ~(uint32_t)AUTOFILL_MASK; this_spi->hw_reg->COMMAND |= TX_FIFO_RESET_MASK; /* * Ensure single frame transfer selected so interrupts work correctly * * IMPORTANT: Note this must be done before writing to the TX_DATA register * as it seems that doing these in the opposite order causes the receive * and transmit interrupts to be disabled. */ this_spi->hw_reg->FRAMESUP = 0u; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1u << TXRXDFCOUNT_SHIFT); /* Load frame into Tx data register. */ this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame; /* Disable block specific interrupts */ this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK; this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_SSEND_IRQ_MASK; /* Clear down interrupts to avoid stale interrupts triggering when we * enable them below */ this_spi->hw_reg->INT_CLEAR = ((uint32_t)TXURUN_IRQ_MASK | (uint32_t)RXOVFLOW_IRQ_MASK | (uint32_t)RXDONE_IRQ_MASK); /* * Enable Tx Done interrupt in order to reload the slave Tx frame after each * time it has been sent. * * Enable TX underrun and RX overflow interrupts to improve error * recovery. */ this_spi->hw_reg->CONTROL |= ((uint32_t)CTRL_URUN_IRQ_EN_MASK | (uint32_t)CTRL_OVFLOW_IRQ_EN_MASK | (uint32_t)CTRL_RX_IRQ_EN_MASK); PLIC_EnableIRQ(this_spi->irqn); } /***************************************************************************//** * MSS_SPI_set_slave_block_buffers() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_set_slave_block_buffers ( mss_spi_instance_t * this_spi, const uint8_t * tx_buffer, uint32_t tx_buff_size, uint8_t * rx_buffer, uint32_t rx_buff_size, mss_spi_block_rx_handler_t block_rx_handler ) { uint32_t frame_count; uint32_t done = 0u; ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); /* This function is only intended to be used with an SPI slave. */ ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK); /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ(this_spi->irqn); /* Make sure correct mode is selected */ this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_BLOCK; /* Set cmd_done correctly to ensure 0 padding works. */ if ((mss_spi_block_rx_handler_t)0 == this_spi->cmd_handler) { this_spi->cmd_done = 1u; } else { this_spi->cmd_done = 0u; } /* Disable Rx frame handler as it is mutually exclusive with block rx handler. */ this_spi->frame_rx_handler = 0u; /* Keep a copy of the pointer to the block rx handler function. */ this_spi->block_rx_handler = block_rx_handler; this_spi->slave_rx_buffer = rx_buffer; this_spi->slave_rx_size = rx_buff_size; this_spi->slave_rx_idx = 0u; /* Initialise the transmit state data. */ this_spi->slave_tx_buffer = tx_buffer; this_spi->slave_tx_size = tx_buff_size; this_spi->slave_tx_idx = 0u; /* Flush the Tx and Rx FIFOs. * Please note this does not have any effect on A2F200. */ this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK | (uint32_t)RX_FIFO_RESET_MASK); /* Recover from receive overflow if needs be */ if (0u != (this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK)) { recover_from_rx_overflow(this_spi); } /* Flush Rx FIFO in case we are executing on A2F200. */ while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { volatile uint32_t dummy; dummy = this_spi->hw_reg->RX_DATA; } /* Use the frame counter to control how often receive interrupts are * generated */ frame_count = RX_IRQ_THRESHOLD; this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK; this_spi->hw_reg->FRAMESUP = frame_count & BYTESUPPER_MASK; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | (frame_count << TXRXDFCOUNT_SHIFT); this_spi->hw_reg->FRAMESIZE = MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE; this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; /* Load the transmit FIFO. */ while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) && (0u == done)) { if (this_spi->slave_tx_idx < this_spi->slave_tx_size) { this_spi->hw_reg->TX_DATA = (uint32_t)(this_spi->slave_tx_buffer[this_spi->slave_tx_idx]); } else if (0u != this_spi->cmd_done) { /* Fill with 0s if no need to insert command response */ this_spi->hw_reg->TX_DATA = 0x00u; } else { /* Exit loop early as command response needs to be inserted next */ done = 1u; } ++this_spi->slave_tx_idx; } if (tx_buff_size > 0u) { /* Clear and enable TX interrupt. Also disable autofill */ this_spi->hw_reg->COMMAND &= ~(uint32_t)AUTOFILL_MASK; this_spi->hw_reg->INT_CLEAR = TXDONE_IRQ_MASK; this_spi->hw_reg->CONTROL |= CTRL_TX_IRQ_EN_MASK; } else { this_spi->hw_reg->COMMAND |= AUTOFILL_MASK; } /* Ensure command interrupt disabled if no handler */ if ((mss_spi_block_rx_handler_t)0 == this_spi->cmd_handler) { this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK; } /* * Enable slave select release interrupt. The SSEND interrupt is used to * complete reading of the receive FIFO and prepare the transmit FIFO for * the next transaction. * Make sure to clear any pending send ints otherwise we will trigger * an immediate interrupt. */ this_spi->hw_reg->INT_CLEAR = SSEND_IRQ_MASK; this_spi->hw_reg->CONTROL2 |= C2_ENABLE_SSEND_IRQ_MASK; /* Clear down interrupts to avoid stale interrupts triggering when we * enable them below */ this_spi->hw_reg->INT_CLEAR = ((uint32_t)TXURUN_IRQ_MASK | (uint32_t)RXOVFLOW_IRQ_MASK | (uint32_t)RXDONE_IRQ_MASK); /* * Enable TX underrun and RX overflow interrupts to improve error * recovery. */ this_spi->hw_reg->CONTROL |= ((uint32_t)CTRL_URUN_IRQ_EN_MASK | (uint32_t)CTRL_OVFLOW_IRQ_EN_MASK | (uint32_t)CTRL_RX_IRQ_EN_MASK); PLIC_EnableIRQ(this_spi->irqn); } /***************************************************************************//** * MSS_SPI_set_cmd_handler() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_set_cmd_handler ( mss_spi_instance_t * this_spi, mss_spi_block_rx_handler_t cmd_handler, uint32_t cmd_size ) { /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ(this_spi->irqn); /* Make sure response state is cleared down */ this_spi->resp_tx_buffer = 0u; this_spi->resp_buff_size = 0u; this_spi->resp_buff_tx_idx = 0u; if ((mss_spi_block_rx_handler_t)0 == cmd_handler) { /* * Set this flag so zero padding is enabled */ this_spi->cmd_done = 1u; /* * Ensure command interrupt disabled if no handler * and handler pointer is wiped clean. */ this_spi->cmd_handler = 0u; this_spi->hw_reg->CMDSIZE = 0u; this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK; } else { /* * Clear this flag so zero padding is disabled until command response * has been taken care of. */ this_spi->cmd_done = 0u; this_spi->cmd_handler = cmd_handler; this_spi->hw_reg->CMDSIZE = cmd_size; /* Flush the Tx FIFO. Please note this does not have any effect on * A2F200. */ this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK | (uint32_t)RX_FIFO_RESET_MASK); /* * Reload TX FIFO as MSS_SPI_set_slave_block_buffers() may have zero * filled the FIFO if command handler was not in place when it was * called and so the first frame sent could be wrong. */ this_spi->slave_tx_idx = 0u; fill_slave_tx_fifo(this_spi); /* * Make sure to clear any pending command ints otherwise we will trigger * an immediate interrupt. */ this_spi->hw_reg->INT_CLEAR = CMD_IRQ_MASK; this_spi->hw_reg->CONTROL2 |= C2_ENABLE_CMD_IRQ_MASK; } PLIC_EnableIRQ(this_spi->irqn); /* Safe to allow interrupts again */ } /***************************************************************************//** * MSS_SPI_set_cmd_response() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_set_cmd_response ( mss_spi_instance_t * this_spi, const uint8_t * resp_tx_buffer, uint32_t resp_buff_size ) { this_spi->resp_tx_buffer = resp_tx_buffer; this_spi->resp_buff_size = resp_buff_size; this_spi->resp_buff_tx_idx = 0u; /* Note that we have provided response and start getting it into the FIFO */ this_spi->cmd_done = 1u; fill_slave_tx_fifo(this_spi); } /***************************************************************************//** * MSS_SPI_enable() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_enable ( mss_spi_instance_t * this_spi ) { /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ(this_spi->irqn); this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; /* Re enable interrupts */ PLIC_EnableIRQ(this_spi->irqn); } /***************************************************************************//** * MSS_SPI_disable() * See "mss_spi.h" for details of how to use this function. */ void MSS_SPI_disable ( mss_spi_instance_t * this_spi ) { /* Shut down interrupts from the MSS SPI while we do this */ PLIC_DisableIRQ(this_spi->irqn); this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK; /* Reenable interrupts */ PLIC_EnableIRQ(this_spi->irqn); } /***************************************************************************//** * MSS_SPI_tx_done() * See "mss_spi.h" for details of how to use this function. */ uint32_t MSS_SPI_tx_done ( mss_spi_instance_t * this_spi ) { uint32_t tx_done; tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK; return tx_done; } /***************************************************************************//** * Fill the transmit FIFO(used for slave block transfers). */ static void fill_slave_tx_fifo ( mss_spi_instance_t * this_spi ) { uint32_t guard = 0u; while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) && (this_spi->slave_tx_idx < this_spi->slave_tx_size)) { /* Sending from primary slave transmit buffer */ this_spi->hw_reg->TX_DATA = (uint32_t)(this_spi->slave_tx_buffer[this_spi->slave_tx_idx]); ++this_spi->slave_tx_idx; } if (this_spi->slave_tx_idx >= this_spi->slave_tx_size) { while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) && (this_spi->resp_buff_tx_idx < this_spi->resp_buff_size)) { /* Sending from command response buffer */ this_spi->hw_reg->TX_DATA = (uint32_t)(this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx]); ++this_spi->resp_buff_tx_idx; } } if ((0u != this_spi->cmd_done) && (this_spi->slave_tx_idx >= this_spi->slave_tx_size) && (this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size)) { while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) && (guard < BIG_FIFO_SIZE)) { /* Nothing left so pad with 0s for consistency */ this_spi->hw_reg->TX_DATA = 0x00u; /* * We use the guard count to cover the unlikely event that we are * never seeing the TX FIFO full because the data is being pulled * out as fast as we can stuff it in. In this event we never spend * more than a full FIFOs worth of time spinning here. */ guard++; } } } /***************************************************************************//** * */ static void read_slave_rx_fifo ( mss_spi_instance_t * this_spi ) { volatile uint32_t rx_frame; if (MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode) { while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { /* Single frame handling mode. */ rx_frame = this_spi->hw_reg->RX_DATA; if ((mss_spi_frame_rx_handler_t)0 != this_spi->frame_rx_handler) { this_spi->frame_rx_handler( rx_frame ); } } } else if (MSS_SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) { /* Block handling mode. */ /* Something needs to be read from FIFO */ while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { rx_frame = this_spi->hw_reg->RX_DATA; if (this_spi->slave_rx_idx < this_spi->slave_rx_size) { this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; } ++this_spi->slave_rx_idx; } } else { /* Should not happen... Just purge FIFO */ while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { rx_frame = this_spi->hw_reg->RX_DATA; } } } /***************************************************************************//** * SPI interrupt service routine. */ static void mss_spi_isr ( mss_spi_instance_t * this_spi ) { volatile uint32_t rx_frame; volatile uint32_t *this_mis = &this_spi->hw_reg->MIS; ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); if (0u != (*this_mis & RXDONE_IRQ_MASK)) { if (MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode) { /* Single frame handling mode. */ while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { rx_frame = this_spi->hw_reg->RX_DATA; if ((mss_spi_frame_rx_handler_t)0 != this_spi->frame_rx_handler) { this_spi->frame_rx_handler(rx_frame); } } } else if (MSS_SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) { /* Block handling mode. Something needs to be read from FIFO */ while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { /* Read from FIFO irrespective */ rx_frame = this_spi->hw_reg->RX_DATA; /* Write to array if required */ if (this_spi->slave_rx_idx < this_spi->slave_rx_size) { this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; } ++this_spi->slave_rx_idx; } } else { /* No slave handling in place so just purge FIFO */ while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK)) { rx_frame = this_spi->hw_reg->RX_DATA; } } this_spi->hw_reg->INT_CLEAR = RXDONE_IRQ_MASK; } /* Handle transmit. */ if (0u != (*this_mis & TXDONE_IRQ_MASK)) { if (MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode) { /* Reload slave tx frame into Tx data register. */ this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame; } else /* Must be block mode so load FIFO to the max */ { fill_slave_tx_fifo (this_spi); } this_spi->hw_reg->INT_CLEAR = TXDONE_IRQ_MASK; } /* Handle command interrupt. */ if (0u != (*this_mis & CMD_IRQ_MASK)) { read_slave_rx_fifo (this_spi); /* * Call the command handler if one exists. */ if ((mss_spi_block_rx_handler_t)0 != this_spi->cmd_handler) { (*this_spi->cmd_handler)(this_spi->slave_rx_buffer, this_spi->slave_rx_idx); fill_slave_tx_fifo(this_spi); } /* Set cmd_done to indicate it is now safe to 0 fill TX FIFO */ this_spi->cmd_done = 1u; /* Disable command interrupt until slave select becomes de-asserted to * avoid retriggering. */ this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK; this_spi->hw_reg->INT_CLEAR = CMD_IRQ_MASK; } if (0u != (*this_mis & RXOVFLOW_IRQ_MASK)) { /* * Receive overflow, not a lot we can do for this. Reset the receive * FIFO, clear the interrupt and hope it doesn't happen again... */ this_spi->hw_reg->COMMAND |= RX_FIFO_RESET_MASK; recover_from_rx_overflow(this_spi); this_spi->hw_reg->INT_CLEAR = RXOVFLOW_IRQ_MASK; } /* * Transmit underrun, try and recover by reapplying the current * slave TX FIFO data setup (if there is one). * In block mode this will probably not be very successful as we will * be out of synch with the master but the reset on SSEND will hopefully * take care of that for the next transfer. */ if (0u != (*this_mis & TXURUN_IRQ_MASK)) { this_spi->hw_reg->COMMAND |= TX_FIFO_RESET_MASK; if ( MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode ) { this_spi->hw_reg->FRAMESUP = 0u; this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1u << TXRXDFCOUNT_SHIFT); /* Reload slave tx frame into Tx data register. */ this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame; } else if (MSS_SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode) { /* Block mode so reload FIFO to the max */ this_spi->slave_tx_idx = 0u; fill_slave_tx_fifo(this_spi); } else { /* Not frame or block mode? Can't do anything here... */ } this_spi->hw_reg->INT_CLEAR = TXURUN_IRQ_MASK; } /* * Handle slave select becoming de-asserted. Only enables if * we are operating in block mode, in frame mode we do everything * in the receive and transmit interrupt handlers. */ if (0u != (*this_mis & SSEND_IRQ_MASK)) { uint32_t rx_size; read_slave_rx_fifo(this_spi); rx_size = this_spi->slave_rx_idx; /* * Re-enable command interrupt if required and clear all the response * buffer state in readiness for next response. This must be done * before reloading the TX FIFO. */ if (0 != this_spi->cmd_handler) { this_spi->cmd_done = 0u; this_spi->resp_tx_buffer = 0u; this_spi->resp_buff_size = 0u; this_spi->resp_buff_tx_idx = 0u; this_spi->hw_reg->INT_CLEAR = CMD_IRQ_MASK; this_spi->hw_reg->CONTROL2 |= C2_ENABLE_CMD_IRQ_MASK; } /* * Reset the transmit index to 0 to restart transmit at the start of the * transmit buffer in the next transaction. This also requires flushing * the Tx FIFO and refilling it with the start of Tx data buffer. */ this_spi->slave_tx_idx = 0u; this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK | (uint32_t)RX_FIFO_RESET_MASK); fill_slave_tx_fifo(this_spi); /* Prepare to receive next packet. */ this_spi->slave_rx_idx = 0u; /* * Call the receive handler if one exists. */ if ((mss_spi_block_rx_handler_t)0 != this_spi->block_rx_handler) { (*this_spi->block_rx_handler)(this_spi->slave_rx_buffer, rx_size); } this_spi->hw_reg->INT_CLEAR = SSEND_IRQ_MASK; } } /************************************************************************//*** This is the local function to recover from rx overflow. This function performs set of operations which includes storing the current state of MSS SPI registers, reset the SPI core, restore the registers. Reseting the SPI core is performed by call back function which user must implement. Driver sends information about the SPI instance in use and the handler function resets particular SPI core. Note: while configuring the SPI in master mode, user must provide the overflow handler function as one of the arguments. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to be configured. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. */ static void recover_from_rx_overflow ( mss_spi_instance_t * this_spi ) { uint32_t control_reg; uint32_t clk_gen; uint32_t frame_size; uint32_t control2; uint32_t packet_size; uint32_t cmd_size; uint32_t slave_select; /* * Read current SPI hardware block configuration. */ control_reg = this_spi->hw_reg->CONTROL; clk_gen = this_spi->hw_reg->CLK_GEN; frame_size = this_spi->hw_reg->FRAMESIZE; control2 = this_spi->hw_reg->CONTROL2; packet_size = this_spi->hw_reg->PKTSIZE; cmd_size = this_spi->hw_reg->CMDSIZE; slave_select = this_spi->hw_reg->SLAVE_SELECT; /* * Reset the SPI hardware block. */ if (this_spi == &g_mss_spi0_lo) { this_spi->hw_reg = MSS_SPI0_LO_BASE; this_spi->irqn = SPI0_PLIC; /* reset SPI0 */ this_spi->buffer_overflow_handler(0U); this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; } else if (this_spi == &g_mss_spi1_lo) { this_spi->hw_reg = MSS_SPI1_LO_BASE; this_spi->irqn = SPI1_PLIC; /* reset SPI1 */ this_spi->buffer_overflow_handler(1u); this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; } else if (this_spi == &g_mss_spi0_hi) { this_spi->hw_reg = MSS_SPI0_HI_BASE; this_spi->irqn = SPI0_PLIC; /* reset SPI0 */ this_spi->buffer_overflow_handler(0u); this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; } else if (this_spi == &g_mss_spi1_hi) { this_spi->hw_reg = MSS_SPI1_HI_BASE; this_spi->irqn = SPI1_PLIC; /* reset SPI1 */ this_spi->buffer_overflow_handler(1u); this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; } else { ASSERT(0); } /* * Restore SPI hardware block configuration. */ control_reg &= ~(uint32_t)CTRL_ENABLE_MASK; this_spi->hw_reg->CONTROL = control_reg; this_spi->hw_reg->CLK_GEN = clk_gen; this_spi->hw_reg->FRAMESIZE = frame_size; this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; this_spi->hw_reg->CONTROL2 = control2; this_spi->hw_reg->PKTSIZE = packet_size; this_spi->hw_reg->CMDSIZE = cmd_size; this_spi->hw_reg->SLAVE_SELECT = slave_select; } /***************************************************************************//** * SPI0 interrupt service routine. * Please note that the name of this ISR is defined as part of the PSE HAL * start-up code. */ uint8_t spi0_plic_IRQHandler(void) { if (g_spi_axi_pos & 0x01u) { mss_spi_isr(&g_mss_spi0_hi); } else { mss_spi_isr(&g_mss_spi0_lo); } return (uint8_t)EXT_IRQ_KEEP_ENABLED; } /***************************************************************************//** * SPI1 interrupt service routine. * Please note that the name of this ISR is defined as part of the PSE HAL * startup code. */ uint8_t spi1_plic_IRQHandler(void) { if (g_spi_axi_pos & 0x02u) { mss_spi_isr(&g_mss_spi1_hi); } else { mss_spi_isr(&g_mss_spi1_lo); } return (uint8_t)EXT_IRQ_KEEP_ENABLED; } #ifdef __cplusplus } #endif mss_spi.h000066400000000000000000001541541432224323300365700ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_spi/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC (PSE) microprocessor subsystem SPI bare metal software * driver public API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS SPI Bare Metal Driver. @section intro_sec Introduction The PolarFire SoC microprocessor subsystem (MSS) includes two serial peripheral interface (SPI) peripherals for serial communication. This driver provides a set of functions for controlling the MSS SPIs as part of a bare metal system where no operating system is available. These drivers can be adapted for use as part of an operating system, but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. @section hw_dependencies Hardware Flow Dependencies The configuration of all features of the MSS SPI peripherals is covered by this driver with the exception of the PolarFire SoC IOMUX configuration. PolarFire SoC allows multiple non-concurrent uses of some external pins through IOMUX configuration. This feature allows optimization of external pin usage by assigning external pins for use by either the microprocessor subsystem or the FPGA fabric. The MSS SPI serial signals are routed through IOMUXs to the PolarFire SoC device external pins. The MSS SPI serial signals may also be routed through IOMUXs to the PolarFire SoC FPGA fabric. The IOMUXs are configured using the PolarFire SoC MSS configurator tool. You must ensure that the MSS SPI peripherals are enabled and configured in the PolarFire SoC MSS configurator if you wish to use them. For more information on IOMUXs, refer to the IOMUX section of the PolarFire SoC microprocessor Subsystem (MSS) Users Guide. The base address, register addresses and interrupt number assignment for the MSS SPI peripherals are defined as constants in the PolarFire SoC HAL. You must ensure that the latest PolarFire SoC HAL is included in the project settings of the software tool chain used to build your project and that it is generated into your project. @section theory_op Theory of Operation The MSS SPI driver functions are grouped in following categories: * Initialization * Configure either master or slave mode * SPI Master frame transfer control * SPI Master block transfer control * SPI Slave frame transfer control * SPI Slave block transfer control Frame transfer allows the MSS SPI to write or read up to 32 bits of data in a SPI transaction. For example, a frame transfer of 12 bits might be used to read the result of ADC conversion from SPI analog to digital converter. Block transfer allows the MSS SPI to write and read several bytes in a SPI transaction. Block transfer transaction allow the data transfer in multiple of 8 bits (8, 16, 24, 32 ....). Block transfers are typically used with the byte-oriented devices such as SPI FLASH device. Initialization The MSS SPI driver is initialized through a call to the MSS_SPI_init() function. The MSS_SPI_init() function takes only one parameter, a pointer to one of two global data structures used by the driver to store state information for each MSS SPI. A pointer to these data structures is also used as first parameter to any of the driver functions to identify which MSS SPI will be used by the called function. The names of these two data structures are g_mss_spi0 and g_mss_spi1. Therefore any call to an MSS SPI driver function should be of the form MSS_SPI_function_name(&g_mss_spi0, ... ) or MSS_SPI_function_name( &g_mss_spi1, ... ). The user must reset the MSS SPI core before calling MSS_SPI_init() function. The MSS_SPI_init() function resets the specified MSS SPI hardware block and clears any pending interrupts from local interrupt controller or PLIC. The MSS_SPI_init() function must be called before any other MSS SPI driver functions can be called. Configuration An MSS SPI block can operate either as a master or slave SPI device. There are two distinct functions for configuring a MSS SPI block for master or slave operations. Master configuration The MSS_SPI_configure_master_mode() function configures the specified MSS SPI block for operations as a SPI master. It must be called once for each remote SPI slave device which the MSS SPI block will communicate with. It is used to provide the following information about each SPI slave's communication characteristics: * The SPI protocol mode * The SPI clock speed * The frame bit length * The SPI overflow handler This information is held by the driver and will be used to alter the configuration of the MSS SPI block each time a slave is selected through a call to MSS_SPI_set_slave_select(). The SPI protocol mode defines the initial state of the clock signal at the start of a transaction and which clock edge will be used to sample the data signal (Motorola SPI modes), or it defines whether the SPI block will operate in Texas Instruments (TI) synchronous serial mode or in National Semiconductor (NSC) MICROWIRE mode. The MSS_SPI_configure_master_mode() function will register the MSS_SPI_overflow_handler() function to the SPI instance, MSS_SPI_overflow_handler() function is used by driver in case of buffer overflow. Slave configuration The MSS_SPI_configure_slave_mode() function configures the specified MSS SPI block for operations as a SPI slave. It configures the following SPI communication characteristics: * The SPI protocol mode * The frame bit length * The SPI overflow handler The SPI protocol mode defines the initial state of the clock signal at the start of a transaction and which clock edge will be used to sample the data signal (Motorola SPI modes), or it defines whether the SPI block will operate in TI synchronous serial mode or in NSC MICROWIRE mode. The MSS_SPI_configure_slave_mode() function will register the MSS_SPI_overflow_handler() function to the SPI instance, MSS_SPI_overflow_handler() function is used by driver in case of buffer overflow. SPI master frame transfer control The following functions are used as part of SPI master frame transfers: - MSS_SPI_set_slave_select() - MSS_SPI_transfer_frame() - MSS_SPI_clear_slave_select() The master must first select the target slave through a call to MSS_SPI_set_slave_select(). This causes the relevant slave select line to become asserted while data is clocked out onto the SPI data line. A call is then made to MSS_SPI_transfer_frame() specifying the value of the data frame to be sent. The function MSS_SPI_clear_slave_select() can be used after the transfer is complete to prevent this slave select line from being asserted during subsequent SPI transactions. A call to this function is only required if the master is communicating with multiple slave devices. SPI master block transfer control The following functions are used as part of SPI master block transfers: - MSS_SPI_set_slave_select() - MSS_SPI_clear_slave_select() - MSS_SPI_transfer_block() The master must first select the target slave through a call to MSS_SPI_set_slave_select(). This causes the relevant slave select line to become asserted while data is clocked out onto the SPI data line. A call is then made to MSS_SPI_transfer_block (). The parameters of this function specify: - the number of bytes to be transmitted - a pointer to the buffer containing the data to be transmitted - the number of bytes to be received - a pointer to the buffer where received data will be stored The number of bytes to be transmitted can be set to zero to indicate that the transfer is purely a block read transfer. Alternatively, the number of bytes to be received can be set to zero to specify that the transfer is purely a block write transfer. The function MSS_SPI_clear_slave_select() can be used after the transfer is complete to prevent this slave select line from being asserted during subsequent SPI transactions. A call to this function is only required if the master is communicating with multiple slave devices. Note: Unlike in previous versions of this driver, the SPS bit is set in the CONTROL register in Motorola modes so that the Slave Select line remains asserted throughout block transfers. SPI slave frame transfer control The following functions are used as part of SPI slave frame transfers: - MSS_SPI_set_slave_tx_frame() - MSS_SPI_set_frame_rx_handler() The MSS_SPI_set_slave_tx_frame() function specifies the frame data that will be returned to the SPI master. The frame data specified through this function is the value that will be read over the SPI bus by the remote SPI master when it initiates a transaction. A call to MSS_SPI_set_slave_tx_frame() is only required if the MSS SPI slave is the target of SPI read transactions, i.e. if data is meant to be read from the PolarFire SoC device over SPI. The MSS_SPI_set_frame_rx_handler() function specifies the receive handler function that will called when a frame of data has been received by the MSS SPI when it is configured as a slave. The receive handler function specified through this call will process the frame data written, over the SPI bus, to the MSS SPI slave by the remote SPI master. The receive handler function must be implemented as part of the application. It is only required if the MSS SPI slave is the target of SPI frame write transactions. Successive master writes need to take into account the time taken to execute the receive handler if the interface is to work reliably. SPI slave block transfer control The following functions are used as part of SPI slave block transfers: - MSS_SPI_set_slave_block_buffers() - MSS_SPI_set_cmd_handler() - MSS_SPI_set_cmd_response() The MSS_SPI_set_slave_block_buffers() function is used to configure a MSS SPI slave for block transfer operations. It specifies: - The buffer containing the data that will be returned to the remote SPI master - The buffer where data received from the remote SPI master will be stored - The handler function that will be called after the receive buffer has been filled The MSS_SPI_set_cmd_handler() function specifies a command handler function that will be called by the driver once a specific number of bytes has been received after the SPI chip select signal becoming active. The number of bytes making up the command part of the transaction is specified as part of the parameters to MSS_SPI_set_cmd_handler(). The command handler function is implemented as part of the application making use of the SPI driver and would typically call the MSS_SPI_set_cmd_response() function. The MSS_SPI_set_cmd_response() function specifies the data that will be returned to the master. Typically the MSS_SPI_set_slave_block_buffers() will have been called as part of the system initialization to specify the data sent to the master while the command bytes are being received. The transmit buffer specified through the call to MSS_SPI_set_slave_block_buffers() would also typically include one or more bytes allowing for the turn around time required for the command handler function to execute and call MSS_SPI_set_cmd_response(). *//*=========================================================================*/ #ifndef MSS_SPI_H_ #define MSS_SPI_H_ #include #include #include "mss_plic.h" /*Register map of the PSE MSS SPI*/ typedef struct { volatile uint32_t CONTROL; volatile uint32_t FRAMESIZE;/* SPEC 2.13 , removed TXRXDF_SIZE;*/ volatile uint32_t STATUS; volatile uint32_t INT_CLEAR; volatile uint32_t RX_DATA; volatile uint32_t TX_DATA; volatile uint32_t CLK_GEN; volatile uint32_t SLAVE_SELECT; volatile uint32_t MIS; volatile uint32_t RIS; volatile uint32_t CONTROL2; volatile uint32_t COMMAND; volatile uint32_t PKTSIZE; volatile uint32_t CMDSIZE; volatile uint32_t HWSTATUS; volatile uint32_t STAT8; volatile uint32_t CTRL0; volatile uint32_t CTRL1; volatile uint32_t CTRL2; volatile uint32_t CTRL3; volatile uint32_t FRAMESUP; /* SPEC 2.13 */ } SPI_TypeDef; #define SPI0_LO_BASE 0x20108000u #define SPI1_LO_BASE 0x20109000u #define SPI0_HI_BASE 0x28108000u #define SPI1_HI_BASE 0x28109000u #define MSS_SPI0_LO_BASE ((SPI_TypeDef *) SPI0_LO_BASE) #define MSS_SPI1_LO_BASE ((SPI_TypeDef *) SPI1_LO_BASE) #define MSS_SPI0_HI_BASE ((SPI_TypeDef *) SPI0_HI_BASE) #define MSS_SPI1_HI_BASE ((SPI_TypeDef *) SPI1_HI_BASE) #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** This defines the function prototype that must be followed by MSS SPI slave frame receive handler functions. These functions are registered with the MSS SPI driver through the MSS_SPI_set_frame_rx_handler () function. Declaring and Implementing Slave Frame Receive Handler Functions: Slave frame receive handler functions should follow the following prototype: void slave_frame_receive_handler ( uint32_t rx_frame ); The actual name of the receive handler is unimportant. You can use any name of your choice for the receive frame handler. The rx_frame parameter will contain the value of the received frame. */ typedef void (*mss_spi_frame_rx_handler_t)( uint32_t rx_frame ); /***************************************************************************//** This defines the function prototype that must be followed by MSS SPI slave block receive handler functions. These functions are registered with the MSS SPI driver through the MSS_SPI_set_slave_block_buffers() function. Declaring and Implementing Slave Block Receive Handler Functions Slave block receive handler functions should follow the following prototype: void mss_spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); The actual name of the receive handler is unimportant. You can use any name of your choice for the receive frame handler. The rx_buff parameter will contain a pointer to the start of the received block. The rx_size parameter indicates the number of bytes in the received block. */ typedef void (*mss_spi_block_rx_handler_t)(uint8_t * rx_buff, uint32_t rx_size); /**************************************************************************//** This defines the function prototype that must be used by the MSS SPI init functions. This handler functions is registered with the MSS SPI driver through the MSS_SPI_init() function. Declaring and Implementing Overflow handler functions The buffer overflow handler functions must use the following prototype void mss_spi0_overflow_handler(uint8_t mss_spi_core); The actual name of the overflow handler is not important. User can use any name of choice. This function is passed as a argument to the MSS_SPI_init(), which registers overflow handler to the MSS SPI instance.The parameter passed with the function informs the handler function about which SPI core to reset.This variable can later be used by the driver to recover from buffer overflow situations. */ typedef void (*mss_spi_oveflow_handler_t)(uint8_t mss_spi_core); /***************************************************************************//** This enumeration is used to define the settings for the SPI protocol mode bits which select the different modes of operation for the MSS SPI. It is used as a parameter to the MSS_SPI_configure_master_mode() and MSS_SPI_configure_slave_mode() functions. - MSS_SPI_MODE0: Clock starts low, data read on clock's rising edge, data changes on falling edge. - MSS_SPI_MODE1: Clock starts low, data read on clock's falling edge, data changes on rising edge. - MSS_SPI_MODE2: Clock starts high, data read on clock's falling edge, data changes on rising edge. - MSS_SPI_MODE3: Clock starts high, data read on clock's rising edge, data changes on falling edge. - MSS_TI_MODE: TI synchronous serial mode. Slave select is pulsed at start of transfer. - MSS_NSC_MODE: NSC Microwire mode. */ typedef enum __mss_spi_protocol_mode_t { MSS_SPI_MODE0 = 0x00000000, MSS_SPI_TI_MODE = 0x01000004, MSS_SPI_NSC_MODE = 0x00000008, MSS_SPI_MODE2 = 0x01000000, MSS_SPI_MODE1 = 0x02000000, MSS_SPI_MODE3 = 0x03000000 } mss_spi_protocol_mode_t; /***************************************************************************//** This enumeration is used to select a specific SPI slave device (0 to 7). It is used as a parameter to the MSS_SPI_configure_master_mode(), MSS_SPI_set_slave_select() and MSS_SPI_clear_slave_select () functions. */ typedef enum __mss_spi_slave_t { MSS_SPI_SLAVE_0 = 0, MSS_SPI_SLAVE_1 = 1, MSS_SPI_SLAVE_2 = 2, MSS_SPI_SLAVE_3 = 3, MSS_SPI_SLAVE_4 = 4, MSS_SPI_SLAVE_5 = 5, MSS_SPI_SLAVE_6 = 6, MSS_SPI_SLAVE_7 = 7, MSS_SPI_MAX_NB_OF_SLAVES = 8 } mss_spi_slave_t; /***************************************************************************//** This constant defines a frame size of 8 bits when configuring an MSS SPI to perform block transfer data transactions. It must be used as the value for the frame_bit_length parameter of function MSS_SPI_configure_master_mode() when performing block transfers between the MSS SPI master and the target SPI slave. It must also be used as the value for the frame_bit_length parameter of MSS_SPI_configure_slave_mode() when performing block transfers between the MSS SPI slave and the remote SPI master. */ #define MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE 8u /***************************************************************************//** The mss_spi_slave_cfg_t holds the MSS SPI configuration that must be used to communicate with a specific SPI slave. */ typedef struct __mss_spi_slave_cfg_t { uint32_t ctrl_reg; uint8_t txrxdf_size_reg; uint8_t clk_gen; } mss_spi_slave_cfg_t; /***************************************************************************//** This enumeration is used to indicate the current slave mode transfer type so that we are not relying on buffer comparisons to dictate the logic of the driver. */ typedef enum __mss_spi_sxfer_mode_t { MSS_SPI_SLAVE_XFER_NONE = 0, /* Not configured yet */ MSS_SPI_SLAVE_XFER_BLOCK = 1, /* Block transfers, with SSEND delimiting end of block */ MSS_SPI_SLAVE_XFER_FRAME = 2 /* Single frame transfers */ } mss_spi_sxfer_mode_t; /***************************************************************************//** There is one instance of this structure for each of the microprocessor subsystem's SPIs. Instances of this structure are used to identify a specific SPI. A pointer to an instance of the mss_spi_instance_t structure is passed as the first parameter to MSS SPI driver functions to identify which SPI should perform the requested operation. */ typedef struct __mss_spi_instance_t { /* SPI hardware identification definitions . */ SPI_TypeDef * hw_reg; /*!< Pointer to SPI registers. */ PLIC_IRQn_Type irqn; /*!< SPI's PLIC interrupt number. */ /* Internal transmit state: */ const uint8_t * slave_tx_buffer; /*!< Pointer to slave transmit buffer. */ uint32_t slave_tx_size; /*!< Size of slave transmit buffer. */ uint32_t slave_tx_idx; /*!< Current index into slave transmit buffer. */ /* Slave command response buffer: */ const uint8_t * resp_tx_buffer; uint32_t resp_buff_size; uint32_t resp_buff_tx_idx; mss_spi_block_rx_handler_t cmd_handler; uint32_t cmd_done; /*!< Flag which indicates response has been set up and it is safe to pad with 0s once the response is sent. */ /* Internal receive state: */ uint8_t * slave_rx_buffer; /*!< Pointer to buffer where data received by a slave will be stored. */ uint32_t slave_rx_size; /*!< Slave receive buffer siSze. */ uint32_t slave_rx_idx; /*!< Current index into slave receive buffer. */ /* Configuration for each target slave. */ mss_spi_slave_cfg_t slaves_cfg[MSS_SPI_MAX_NB_OF_SLAVES]; /* Slave received frame handler: */ mss_spi_frame_rx_handler_t frame_rx_handler; /*!< Pointer to function that will be called when a frame is received when the SPI block is configured as slave. */ uint32_t slave_tx_frame; /*!< Value of the data frame that will be transmitted when the SPI block is configured as slave. */ /* Slave block rx handler: */ mss_spi_block_rx_handler_t block_rx_handler; /*!< Pointer to the function that will be called when a data block has been received. */ /* How we are expecting to deal with slave transfers */ mss_spi_sxfer_mode_t slave_xfer_mode; /*!< Current slave mode transfer configuration. */ /* MSS SPI reset handler*/ mss_spi_oveflow_handler_t buffer_overflow_handler; } mss_spi_instance_t; /***************************************************************************//** This instance of mss_spi_instance_t holds all data related to the operations performed by the MSS SPI. The function MSS_SPI_init() initializes this structure. A pointer to g_mss_spi0_lo is passed as the first parameter to MSS SPI driver functions to indicate that SPI0 should perform the requested operation. */ extern mss_spi_instance_t g_mss_spi0_lo; extern mss_spi_instance_t g_mss_spi1_lo; extern mss_spi_instance_t g_mss_spi0_hi; extern mss_spi_instance_t g_mss_spi1_hi; /***************************************************************************//** The MSS_SPI_init() function initializes and hardware and data structures of one of the MSS SPIs. The MSS_SPI_init() function must be called before any other MSS SPI driver functions can be called. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to be initialized. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. Example: @code MSS_SPI_init(&g_mss_spi0); @endcode */ void MSS_SPI_init ( mss_spi_instance_t * this_spi ); /***************************************************************************//** The MSS_SPI_configure_slave_mode() function configure a MSS SPI block for operations as a slave SPI device. It configures the SPI hardware with the selected SPI protocol mode and frame size for communication with a specific SPI master. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to be configured. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param protocol_mode This parameter is used to specify the SPI operating mode. Allowed values are: - MSS_SPI_MODE0 - MSS_SPI_MODE1 - MSS_SPI_MODE2 - MSS_SPI_MODE3 - MSS_TI_MODE - MSS_NSC_MODE @param frame_bit_length Number of bits making up the frame. You must use the MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE constant as the value for frame_bit_length when configuring the MSS SPI master for block transfer transactions with the target SPI slave. @param recieve_buffer_overflow_handler The recieve_buffer_overflow_handler parameter is a pointer to the callback function which is called when rx overflow occurs. The MSS_SPI_configure_master_mode() function registers user implemented receive buffer overflow handler to the mss_spi_instance_t structure. This registered handler is used by driver to recover from buffer overflow situation. Note: There is no restriction in naming the buffer overflow handler, User can name as per wish. Example: @code MSS_SPI_init(&g_mss_spi0); MSS_SPI_configure_slave_mode ( &g_mss_spi0, MSS_SPI_MODE2, MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE, mss_spi_overflow_handler ); @endcode */ void MSS_SPI_configure_slave_mode ( mss_spi_instance_t * this_spi, mss_spi_protocol_mode_t protocol_mode, uint8_t frame_bit_length, mss_spi_oveflow_handler_t recieve_buffer_overflow_handler ); /***************************************************************************//** The MSS_SPI_configure_master_mode() function configures the protocol mode, serial clock speed and frame size for a specific target SPI slave device. It is used when the MSS SPI hardware block is used as a SPI master. This function must be called once for each target SPI slave which the MSS SPI master is wishes to communicate with. The SPI master hardware will be configured with the configuration specified by this function during calls to MSS_SPI_set_slave_select(). @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to be configured. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param slave The slave parameter is used to identify a target SPI slave. The driver will hold the MSS SPI master configuration required to communicate with this slave, as specified by the other function parameters. Allowed values are: * MSS_SPI_SLAVE_0 * MSS_SPI_SLAVE_1 * MSS_SPI_SLAVE_2 * MSS_SPI_SLAVE_3 * MSS_SPI_SLAVE_4 * MSS_SPI_SLAVE_5 * MSS_SPI_SLAVE_6 * MSS_SPI_SLAVE_7 @param protocol_mode This parameter is used to specify the SPI operating mode. Allowed values are: * MSS_SPI_MODE0 * MSS_SPI_MODE1 * MSS_SPI_MODE2 * MSS_SPI_MODE3 * MSS_SPI_TI_MODE * MSS_SPI_NSC_MODE @param clk_div SPI clock divider value used to generate serial interface clock signal from PCLK. Allowed values are even numbers in the range from 2 to 512. The PCLK frequency is divided by the specified value to give the serial interface clock frequency. @param frame_bit_length Number of bits making up the frame. The maximum frame length is 32 bits. You must use the MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE constant as the value for frame_bit_length when configuring the MSS SPI master for block transfer transactions with the target SPI slave. @param recieve_buffer_overflow_handler The recieve_buffer_overflow_handler parameter is a pointer to the callback function receive buffer overflow handler. User must implement a local function to handle buffer overflow. The MSS_SPI_configure_master_mode() function registers user implemented receive buffer overflow handler to the mss_spi_instance_t structure. This registered handler is used by driver to prevent in state of buffer overflow. Note: There is no limitation in naming the buffer overflow handler, User can name as per wish . Example: @code MSS_SPI_init(&g_mss_spi0); MSS_SPI_configure_master_mode ( &g_mss_spi0, MSS_SPI_SLAVE_0, MSS_SPI_MODE2, 64u, 12, mss_spi_overflow_handler ); MSS_SPI_configure_master_mode ( &g_mss_spi0, MSS_SPI_SLAVE_1, MSS_SPI_TI_MODE, 128u, MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE, mss_spi_overflow_handler ); MSS_SPI_set_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); MSS_SPI_transfer_frame(&g_mss_spi0, 0xaaa); MSS_SPI_clear_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); MSS_SPI_set_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_1); MSS_SPI_transfer_frame(&g_mss_spi0, 0x55); MSS_SPI_clear_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_1); @endcode */ void MSS_SPI_configure_master_mode ( mss_spi_instance_t * this_spi, mss_spi_slave_t slave, mss_spi_protocol_mode_t protocol_mode, uint32_t clk_div, uint8_t frame_bit_length, mss_spi_oveflow_handler_t recieve_buffer_overflow_handler ); /*============================================================================== * Master functions *============================================================================*/ /***************************************************************************//** The MSS_SPI_set_slave_select() function is used by a MSS SPI master to select a specific slave. This function causes the relevant slave select signal to be asserted while data is clocked out onto the SPI data line. This function also configures the MSS SPI master with the configuration settings necessary for communication with the specified slave. These configuration settings must be specified in a previous call to the MSS_SPI_configure_master_mode() function. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param slave The slave parameter is one of the mss_spi_slave_t enumerated constants identifying the slave. Example: @code const uint8_t frame_size = 25; const uint32_t master_tx_frame = 0x0100A0E1; MSS_SPI_init(&g_mss_spi0); MSS_SPI_configure_master_mode ( &g_mss_spi0, MSS_SPI_SLAVE_0, MSS_SPI_MODE1, 256u, frame_size, mss_spi_overflow_handler ); MSS_SPI_set_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); MSS_SPI_transfer_frame(&g_mss_spi0, master_tx_frame); MSS_SPI_clear_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); @endcode */ void MSS_SPI_set_slave_select ( mss_spi_instance_t * this_spi, mss_spi_slave_t slave ); /***************************************************************************//** The MSS_SPI_clear_slave_select() function is used by a MSS SPI Master to deselect a specific slave. This function causes the relevant slave select signal to be de-asserted. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param slave The slave parameter is one of mss_spi_slave_t enumerated constants identifying a slave. Example: @code const uint8_t frame_size = 25; const uint32_t master_tx_frame = 0x0100A0E1; MSS_SPI_init(&g_mss_spi0); MSS_SPI_configure_master_mode ( &g_mss_spi0, MSS_SPI_SLAVE_0, MSS_SPI_MODE1, 256u, frame_size, mss_spi_overflow_handler ); MSS_SPI_set_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); MSS_SPI_transfer_frame(&g_mss_spi0, master_tx_frame); MSS_SPI_clear_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); @endcode */ void MSS_SPI_clear_slave_select ( mss_spi_instance_t * this_spi, mss_spi_slave_t slave ); /***************************************************************************//** The MSS_SPI_disable() function is used to temporarily disable a MSS SPI hardware block. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. Example: @code uint32_t transfer_size; uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; transfer_size = sizeof(tx_buffer); MSS_SPI_disable(&g_mss_spi0); MSS_SPI_set_transfer_byte_count(&g_mss_spi0, transfer_size); @endcode */ void MSS_SPI_disable ( mss_spi_instance_t * this_spi ); /***************************************************************************//** The MSS_SPI_enable() function is used to re-enable a MSS SPI hardware block after it was disabled using the SPI_disable() function. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. Example: @code uint32_t transfer_size; uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; transfer_size = sizeof(tx_buffer); MSS_SPI_disable(&g_mss_spi0); MSS_SPI_set_transfer_byte_count(&g_mss_spi0, transfer_size); MSS_SPI_enable(&g_mss_spi0); @endcode */ void MSS_SPI_enable ( mss_spi_instance_t * this_spi ); /***************************************************************************//** The MSS_SPI_transfer_frame() function is used by a MSS SPI master to transmit and receive a frame up to 32 bits long. This function is typically used for transactions with a SPI slave where the number of transmit and receive bits is not divisible by 8. Note: The maximum frame size in NSC Microwire mode is 24 bits organized as an 8 bit command followed by up to 16 bits of data . @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param tx_bits The tx_bits parameter is a 32 bits word containing the data that will be transmitted. Note: The bit length of the value to be transmitted to the slave must be specified as the frame_bit_length parameter in a previous call to the MSS_SPI_configure_master_mode() function. @return This function returns a 32 bits word containing the value that is received from the slave. Example: @code const uint8_t frame_size = 25; const uint32_t master_tx_frame = 0x0100A0E1; uint32_t master_rx; MSS_SPI_init(&g_mss_spi0); MSS_SPI_configure_master_mode ( &g_mss_spi0, MSS_SPI_SLAVE_0, MSS_SPI_MODE1, 256u, frame_size, mss_spi_overflow_handler ); MSS_SPI_set_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); master_rx = MSS_SPI_transfer_frame(&g_mss_spi0, master_tx_frame); MSS_SPI_clear_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); @endcode */ uint32_t MSS_SPI_transfer_frame ( mss_spi_instance_t * this_spi, uint32_t tx_bits ); /***************************************************************************//** The MSS_SPI_transfer_block() function is used by MSS SPI masters to transmit and receive blocks of data organized as a specified number of bytes. It can be used for: * Writing a data block to a slave * Reading a data block from a slave * Sending a command to a slave followed by reading the response to the command in a single SPI transaction. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param cmd_buffer The cmd_buffer parameter is a pointer to the buffer containing the data that will be sent by the master from the beginning of the transfer. @param cmd_byte_size The cmd_byte_size parameter specifies the number of bytes contained in cmd_buffer that will be sent. A value of 0 indicates that no data needs to be sent to the slave. @param rd_buffer The rd_buffer parameter is a pointer to the buffer where the data received from the slave after the command has been sent will be stored. @param rd_byte_size The rd_byte_size parameter specifies the number of bytes to be received from the slave and stored in the rd_buffer. A value of 0 indicates that no data is to be read from the slave. Polled write transfer example: @code uint8_t master_tx_buffer[MASTER_TX_BUFFER] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A }; MSS_SPI_init(&g_mss_spi0); MSS_SPI_configure_master_mode ( &g_mss_spi0, MSS_SPI_SLAVE_0, MSS_SPI_MODE1, 256u, MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE, mss_spi_overflow_handler ); MSS_SPI_set_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); MSS_SPI_transfer_block ( &g_mss_spi0, master_tx_buffer, sizeof(master_tx_buffer), 0, 0 ); MSS_SPI_clear_slave_select(&g_mss_spi0, MSS_SPI_SLAVE_0); @endcode */ void MSS_SPI_transfer_block ( mss_spi_instance_t * this_spi, const uint8_t cmd_buffer[], uint32_t cmd_byte_size, uint8_t rd_buffer[], uint32_t rd_byte_size ); /*============================================================================== * Slave functions *============================================================================*/ /***************************************************************************//** The MSS_SPI_set_frame_rx_handler() function is used by MSS SPI slaves to specify the receive handler function that will be called by the MSS SPI driver interrupt handler when a a frame of data is received by the MSS SPI slave. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param rx_handler The rx_handler parameter is a pointer to the frame receive handler that must be called when a frame is received by the MSS SPI slave. Example: @code uint32_t g_slave_rx_frame = 0; void slave_frame_handler(uint32_t rx_frame) { g_slave_rx_frame = rx_frame; } int setup_slave(void) { const uint16_t frame_size = 25; MSS_SPI_init(&g_mss_spi1); MSS_SPI_configure_slave_mode ( &g_mss_spi0, MSS_SPI_MODE2, frame_size, mss_spi_overflow_handler ); MSS_SPI_set_frame_rx_handler(&g_mss_spi1, slave_frame_handler); } @endcode */ void MSS_SPI_set_frame_rx_handler ( mss_spi_instance_t * this_spi, mss_spi_frame_rx_handler_t rx_handler ); /***************************************************************************//** The MSS_SPI_set_slave_tx_frame() function is used by MSS SPI slaves to specify the frame that will be transmitted when a transaction is initiated by the SPI master. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param frame_value The frame_value parameter contains the value of the frame to be sent to the master. Note: The bit length of the value to be transmitted to the master must be specified as the frame_bit_length parameter in a previous call to the MSS_SPI_configure_slave_mode() function. Example: @code const uint16_t frame_size = 25; const uint32_t slave_tx_frame = 0x0110F761; uint32_t master_rx; MSS_SPI_init(&g_mss_spi1); MSS_SPI_configure_slave_mode ( &g_mss_spi0, MSS_SPI_MODE2, frame_size, mss_spi_overflow_handler ); MSS_SPI_set_slave_tx_frame(&g_mss_spi1, slave_tx_frame); @endcode */ void MSS_SPI_set_slave_tx_frame ( mss_spi_instance_t * this_spi, uint32_t frame_value ); /***************************************************************************//** The MSS_SPI_set_slave_block_buffers() function is used to configure an MSS SPI slave for block transfer operations. It specifies one or more of the following: - The data that will be transmitted when accessed by a master. - The buffer where data received from a master will be stored. - The handler function that must be called after the receive buffer has been filled. - The maximum number of bytes that the slave will accept from the master (excess bytes are discarded). These parameters allow the following use cases: - Slave performing an action after receiving a block of data from a master containing a command. The action will be performed by the receive handler based on the content of the receive data buffer. - Slave returning a block of data to the master. The type of information is always the same but the actual values change over time. For example, returning the voltage of a predefined set of analog inputs. - Slave returning data based on a command contained in the first part of the SPI transaction. For example, reading the voltage of the analog input specified by the first data byte by the master. This is achieved by using the MSS_SPI_set_slave_block_buffers() function in conjunction with functions MSS_SPI_set_cmd_handler() and MSS_SPI_set_cmd_response(). Please refer to the MSS_SPI_set_cmd_handler() function description for details of this use case. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block to operate on. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param tx_buffer The tx_buffer parameter is a pointer to a buffer containing the data that will be sent to the master. This parameter can be set to 0 if the MSS SPI slave is not intended to be the target of SPI read. @param tx_buff_size The tx_buff_size parameter specifies the number of bytes that will be transmitted by the SPI slave. It is the number of bytes contained in the tx_buffer. This parameter can be set to 0 if the MSS SPI slave is not intended to be the target of SPI read transactions. @param rx_buffer The rx_buffer parameter is a pointer to the buffer where data received from the master will be stored. This parameter can be set to 0 if the MSS SPI slave is not intended to be the target of SPI write or write-read transactions. @param rx_buff_size The rx_buff_size parameter specifies the size of the receive buffer. It is also the number of bytes that must be received before the receive handler is called, if a receive handler is specified using the block_rx_handler parameter. This parameter can be set to 0 if the MSS SPI slave is not intended to be the target of SPI write or write-read transactions. @param block_rx_handler The block_rx_handler parameter is a pointer to a function that will be called when the receive buffer has been filled. This parameter can be set to 0 if the MSS SPI slave is not intended to be the target of SPI write or write-read transactions. Slave performing operation based on master command: In this example the SPI slave is configured to receive 10 bytes of data or command from the SPI master and process the data received. @code uint32_t nb_of_rx_handler_calls = 0; void spi1_block_rx_handler_b ( uint8_t * rx_buff, uint16_t rx_size ) { ++nb_of_rx_handler_calls; } void setup_slave(void) { uint8_t slave_rx_buffer[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; MSS_SPI_init(&g_mss_spi1); MSS_SPI_configure_slave_mode ( &g_mss_spi0, MSS_SPI_MODE2, MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE, mss_spi_overflow_handler ); MSS_SPI_set_slave_block_buffers ( &g_mss_spi1, 0, 0, slave_rx_buffer, sizeof(slave_rx_buffer), spi1_block_rx_handler_b ); } @endcode */ void MSS_SPI_set_slave_block_buffers ( mss_spi_instance_t * this_spi, const uint8_t * tx_buffer, uint32_t tx_buff_size, uint8_t * rx_buffer, uint32_t rx_buff_size, mss_spi_block_rx_handler_t spi_block_rx_handler ); /***************************************************************************//** The MSS_SPI_set_cmd_handler() function specifies a command handler function that will be called when the number of bytes received reaches the command size specified as parameter. This function is used by SPI slaves performing block transfers. Its purpose is to allow a SPI slave to decide the data that will be returned to the master while a SPI transaction is taking place. Typically, one of more command bytes are sent by the master to request some specific data. The slave interprets the command byte(s) while one or more turn-around bytes are transmitted. The slave adjusts its transmit data buffer based on the command during the turnaround time. The diagram below provides an example of the use of this function where the SPI slave returns data bytes D0 to D6 based on the value of a command. The 3 bytes long command is made up of a command opcode byte followed by an address byte followed by a size byte. The cmd_handler() function specified through an earlier call to MSS_SPI_set_cmd_handler() is called by the SPI driver once the third byte is received. The cmd_handler() function interprets the command bytes and calls MSS_SPI_set_cmd_response() to set the SPI slave's response transmit buffer with the data to be transmitted after the turnaround bytes (T0 to T3). The number of turnaround bytes must be sufficient to give enough time for the cmd_handler() to execute. The number of turnaround bytes is specified by the protocol used on top of the SPI transport layer, so both the master and slave must adhere to this. t0 t1 t2 t3 t4 | | | | | |------------------------------------------------------------------| | COMMAND | TURN-AROUND | DATA | |------------------------------------------------------------------| | C | A | S | T0 | T1 | T2 | T4 | D0 | D1 | D2 | D3 | D4 | D5 | D6 | |------------------------------------------------------------------| | | --> cmd_handler() called here. | | --> MSS_SPI_set_cmd_response() called here by implementation of cmd_handler() to set the data that will be transmitted by the SPI slave. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block used. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param cmd_handler The cmd_handler parameter is a pointer to a function with prototype: void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); It specifies the function that will be called when the number of bytes specified by parameter cmd_size has been received. Passing in a null pointer for this disables the command handler and the associated interrupt. @param cmd_size The cmd_size parameter specifies the number of bytes that must be received before the command handler function specified by cmd_handler is called. The example below demonstrates how to configure SPI1 to implement the protocol given as example in the diagram above. The configure_slave() function configures SPI1. It sets the receive and transmit buffers. The transmit buffer specified through the call to MSS_SPI_set_slave_block_buffers() specifies the data that will be returned to the master in bytes between t0 and t3. These are the bytes that will be sent to the master while the master transmits the command and dummy bytes. The spi1_slave_cmd_handler() function will be called by the driver at time t1 after the 3 command bytes have been received. The spi1_block_rx_handler() function will be called by the driver at time t4 when the transaction completes when the slave select signal becomes de-asserted. @code #define COMMAND_SIZE 3 #define NB_OF_DUMMY_BYTES 4 #define MAX_TRANSACTION_SIZE 16 uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; void configure_slave(void) { MSS_SPI_init(&g_mss_spi1); MSS_SPI_configure_slave_mode ( &g_mss_spi1, MSS_SPI_MODE1, MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE, mss_spi_overflow_handler ); MSS_SPI_set_slave_block_buffers ( &g_mss_spi1, slave_tx_buffer, COMMAND_SIZE + NB_OF_DUMMY_BYTES, slave_rx_buffer, sizeof(slave_rx_buffer), spi1_block_rx_handler ); MSS_SPI_set_cmd_handler ( &g_mss_spi1, spi1_slave_cmd_handler, COMMAND_SIZE ); } void spi1_slave_cmd_handler ( uint8_t * rx_buff, uint32_t rx_size ) { uint8_t command; uint8_t address; uint8_t size; uint8_t * p_response; uint32_t response_size; command = rx_buff[0]; address = rx_buff[1]; size = rx_buff[2]; p_response = get_response_data(command, address, size, &response_size); MSS_SPI_set_cmd_response(&g_mss_spi1, p_response, response_size); } void spi1_block_rx_handler ( uint8_t * rx_buff, uint32_t rx_size ) { process_rx_data(rx_buff, rx_size); } @endcode */ void MSS_SPI_set_cmd_handler ( mss_spi_instance_t * this_spi, mss_spi_block_rx_handler_t cmd_handler, uint32_t cmd_size ); /***************************************************************************//** The MSS_SPI_set_cmd_response() function specifies the data that will be returned to the master, when a command has been received by the slave. This function is called as part of the MSS_SPI_set_cmd_handler(). See the description of MSS_SPI_set_cmd_handler() for more details. @param this_spi The this_spi parameter is a pointer to an mss_spi_instance_t structure identifying the MSS SPI hardware block used. There are two such data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 or g_mss_spi1 global data structure defined within the SPI driver. @param resp_tx_buffer The resp_tx_buffer parameter is a pointer to the buffer containing the data that must be returned to the host in the data phase of a SPI command oriented transaction. @param resp_buff_size The resp_buff_size parameter specifies the size of the buffer pointed to by the resp_tx_buffer parameter. */ void MSS_SPI_set_cmd_response ( mss_spi_instance_t * this_spi, const uint8_t * resp_tx_buffer, uint32_t resp_buff_size ); #ifdef __cplusplus } #endif #endif /* MSS_SPI_H_*/ mss_sys_services/000077500000000000000000000000001432224323300366565ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_sys_services.c000066400000000000000000001661631432224323300424420ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_sys_services/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PSE microcontroller subsystem System Services bare metal driver * implementation. * * SVN $Revision$ * SVN $Date$ */ #include "drivers/mss/mss_sys_services/mss_sys_services.h" #include "drivers/mss/mss_sys_services/mss_sys_services_regs.h" #include "mss_hal.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif /******************************************************************************* * Null buffer constant definition */ #define NULL_BUFFER (( uint8_t* ) 0) /*-------------------------------------------------------------------------*//** System service response offset ============================ The following constants are used to specify the offset in the mailbox where the service response is written by the system controller after service execution. */ #define MSS_SYS_COMMON_RET_OFFSET 0u #define MSS_SYS_DIGITAL_SIG_RET_OFFSET 48u #define MSS_SYS_SECURE_NVM_READ_RET_OFFSET 16u #define MSS_SYS_PUF_EMULATION_RET_OFFSET 20u #define MSS_SYS_DIGEST_CHECK_RET_OFFSET 4u #define MSS_SYS_GENERATE_OTP_RET_OFFSET 20u /******************************************************************************* * Global variables declarations */ volatile uint8_t g_message_received = 0u; uint8_t g_service_mode = 0u; uint8_t* gp_int_service_response; uint16_t g_int_service_response_size; uint16_t g_int_service_response_offset; volatile uint8_t g_message_interrupt_counter = 0u; /******************************************************************************* * Callback handler function declaration */ mss_sys_service_handler_t mss_sys_interrupt_handler; /******************************************************************************* * Local function declarations. */ static uint16_t execute_ss_polling_mode ( uint8_t cmd_opcode, uint8_t* cmd_data, uint16_t cmd_data_size, uint8_t* p_response, uint16_t response_size, uint16_t mb_offset, uint16_t response_offset ); static uint16_t execute_ss_interrupt_mode ( uint8_t cmd_opcode, uint8_t* cmd_data, uint16_t cmd_data_size, uint8_t* p_response, uint16_t response_size, uint16_t mb_offset, uint16_t response_offset ); static uint16_t request_system_service ( uint8_t cmd_opcode, uint8_t* cmd_data, uint16_t cmd_data_size, uint8_t* p_response, uint16_t response_size, uint16_t mb_offset, uint16_t response_offset ); /*----------------------------------------------------------------------------- Public Functions -----------------------------------------------------------------------------*/ /***************************************************************************//** * MSS_SYS_get_serial_number() * See "mss_sysservices.h" for details of how to use this function. */ void MSS_SYS_select_service_mode ( uint8_t sys_service_mode, mss_sys_service_handler_t mss_sys_service_interrupt_handler ) { g_service_mode = sys_service_mode; mss_sys_interrupt_handler = mss_sys_service_interrupt_handler; } /***************************************************************************//** * MSS_SYS_get_serial_number() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_get_serial_number ( uint8_t * p_serial_number, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_SERIAL_NUMBER_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_serial_number, (uint16_t)MSS_SYS_SERIAL_NUMBER_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_SERIAL_NUMBER_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_serial_number, (uint16_t)MSS_SYS_SERIAL_NUMBER_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_get_user_code() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_get_user_code ( uint8_t * p_user_code, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_USERCODE_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_user_code, (uint16_t)MSS_SYS_USERCODE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_USERCODE_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_user_code, (uint16_t)MSS_SYS_USERCODE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_get_design_info() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_get_design_info ( uint8_t * p_design_info, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_DESIGN_INFO_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_design_info, (uint16_t)MSS_SYS_DESIGN_INFO_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_DESIGN_INFO_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_design_info, (uint16_t)MSS_SYS_DESIGN_INFO_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_get_device_certificate() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_get_device_certificate ( uint8_t * p_device_certificate, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_DEVICE_CERTIFICATE_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_device_certificate, (uint16_t)MSS_SYS_DEVICE_CERTIFICATE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_DEVICE_CERTIFICATE_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_device_certificate, (uint16_t)MSS_SYS_DEVICE_CERTIFICATE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_read_digest() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_read_digest ( uint8_t * p_digest, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_READ_DIGEST_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_digest, (uint16_t)MSS_SYS_READ_DIGEST_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_READ_DIGEST_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_digest, (uint16_t)MSS_SYS_READ_DIGEST_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_query_security() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_query_security ( uint8_t * p_security_locks, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t idx=0; uint8_t buf[36] = {0}; /*Actual QUERY_SECURITY_RESP_LEN is 9 but CoreSysService_PF IP needs number of words instead of number of bytes to be written to or read from MailBox*/ if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_QUERY_SECURITY_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, buf, (uint16_t)(MSS_SYS_QUERY_SECURITY_RESP_LEN + 3u), mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_QUERY_SECURITY_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, buf, (uint16_t)(MSS_SYS_QUERY_SECURITY_RESP_LEN + 3u), mb_offset, MSS_SYS_COMMON_RET_OFFSET); } for (idx = 0u; idx < MSS_SYS_QUERY_SECURITY_RESP_LEN; idx++) { *(p_security_locks + idx) = buf[idx]; } return status; } /***************************************************************************//** * SYS_read_debug_info() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_read_debug_info ( uint8_t * p_debug_info, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_READ_DEBUG_INFO_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_debug_info, (uint16_t)MSS_SYS_READ_DEBUG_INFO_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_READ_DEBUG_INFO_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_debug_info, (uint16_t)MSS_SYS_READ_DEBUG_INFO_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /**************************************************************************//** * SYS_read_envm_param() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_read_envm_parameter ( uint8_t * p_envm_param, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_READ_ENVM_PARAM_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_envm_param, (uint16_t)MSS_SYS_READ_ENVM_PARAM_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_READ_ENVM_PARAM_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_envm_param, (uint16_t)MSS_SYS_READ_ENVM_PARAM_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_puf_emulation_service() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_puf_emulation_service ( uint8_t * p_challenge, uint8_t op_type, uint8_t* p_response, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[20] = {0x00}; uint8_t index = 0u; /* Frame the data required for mailbox */ mb_format[index] = op_type; for (index = 4u; index < 20u; index++) { mb_format[index] = p_challenge[index - 4u]; } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_PUF_EMULATION_SERVICE_REQUEST_CMD, mb_format, (uint16_t)MSS_SYS_PUF_EMULATION_SERVICE_CMD_LEN, p_response, (uint16_t)MSS_SYS_PUF_EMULATION_SERVICE_RESP_LEN, mb_offset, (uint16_t)MSS_SYS_PUF_EMULATION_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_PUF_EMULATION_SERVICE_REQUEST_CMD, mb_format, (uint16_t)MSS_SYS_PUF_EMULATION_SERVICE_CMD_LEN, p_response, (uint16_t)MSS_SYS_PUF_EMULATION_SERVICE_RESP_LEN, mb_offset, (uint16_t)MSS_SYS_PUF_EMULATION_RET_OFFSET); } return status; } /***************************************************************************//** * SYS_digital_signature_service() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_digital_signature_service ( uint8_t* p_hash, uint8_t format, uint8_t* p_response, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (format == MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD) { if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode ((uint8_t)MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, p_hash, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_HASH_DATA_LEN, p_response, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, mb_offset, (uint16_t)MSS_SYS_DIGITAL_SIG_RET_OFFSET); } else { status = execute_ss_polling_mode ((uint8_t)MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD, p_hash, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_HASH_DATA_LEN, p_response, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE, mb_offset, (uint16_t)MSS_SYS_DIGITAL_SIG_RET_OFFSET); } } else { if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode ((uint8_t)MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, p_hash, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_HASH_DATA_LEN, p_response, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, mb_offset, (uint16_t)MSS_SYS_DIGITAL_SIG_RET_OFFSET); } else { status = execute_ss_polling_mode ((uint8_t)MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD, p_hash, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_HASH_DATA_LEN, p_response, (uint16_t)MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE, mb_offset, (uint16_t)MSS_SYS_DIGITAL_SIG_RET_OFFSET); } } return status; } /***************************************************************************//** * SYS_secure_nvm_write() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_secure_nvm_write ( uint8_t format, uint8_t snvm_module, uint8_t* p_data, uint8_t* p_user_key, uint16_t mb_offset ) { uint8_t frame[256] = {0x00}; uint8_t* p_frame = &frame[0]; uint16_t index = 0; uint16_t status = MSS_SYS_PARAM_ERR; ASSERT(!(NULL_BUFFER == p_data)); ASSERT(!(NULL_BUFFER == p_user_key)); ASSERT(!(snvm_module >= 221u)); *p_frame = snvm_module; /*SNVMADDR - SNVM module*/ p_frame += 4; /* Next 3 bytes RESERVED - For alignment */ /* Copy user key and send the command/data to mailbox. */ if ((format == MSS_SYS_SNVM_AUTHEN_TEXT_REQUEST_CMD) || (format == MSS_SYS_SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) { /* Copy user data */ for (index = 0u; index < (MSS_SYS_AUTHENTICATED_TEXT_DATA_LEN - MSS_SYS_USER_SECRET_KEY_LEN); index++) { *p_frame = p_data[index]; p_frame++; } /* Copy user key */ for (index = 0u; index < MSS_SYS_USER_SECRET_KEY_LEN; index++) { *p_frame = p_user_key[index]; p_frame++; } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( format, &frame[0], (uint16_t)MSS_SYS_AUTHENTICATED_TEXT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( format, &frame[0], (uint16_t)MSS_SYS_AUTHENTICATED_TEXT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } } else { /* Copy user data */ for (index = 0u; index < (MSS_SYS_NON_AUTHENTICATED_TEXT_DATA_LEN - 4u); index++) { *(p_frame+index) = p_data[index]; } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( format, &frame[0], (uint16_t)MSS_SYS_NON_AUTHENTICATED_TEXT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( format, &frame[0], (uint16_t)MSS_SYS_NON_AUTHENTICATED_TEXT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } } return status; } /***************************************************************************//** * SYS_secure_nvm_read() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_secure_nvm_read ( uint8_t snvm_module, uint8_t* p_user_key, uint8_t* p_admin, uint8_t* p_data, uint16_t data_len, uint16_t mb_offset ) { /* Frame the message. */ uint8_t frame[16] = {0x00u}; uint8_t* p_frame = &frame[0]; uint16_t index = 0u; uint16_t status = MSS_SYS_PARAM_ERR; uint8_t response[256] = {0x00}; ASSERT(!(NULL_BUFFER == p_data)); ASSERT(!(NULL_BUFFER == p_admin)); ASSERT(!(snvm_module > 221u)); ASSERT((data_len == 236u) || (data_len == 252u)); *p_frame = snvm_module; /*SNVMADDR - SNVM module*/ p_frame += 4u; /* RESERVED - For alignment */ /* Copy user key */ if (236u == data_len) { for (index = 0u; index < 12u; index++) { ASSERT(p_user_key != NULL_BUFFER); *p_frame = p_user_key[index]; p_frame++; } } else { p_frame += 12u; } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_SNVM_READ_REQUEST_CMD, &frame[0], (uint16_t)MSS_SYS_SECURE_NVM_READ_DATA_LEN, response, (data_len + 4u), mb_offset, (uint16_t)MSS_SYS_SECURE_NVM_READ_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_SNVM_READ_REQUEST_CMD, &frame[0], (uint16_t)MSS_SYS_SECURE_NVM_READ_DATA_LEN, response, (data_len + 4u), mb_offset, (uint16_t)MSS_SYS_SECURE_NVM_READ_RET_OFFSET); } if (MSS_SYS_SUCCESS == status) { for (index = 0u; index < 4u; index++) { *(p_admin+index) = (uint32_t)response[index]; } /* Copy data into user buffer. */ for (index = 4u; index < (data_len + 4u); index++) { *(p_data + (index - 4u)) = response[index]; } } else { ; } return status; } /***************************************************************************//** * SYS_nonce_service() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_nonce_service ( uint8_t * p_nonce, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_NONCE_SERVICE_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_nonce, (uint16_t)MSS_SYS_NONCE_SERVICE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_NONCE_SERVICE_REQUEST_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, p_nonce, (uint16_t)MSS_SYS_NONCE_SERVICE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_execute_uic_script() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_execute_uic_script ( uint8_t src_periph_type, uint32_t periph_address, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t input_data[8]; uint32_t l_periph_addr = periph_address; if (src_periph_type == MSS_SYS_UIC_SOURCE_PERIPH_SNVM) { l_periph_addr &= 0x000000FFu; /*only first 8 bits are valid*/ } else if ((src_periph_type == MSS_SYS_UIC_SOURCE_PERIPH_NONAUTHEN_SPIFLASH )|| (src_periph_type == MSS_SYS_UIC_SOURCE_PERIPH_AUTHEN_SPIFLASH )) { l_periph_addr &= 0xFFFFFFFFu; /*only first 24 or 32 bits are valid*/ } else if (src_periph_type == MSS_SYS_UIC_SOURCE_PERIPH_UPROM) { l_periph_addr &= 0x000000FFu; /*only first 8 bits are valid*/ l_periph_addr = (l_periph_addr << 14u); } else { return status; } *(uint32_t*)input_data = l_periph_addr; input_data[4] = src_periph_type; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_UIC_EXECUTE_SCRIPT_CMD, &input_data[0], (uint16_t)MSS_SYS_EXECUTE_UIC_SCRIPT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_UIC_EXECUTE_SCRIPT_CMD, &input_data[0], (uint16_t)MSS_SYS_EXECUTE_UIC_SCRIPT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_authenticate_uic_bitstream() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_authenticate_uic_bitstream ( uint32_t spi_flash_address, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint32_t l_spi_flash_address = spi_flash_address; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_UIC_BITSTREAM_AUTHENTICATE_CMD, (uint8_t* )&l_spi_flash_address, (uint16_t)MSS_SYS_UIC_BITSTREAM_AUTHENTICATE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_UIC_BITSTREAM_AUTHENTICATE_CMD, (uint8_t* )&l_spi_flash_address, (uint16_t)MSS_SYS_UIC_BITSTREAM_AUTHENTICATE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_authenticate_bitstream() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_authenticate_bitstream ( uint32_t spi_flash_address, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint32_t l_spi_flash_address = spi_flash_address; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_BITSTREAM_AUTHENTICATE_CMD, (uint8_t* )&l_spi_flash_address, (uint16_t)MSS_SYS_BITSTREAM_AUTHENTICATE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_BITSTREAM_AUTHENTICATE_CMD, (uint8_t* )&l_spi_flash_address, (uint16_t)MSS_SYS_BITSTREAM_AUTHENTICATE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_authenticate_iap_image() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_authenticate_iap_image ( uint32_t spi_idx ) { uint16_t status = MSS_SYS_PARAM_ERR; ASSERT(!(spi_idx == 1u)); if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_BITSTREAM_AUTHENTICATE_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, (uint16_t)spi_idx, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_BITSTREAM_AUTHENTICATE_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, (uint16_t)spi_idx, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_digest_check() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_digest_check ( uint32_t options, uint8_t* digesterr, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint32_t l_options = options; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_DIGEST_CHECK_CMD, (uint8_t* )&l_options, (uint16_t)MSS_SYS_DIGEST_CHECK_DATA_LEN, digesterr, (uint16_t)MSS_SYS_DIGEST_CHECK_SERVICE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_DIGEST_CHECK_CMD, (uint8_t* )&l_options, (uint16_t)MSS_SYS_DIGEST_CHECK_DATA_LEN, digesterr, (uint16_t)MSS_SYS_DIGEST_CHECK_SERVICE_RESP_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_execute_iap() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_execute_iap ( uint8_t iap_cmd, uint32_t spiaddr ) { uint16_t status = MSS_SYS_PARAM_ERR; uint32_t l_spiaddr = spiaddr; if ((MSS_SYS_IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) || (MSS_SYS_IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) { ASSERT(!(1u == spiaddr)); } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)iap_cmd, (uint8_t*)&l_spiaddr, MSS_SYS_IAP_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, (uint16_t)spiaddr, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)iap_cmd, (uint8_t*)&l_spiaddr, MSS_SYS_IAP_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, (uint16_t)spiaddr, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_spi_copy() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_spi_copy ( uint64_t mss_dest_addr, uint32_t mss_spi_flash, uint32_t n_bytes, uint8_t options, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[17]; *(uint64_t *)mb_format = mss_dest_addr; *(uint32_t *)(mb_format + 8u) = mss_spi_flash; *(uint32_t *)(mb_format + 12u) = n_bytes; mb_format[16] = options; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_SPI_COPY_CMD, mb_format, (uint16_t)MSS_SYS_SPI_COPY_MAILBOX_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_SPI_COPY_CMD, mb_format, (uint16_t)MSS_SYS_SPI_COPY_MAILBOX_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_read_probe() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_read_probe ( uint8_t ipseg_addr, uint8_t iprow_addr, uint8_t *prdata, uint16_t mb_offset, uint8_t resp_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[2]; uint16_t service_data = 0u; uint8_t l_resp_offset = resp_offset; service_data = iprow_addr; service_data = service_data << 6u; service_data = service_data + ipseg_addr; *(uint16_t*)mb_format = service_data; l_resp_offset = (4u + (4u * l_resp_offset)); if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_PROBE_READ_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_PROBE_READ_SERVICE_DATA_LEN, prdata, (uint16_t)MSS_SYS_PROBE_READ_SERVICE_RESP_LEN, mb_offset, (uint16_t)l_resp_offset); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_PROBE_READ_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_PROBE_READ_SERVICE_DATA_LEN, prdata, (uint16_t)MSS_SYS_PROBE_READ_SERVICE_RESP_LEN, mb_offset, (uint16_t)l_resp_offset); } return status; } /***************************************************************************//** * MSS_SYS_debug_write_probe() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_write_probe ( uint8_t prb_addr, uint8_t ipseg_addr, uint8_t iprow_addr, uint32_t pwmask, uint32_t pwdata, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[12] = {0}; /* Local variable to store the combination of iprow_addr, ipseg_addr and * prb_addr*/ uint32_t service_data = 0u; service_data = iprow_addr; service_data = service_data << 12u; uint16_t temp = ipseg_addr; temp = temp << 6u; temp += prb_addr; service_data = service_data + temp; *(uint32_t *)mb_format = service_data; *(uint32_t *)(mb_format + 4u) = pwmask; *(uint32_t *)(mb_format + 8u) = pwdata; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_PROBE_WRITE_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_PROBE_WRITE_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_PROBE_WRITE_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_PROBE_WRITE_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_live_probe() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_live_probe ( uint8_t x_addr, uint8_t y_addr, uint8_t ipseg_addr, uint8_t iprow_addr, uint8_t clear, uint8_t ioen, uint16_t mb_offset, uint8_t service_cmd ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[6] = {0}; uint32_t service_data = 0u; uint16_t channel_addr = 0u; uint16_t probe_addr = 0u; channel_addr = y_addr; channel_addr = (channel_addr << 5u) + x_addr; probe_addr = iprow_addr; probe_addr = (probe_addr << 6u) + ipseg_addr; service_data = probe_addr; service_data = (service_data << 11u) + channel_addr; *(uint32_t*)mb_format = service_data; mb_format[4] = clear; mb_format[5] = ioen; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( service_cmd, mb_format, (uint16_t)MSS_SYS_LIVE_PROBE_DEBUG_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( service_cmd, mb_format, (uint16_t)MSS_SYS_LIVE_PROBE_DEBUG_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_select_mem() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_select_mem ( uint8_t ipblk_addr, uint8_t ipseg_addr, uint8_t iprow_addr, uint8_t memtype, uint8_t memlock_mode, uint16_t timeout, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[6] = {0}; uint16_t service_data = 0u; service_data = iprow_addr; uint16_t temp = ipseg_addr; temp = ((temp << 3u) + ipblk_addr); service_data = ((temp << 9u) + temp); *(uint16_t *)mb_format = service_data; mb_format[2] = memtype; mb_format[3] = memlock_mode; *(uint16_t*)(mb_format + 4u) = timeout; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_MEM_SELECT_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_MEM_SELECT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_MEM_SELECT_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_MEM_SELECT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_read_mem() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_read_mem ( uint16_t mem_addr, uint16_t n_words, uint64_t mss_addr, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[16] = {0}; *(uint16_t*)(mb_format) = mem_addr; *(uint16_t*)(mb_format + 2u) = n_words; *(uint64_t*)(mb_format + 8u) = mss_addr; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_MEM_READ_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_MEM_READ_WRITE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_MEM_READ_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_MEM_READ_WRITE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_write_mem() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_write_mem ( uint16_t mem_addr, uint16_t n_words, uint64_t mss_addr, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[16] = {0}; *(uint16_t*)(mb_format) = mem_addr; *(uint16_t*)(mb_format + 2u) = n_words; *(uint64_t*)(mb_format + 8u) = mss_addr; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_MEM_WRITE_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_MEM_READ_WRITE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_MEM_WRITE_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_MEM_READ_WRITE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_read_apb() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_read_apb ( uint32_t apb_addr, uint8_t apb_wsize, uint16_t max_bytes, uint64_t mss_addr, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[24] = {0}; *(uint32_t *)mb_format = apb_addr; mb_format[5] = apb_wsize; *(uint16_t *)(mb_format + 8u) = max_bytes; *(uint64_t *)(mb_format + 16u) = mss_addr; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_APB_READ_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_APB_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_APB_READ_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_APB_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_write_apb() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_write_apb ( uint32_t apb_addr, uint8_t apb_wsize, uint16_t max_bytes, uint64_t mss_addr, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[24] = {0}; *(uint32_t *)mb_format = apb_addr; mb_format[5] = apb_wsize; *(uint16_t *)(mb_format + 8u) = max_bytes; *(uint64_t *)(mb_format + 16u) = mss_addr; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_APB_WRITE_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_APB_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_APB_WRITE_DEBUG_CMD, mb_format, (uint16_t)MSS_SYS_APB_SERVICE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_debug_fabric_snapshot() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_fabric_snapshot ( uint32_t port_addr, uint8_t apb_fast_write, uint16_t mb_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[5]={0}; *(uint32_t *)mb_format = port_addr; mb_format[4] = apb_fast_write; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_DEBUG_SNAPSHOT_CMD, mb_format, (uint16_t)MSS_SYS_DEBUG_SNAPSHOT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_DEBUG_SNAPSHOT_CMD, mb_format, (uint16_t)MSS_SYS_DEBUG_SNAPSHOT_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, MSS_SYS_COMMON_RET_OFFSET); } return status; } /***************************************************************************//** * MSS_SYS_otp_generate() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_otp_generate ( uint8_t keymode, uint8_t* n_user, uint8_t* n_fpga, uint16_t mb_offset, uint16_t resp_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[20] = {0}; uint8_t index = 0u; mb_format[index] = keymode; for (index = 0u; index < 16u; index++ ) { mb_format[index + 4u] = *(n_user + index); } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_GENERATE_OTP_CMD, mb_format, (uint16_t)MSS_SYS_GENERATE_OTP_DATA_LEN, n_fpga, (uint16_t)MSS_SYS_GENERATE_OTP_RESP_LEN, mb_offset, resp_offset); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_GENERATE_OTP_CMD, mb_format, (uint16_t)MSS_SYS_GENERATE_OTP_DATA_LEN, n_fpga, (uint16_t)MSS_SYS_GENERATE_OTP_RESP_LEN, mb_offset, resp_offset); } return status; } /***************************************************************************//** * MSS_SYS_otp_match() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_otp_match ( uint8_t * user_id, uint8_t * validator, uint8_t * otp, uint16_t mb_offset, uint16_t resp_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[80] = {0}; uint8_t index = 0u; for (index = 0u; index < 80u; index++) { if (index < 16u) { mb_format[index] = user_id[index]; } if ((index > 15u) && (index < 48u)) { mb_format[index] = validator[index - 16u]; } if (index > 47u) { mb_format[index] = otp[index - 48u]; } } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_MATCH_OTP_CMD, mb_format, (uint16_t)MSS_SYS_MATCH_OTP_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_MATCH_OTP_CMD, mb_format, (uint16_t)MSS_SYS_MATCH_OTP_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } return status; } /***************************************************************************//** * MSS_SYS_unlock_debug_passcode() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_unlock_debug_passcode ( uint8_t* cmd_data, uint16_t mb_offset, uint16_t resp_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; //uint8_t mb_format[32] = {0}; //uint8_t index = 0u; //for (index = 0u; index < 32u; index++) //{ // mb_format[index] = cmd_data[index]; //} if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_UNLOCK_DEBUG_PASSCODE, cmd_data, (uint16_t)MSS_SYS_UNLOCK_DEBUG_PASSCODE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_UNLOCK_DEBUG_PASSCODE, cmd_data, (uint16_t)MSS_SYS_UNLOCK_DEBUG_PASSCODE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } return status; } /***************************************************************************//** * MSS_SYS_one_way_passcode() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_one_way_passcode ( uint8_t* msg_id, uint8_t* validator, uint8_t keymode, uint8_t* dsn, uint8_t* hash, uint8_t* plaintext_passcode, uint8_t* hwm, uint16_t mb_offset, uint16_t resp_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; uint8_t mb_format[480] = {0}; uint16_t index = 0; for (index = 0u; index < 480u; index++) { if ( index < 16u) { mb_format[index] = msg_id[index]; } if ((index > 15u) && (index < 48u)) { mb_format[index] = validator[index - 16]; } if ( index == 51u) { mb_format[index] = keymode; } if ((index > 67u) && (index < 84u)) { mb_format[index] = dsn[index - 68]; } if ((index > 351u) && (index < 384u)) { mb_format[index] = hash[index - 352]; } if ((index > 383u) && (index < 416u)) { mb_format[index] = plaintext_passcode[index - 384]; } if ((index > 415u) && (index < 432u)) { mb_format[index] = hwm[index]; } } if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_ONE_WAY_PASSCODE_CMD, mb_format, (uint16_t)MSS_SYS_ONE_WAY_PASSCODE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_ONE_WAY_PASSCODE_CMD, mb_format, (uint16_t)MSS_SYS_ONE_WAY_PASSCODE_DATA_LEN, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } return status; } /***************************************************************************//** * MSS_SYS_debug_terminate() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_debug_terminate ( uint16_t mb_offset, uint16_t resp_offset ) { uint16_t status = MSS_SYS_PARAM_ERR; if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { status = execute_ss_interrupt_mode( (uint8_t)MSS_SYS_TERMINATE_DEBUG_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } else { status = execute_ss_polling_mode( (uint8_t)MSS_SYS_TERMINATE_DEBUG_CMD, NULL_BUFFER, MSS_SYS_WITHOUT_CMD_DATA, NULL_BUFFER, MSS_SYS_NO_RESPONSE_LEN, mb_offset, resp_offset); } return status; } /***************************************************************************//** * MSS_SYS_read_response() * See "mss_sysservices.h" for details of how to use this function. */ uint16_t MSS_SYS_read_response ( void ) { uint16_t response_limit = 0u; uint32_t idx; uint16_t status = MSS_SYS_PARAM_ERR; if (g_message_interrupt_counter > 0u) { g_message_interrupt_counter = 0u; if (g_int_service_response_size > 0u) { response_limit = g_int_service_response_size + g_int_service_response_offset; for (idx = g_int_service_response_offset; idx < response_limit; idx++) { gp_int_service_response[idx - g_int_service_response_offset] = *((uint8_t *)MSS_SCBMAILBOX + idx); } } /* Read the status returned by System Controller*/ status = ((MSS_SCBCTRL->SERVICES_SR & SCBCTRL_SERVICESSR_STATUS_MASK) >> SCBCTRL_SERVICESSR_STATUS); } return status; } /***************************************************************************//** Internal functions. */ /* * This function requests the system service to the system controller. It will * first write the Mailbox input data to the mailbox from the cmd_data if * required for that service. * */ static uint16_t request_system_service ( uint8_t cmd_opcode, uint8_t* cmd_data, uint16_t cmd_data_size, uint8_t* p_response, uint16_t response_size, uint16_t mb_offset, uint16_t response_offset ) { uint32_t idx; uint16_t ss_command = 0u; uint32_t* word_buf ; uint8_t* byte_buf ; uint8_t byte_off; uint8_t byte_index; uint32_t * mailbox_reg; uint32_t mailbox_val = 0u; if (MSS_SCBCTRL->SERVICES_SR & SCBCTRL_SERVICESSR_BUSY_MASK) { /*System controller is busy with executing service*/ return MSS_SYS_BUSY; } /*Code for MSS_SYS_PARAM_ERR is not implemented with this version of driver.*/ *MSS_SCBMESSAGE_INT = 0x0u; /*clear message_int reg*/ if (g_service_mode == MSS_SYS_SERVICE_INTERRUPT_MODE) { gp_int_service_response = (uint8_t*)p_response; g_int_service_response_offset = response_offset; g_int_service_response_size = response_size; } if (cmd_data_size > 0u) { word_buf = (uint32_t*)cmd_data; /* Write the user data into mail box. */ for (idx = 0u; idx < (cmd_data_size / 4u); idx++) { *(MSS_SCBMAILBOX + idx) = word_buf[idx]; } if ((cmd_data_size % 4u) > 0u) { byte_off = (((cmd_data_size / 4u) * 4u)); byte_buf = (uint8_t*)(cmd_data + byte_off); mailbox_reg = (MSS_SCBMAILBOX + idx); mailbox_val = *mailbox_reg; for (byte_index = 0u; byte_index < (cmd_data_size % 4u); byte_index++) { mailbox_val &= ~(0xffu << (byte_index * 8u)); mailbox_val |= (byte_buf[byte_index] << (byte_index * 8u)); } *mailbox_reg = mailbox_val; } } /*Form the SS command: bit 0to6 is the opcode, bit 7to15 is the Mailbox offset For some services this field has another meaning. (e.g. for IAP bit-stream auth. it means spi_idx)*/ ss_command = ((mb_offset << 7u) | (cmd_opcode & 0x7Fu)); /*Interrupt based implementation of services */ if (MSS_SYS_SERVICE_INTERRUPT_MODE == g_service_mode) { MSS_SCBCTRL->SERVICES_CR = (((ss_command << SCBCTRL_SERVICESCR_COMMAND) & SCBCTRL_SERVICESCR_COMMAND_MASK) | SCBCTRL_SERVICESCR_REQ_MASK | SCBCTRL_SERVICESSR_NOTIFY_MASK); } else { MSS_SCBCTRL->SERVICES_CR = (((ss_command << SCBCTRL_SERVICESCR_COMMAND) & SCBCTRL_SERVICESCR_COMMAND_MASK) | SCBCTRL_SERVICESCR_REQ_MASK); } /*Service requested successfully*/ return MSS_SYS_SUCCESS; } /* * This function executes the SS command in interrupt mode. If Mailbox input data * is required by the service, the call to request_system_service() function will * first load it from cmd_data into the Mailbox. The response of the service is * not read by this function as it depends on message interrupt. Application * will have to read the response of service by calling MSS_SYS_read_response(), * only after interrupt occurs. */ static uint16_t execute_ss_interrupt_mode ( uint8_t cmd_opcode, uint8_t* cmd_data, uint16_t cmd_data_size, uint8_t* p_response, uint16_t response_size, uint16_t mb_offset, uint16_t response_offset ) { uint16_t status; status = request_system_service(cmd_opcode, cmd_data, cmd_data_size, p_response, response_size, mb_offset, response_offset); return status; } /* * This function executes the SS command in polling mode. If Mailbox input data * is required by the it will first load it from cmd_data into the Mailbox. * After requesting the service it will poll the request and busy bit. If the * service requires the response data to be read from mailbox, it will read the * mailbox contents and store it in p_response buffer. */ static uint16_t execute_ss_polling_mode ( uint8_t cmd_opcode, uint8_t* cmd_data, uint16_t cmd_data_size, uint8_t* p_response, uint16_t response_size, uint16_t mb_offset, uint16_t response_offset ) { uint32_t idx; uint16_t status = 0u; uint16_t response_limit = 0u; uint8_t* response_buf; status = request_system_service(cmd_opcode, cmd_data, cmd_data_size, p_response,response_size, mb_offset, response_offset); if (status == MSS_SYS_SUCCESS) { /**REQ bit will remain set till the system controller starts * processing command. Since DRI is slow interface, we are waiting * here to make sure System controller has started processing * command*/ while (SCBCTRL_SERVICESCR_REQ_MASK == (MSS_SCBCTRL->SERVICES_CR & SCBCTRL_SERVICESCR_REQ_MASK)) { ; } /*Once system controller starts processing command The busy bit will * go 1. Make sure that service is complete i.e. BUSY bit is gone 0*/ while (SCBCTRL_SERVICESSR_BUSY_MASK == (MSS_SCBCTRL->SERVICES_SR & SCBCTRL_SERVICESSR_BUSY_MASK)) { ; } if (response_size > 0u) { response_limit = response_size + response_offset; response_buf = (uint8_t*)p_response; for (idx = response_offset; idx < response_limit; idx++) { response_buf[idx - response_offset] = *((uint8_t *)MSS_SCBMAILBOX + idx); } } /*Read the status returned by System Controller*/ status = ((MSS_SCBCTRL->SERVICES_SR & SCBCTRL_SERVICESSR_STATUS_MASK) >> SCBCTRL_SERVICESSR_STATUS); } else { status = MSS_SYS_BUSY; } return status; } /***************************************************************************//** * Interrupt service routine triggered by message interrupt. * This routine will call handler function which will read the service response * in interrupt mode of operation. */ uint8_t g5c_message_plic_IRQHandler ( void ) { g_message_interrupt_counter++; volatile uint32_t reg = *MSS_SCBMESSAGE; /*read message reg.*/ reg = *MSS_SCBMESSAGE_INT; *MSS_SCBMESSAGE_INT = 0x0u; /*clear message_int reg*/ reg = *MSS_SCBMESSAGE_INT; (void)reg; // reference to avoid compiler warning mss_sys_interrupt_handler(); return 0; } #ifdef __cplusplus } #endif mss_sys_services.h000066400000000000000000004712131432224323300424420ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_sys_services/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire SoC micro processor subsystem system services bare metal driver * implementation. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS System services Bare Metal Driver ============================================================================== Introduction ============================================================================== The PolarFire SoC system services are the services offered by the system controller. These services can be requested by PolarFire SoC MSS over System Controller Bus (SCB). The MSS appears as SCB master over the SCB bus. MSS can communicate with system controller over SCB by write/read to the MSS SCB register space. The PolarFire SoC system service driver software provides a set of functions for controlling the PolarFire SoC system services as part of a bare-metal system where no operating system is available. It can be adapted to be used as a part of an operating system, but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of all the features of the PolarFire SoC MSS system services is covered by this driver. Besides, this driver does not require any other configuration. It relies on SCB register access interface to communicate with system controller. The base address and register addresses are defined in this driver as constants. The interrupt number assigned are defined as constants in the MPFS HAL. Ensure that the latest MPFS HAL is included in the project settings of the SoftConsole toolchain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The PolarFire SoC system services are the services offered by the system controller. These services can be requested by PolarFire SoC MSS over System Controller Bus (SCB). The MSS appears as SCB master over the SCB bus. MSS can communicate with the system controller over SCB by accessing the MSS SCB register space. Requesting a system service over the SCB bus involves a command/response sequence to transfer a system service command from the MSS to the system controller and to transfer status back from the system controller to the MSS. The MSS SCB register space also provides access to the mailbox. The mailbox is used for passing data related to the system service between the MSS and system controller in both directions. On completion of service, the system controller also writes a status code indicating the successful completion of the system service or an error code into the status register. These system services are grouped into the following categories: - Device and design information services - Design services - Data security services - Fabric services - MSS services ----------------------------------------------------------------------------- Device and Design Information Services ----------------------------------------------------------------------------- The PolarFire SoC system service driver can be used to read information about the device on which it is being executed and the current fabric design by making a call to the following functions. - MSS_SYS_get_serial_number() - MSS_SYS_get_user_code() - MSS_SYS_get_design_info() - MSS_SYS_get_device_certificate() - MSS_SYS_read_digest() - MSS_SYS_query_security() - MSS_SYS_read_debug_info() - MSS_SYS_read_envm_param() ----------------------------------------------------------------------------- Design Services ----------------------------------------------------------------------------- The PolarFire SoC system service driver can be used to execute UIC script and perform bitstream authentication using the following functions. - MSS_SYS_execute_UIC_script_service() - MSS_SYS_UIC_bitstream_authenticate_service() - MSS_SYS_bitstream_authenticate_service() - MSS_SYS_IAP_image_authenticate_service() ----------------------------------------------------------------------------- Data Security Services ----------------------------------------------------------------------------- The PolarFire SoC System Service driver can be used to execute data security services using the following functions: - MSS_SYS_digital_signature_service () - MSS_SYS_secure_nvm_write() - MSS_SYS_secure_nvm_read() - MSS_SYS_puf_emulation_service () - MSS_SYS_nonce_service () ----------------------------------------------------------------------------- Executing Fabric Services ----------------------------------------------------------------------------- The PolarFire SoC System Service driver can be used to execute fabric services using the following functions: - MSS_SYS_digest_check_service() - MSS_SYS_iap_service() ----------------------------------------------------------------------------- MSS Services ----------------------------------------------------------------------------- The PolarFire SoC System Service driver can be used to execute MSS services using following functions: - MSS_SYS_spi_copy_service() - MSS_SYS_probe_read_debug_service() - MSS_SYS_probe_write_debug_service() - MSS_SYS_live_probe_debug_service() - MSS_SYS_MEM_select_debug_service() - MSS_SYS_MEM_read_debug_service() - MSS_SYS_MEM_write_debug_service() - MSS_SYS_apb_read_service() - MSS_SYS_apb_write_debug_service() - MSS_SYS_debug_snapshot_service() - MSS_SYS_generate_otp_service() - MSS_SYS_match_otp_service() - MSS_SYS_unlock_debug_passcode_service() - MSS_SYS_one_way_passcode_service() - MSS_SYS_terminate_debug_service() ----------------------------------------------------------------------------- Mode of operation and status response ----------------------------------------------------------------------------- The PolarFire SoC MSS system service driver can be configured to execute service in interrupt mode or polling mode. User need to select the mode of operation by configuring the driver with appropriate service mode macros as a parameter to MSS_SYS_select_service_mode() function. For interrupt mode, the calling service function exits after requesting the system service with a success return value. The actual response from the system controller will only be available after the interrupt occurs. Use the MSS_SYS_read_response() function to read the service response and the status response code. For Polling mode, the calling service function exits only after the completion of the service, the return value in this case will indicate the service response code received from the system controller. All the service execution functions return the 16-bit status returned by system controller on executing the given service. A zero value indicates the successful execution of that service. A non-zero value indicates an error code representing the type of error that was encountered while executing the service. Irrespective of the mode, if the controller is busy executing the previous service the function will exit with the MSS_SYS_BUSY return value. The error codes are different for each service. See individual function descriptions to know the meaning of the error code for each service. */ #ifndef MSS_SYS_SERVICES_H_ #define MSS_SYS_SERVICES_H_ #include #ifdef __cplusplus extern "C" { #endif /*--------------------------------Public constants----------------------------*/ /*-------------------------------------------------------------------------*//** System services Generic constants ============================ These constants are used to communicate the outcome of a system services request. These status codes are used across all types of services. The following table lists the system service driver generic constants. MSS_SYS_SUCCESS System service executed successfully. MSS_SYS_BUSY system controller is busy executing system service which was initiated using its AMBA interface. MSS_SYS_PARAM_ERR System service cannot be executed as one or more parameters are not as expected by this driver. */ #define MSS_SYS_SUCCESS 0u #define MSS_SYS_BUSY 0xEFu #define MSS_SYS_PARAM_ERR 0xFFu /*-------------------------------------------------------------------------*//** System service execution mode macros ============================ The following defines are used to select whether to execute services in interrupt mode or polling mode. */ /* Parameter used in MSS_SYS_service_mode() function * to execute the services in interrupt mode */ #define MSS_SYS_SERVICE_INTERRUPT_MODE 1u /* Parameter used in MSS_SYS_service_mode() function * to execute the services in polling mode */ #define MSS_SYS_SERVICE_POLLING_MODE 0u /*-------------------------------------------------------------------------*//** System service error codes ============================ The following constants list the success/error code for each system service. */ /*-------------------------------------------------------------------------*//** Device Certificate Service error codes MSS_SYS_DCF_DEVICE_MISMATCH Public key or FSN do not match device MSS_SYS_DCF_INVALID_SIGNATURE Certificate signature is invalid MSS_SYS_DCF_SYSTEM_ERROR PUF or storage failure */ #define MSS_SYS_DCF_DEVICE_MISMATCH 1u #define MSS_SYS_DCF_INVALID_SIGNATURE 2u #define MSS_SYS_DCF_SYSTEM_ERROR 3u /*------------------------------------------------------------------------*//** Read ENVM parameters service error codes MSS_SYS_ENVM_DIGEST_ERROR Page digest mismatches. Parameter values still returned */ #define MSS_SYS_ENVM_DIGEST_ERROR 1u /*-------------------------------------------------------------------------*//** Execute UIC script and UIC bitstream authentication error codes EXECUTE_UIC_SPI_MAX_FRAME_ERR Maximum number for Frames have been exceeded during SPI UIC execution EXECUTE_UIC_POLL_TIMEOUT Timeout occurred during the Poll instruction. EXECUTE_UIC_SPI_AUTHEN_ERR Authentication error occurred during UIC SPI Authenticated mode EXECUTE_UIC_SPI_DECRYPT_ERR Decryption error occurred during UIC SPI Authenticated mode EXECUTE_UIC_SPI_NOTMASTER_ERR SPI isn't set as the master EXECUTE_UIC_FABRIC_APB_ERR A Fabric APB Error was detected during UIC execution EXECUTE_UIC_SCB_ERR A SCB Error was detected during UIC execution EXECUTE_UIC_PNVM_ENCRYPT_ERR An Encrypted SNVM page was detected during UIC execution EXECUTE_UIC_ADDR_OUTOFRANGE_ERR An illegal script address was detected during UIC execution EXECUTE_UIC_JUMP_MAX_ERR The maximum number of Jump executions was exceeded. Current max is 1000. EXECUTE_UIC_UNEXPECTED_FORMAT_ERR Fields within the instruction that were expected to be all 0 were not. EXECUTE_UIC_SCRIPT_TIMEOUT_ERR UIC Script took longer than the specified UIC_SCRIPT_TIMEOUT parameter (in seconds) */ #define MSS_SYS_EXECUTE_UIC_SUCCESS 0u #define MSS_SYS_EXECUTE_UIC_SPI_MAX_FRAME_ERR 1u #define MSS_SYS_EXECUTE_UIC_POLL_TIMEOUT 2u #define MSS_SYS_EXECUTE_UIC_SPI_AUTHEN_ERR 3u #define MSS_SYS_EXECUTE_UIC_SPI_DECRYPT_ERR 4u #define MSS_SYS_EXECUTE_UIC_SPI_NOTMASTER_ERR 5u #define MSS_SYS_EXECUTE_UIC_FABRIC_APB_ERR 6u #define MSS_SYS_EXECUTE_UIC_SCB_ERR 7u #define MSS_SYS_EXECUTE_UIC_PNVM_ENCRYPT_ERR 8u #define MSS_SYS_EXECUTE_UIC_ADDR_OUTOFRANGE_ERR 9u #define MSS_SYS_EXECUTE_UIC_JUMP_MAX_ERR 10u #define MSS_SYS_EXECUTE_UIC_UNEXPECTED_FORMAT_ERR 11u #define MSS_SYS_EXECUTE_UIC_SCRIPT_TIMEOUT_ERR 12u /*-------------------------------------------------------------------------*//** bitstream authentication and IAP bitstream authentication error codes BSTREAM_AUTH_CHAINING_MISMATCH_ERR Validator or hash chaining mismatch. Incorrectly constructed bitstream or wrong key used. BSTREAM_AUTH_UNEXPECTED_DATA_ERR Unexpected data received. Additional data received after end of EOB component BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR Invalid/corrupt encryption key. The requested key mode is disabled or the key could not be read/reconstructed BSTREAM_AUTH_INVALID_HEADER_ERR Invalid component header BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR Back level not satisfied BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR Illegal bitstream mode. Requested bitstream mode is disabled by user security BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR DSN binding mismatch BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR Illegal component sequence BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR Insufficient device capabilities BSTREAM_AUTH_INCORRECT_DEVICEID_ERR Incorrect DEVICEID BSTREAM_AUTH_PROTOCOL_VERSION_ERR Unsupported bitstream protocol version (regeneration required) BSTREAM_AUTH_VERIFY_ERR Verify not permitted on this bitstream BSTREAM_AUTH_INVALID_DEV_CERT_ERR Invalid Device Certificate. Device SCAC is invalid or not present BSTREAM_AUTH_INVALID_DIB_ERR Invalid DIB BSTREAM_AUTH_SPI_NOT_MASTER_ERR Device not in SPI Master Mode. Error may occur only when bitstream is executed through IAP mode BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR No valid images found. Error may occur when bitstream is executed through Auto Update mode. Occurs when No valid image pointers are found. BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR No valid images found. Error may occur when bitstream is executed through IAP mode via Index Mode. Occurs when No valid image pointers are found. BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR Programmed design version is newer than AutoUpdate image found. Error may occur when bitstream is executed through Auto Update mode BSTREAM_AUTH_INVALID_IMAGE_ERR Selected image was invalid and no recovery was performed due to valid design in device. Error may occur only when bitstream is executed through Auto Update or IAP mode (This error is here for completeness but only can be observed by running the READ_DEBUG_INFO instruction and looking at IAP Error code field) BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR Selected and Recovery image failed to program. Error may occur only when bitstream is executed through Auto Update or IAP mode (This error is here for completeness but only can be observed by running the READ_DEBUG_INFO instruction and looking at IAP Error code field) BSTREAM_AUTH_ABORT_ERR Abort. Non-bitstream instruction executed during bitstream loading. BSTREAM_AUTH_NVMVERIFY_ERR Fabric/UFS verification failed (min or weak limit) BSTREAM_AUTH_PROTECTED_ERR Device security prevented modification of non-volatile memory BSTREAM_AUTH_NOTENA Programming mode not enabled BSTREAM_AUTH_PNVMVERIFY pNVM verify operation failed BSTREAM_AUTH_SYSTEM System hardware error (PUF or DRBG) BSTREAM_AUTH_BADCOMPONENT An internal error was detected in a component payload BSTREAM_AUTH_HVPROGERR HV programming subsystem failure (pump failure) BSTREAM_AUTH_HVSTATE HV programming subsystem in unexpected state (internal error) */ #define MSS_SYS_BSTREAM_AUTH_CHAINING_MISMATCH_ERR 1u #define MSS_SYS_BSTREAM_AUTH_UNEXPECTED_DATA_ERR 2u #define MSS_SYS_BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR 3u #define MSS_SYS_BSTREAM_AUTH_INVALID_HEADER_ERR 4u #define MSS_SYS_BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR 5u #define MSS_SYS_BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR 6u #define MSS_SYS_BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR 7u #define MSS_SYS_BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR 8u #define MSS_SYS_BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR 9u #define MSS_SYS_BSTREAM_AUTH_INCORRECT_DEVICEID_ERR 10u #define MSS_SYS_BSTREAM_AUTH_PROTOCOL_VERSION_ERR 11u #define MSS_SYS_BSTREAM_AUTH_VERIFY_ERR 12u #define MSS_SYS_BSTREAM_AUTH_INVALID_DEV_CERT_ERR 13u #define MSS_SYS_BSTREAM_AUTH_INVALID_DIB_ERR 14u #define MSS_SYS_BSTREAM_AUTH_SPI_NOT_MASTER_ERR 21u #define MSS_SYS_BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR 22u #define MSS_SYS_BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR 23u #define MSS_SYS_BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR 24u /*25 Reserved*/ #define MSS_SYS_BSTREAM_AUTH_INVALID_IMAGE_ERR 26u #define MSS_SYS_BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR 27u #define MSS_SYS_BSTREAM_AUTH_ABORT_ERR 127u #define MSS_SYS_BSTREAM_AUTH_NVMVERIFY_ERR 128u #define MSS_SYS_BSTREAM_AUTH_PROTECTED_ERR 129u #define MSS_SYS_BSTREAM_AUTH_NOTENA 130u #define MSS_SYS_BSTREAM_AUTH_PNVMVERIFY 131u #define MSS_SYS_BSTREAM_AUTH_SYSTEM 132u #define MSS_SYS_BSTREAM_AUTH_BADCOMPONENT 133u #define MSS_SYS_BSTREAM_AUTH_HVPROGERR 134u #define MSS_SYS_BSTREAM_AUTH_HVSTATE 135u /*-------------------------------------------------------------------------*//** Digital Signature Service error code DIGITAL_SIGNATURE_FEK_FAILURE_ERROR Error retrieving FEK DIGITAL_SIGNATURE_DRBG_ERROR Failed to generate nonce DIGITAL_SIGNATURE_ECDSA_ERROR ECDSA failed */ #define MSS_SYS_DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 0x01u #define MSS_SYS_DIGITAL_SIGNATURE_DRBG_ERROR 0x02u #define MSS_SYS_DIGITAL_SIGNATURE_ECDSA_ERROR 0x03u /*-------------------------------------------------------------------------*//** Secure NVM write error codes SNVM_WRITE_INVALID_SNVMADDR Illegal page address SNVM_WRITE_FAILURE PNVM program/verify failed SNVM_WRITE_SYSTEM_ERROR PUF or storage failure SNVM_WRITE_NOT_PERMITTED Write is not permitted */ #define MSS_SYS_SNVM_WRITE_INVALID_SNVMADDR 1u #define MSS_SYS_SNVM_WRITE_FAILURE 2u #define MSS_SYS_SNVM_WRITE_SYSTEM_ERROR 3u #define MSS_SYS_SNVM_WRITE_NOT_PERMITTED 4u /*-------------------------------------------------------------------------*//** Secure NVM read error codes SNVM_READ_INVALID_SNVMADDR Illegal page address SNVM_READ_AUTHENTICATION_FAILURE Storage corrupt or incorrect USK SNVM_READ_SYSTEM_ERROR PUF or storage failure */ #define MSS_SYS_SNVM_READ_INVALID_SNVMADDR 1u #define MSS_SYS_SNVM_READ_AUTHENTICATION_FAILURE 2u #define MSS_SYS_SNVM_READ_SYSTEM_ERROR 3u /*-------------------------------------------------------------------------*//** PUF emulation service error codes MSS_SYS_PUF_EMU_INTERNAL_ERR Internal error */ #define MSS_SYS_PUF_EMU_INTERNAL_ERR 1u /*-------------------------------------------------------------------------*//** Nonce Service Error Codes MSS_SYS_NONCE_PUK_FETCH_ERROR Error fetching PUK MSS_SYS_NONCE_SEED_GEN_ERROR Error generating seed */ #define MSS_SYS_NONCE_PUK_FETCH_ERROR 1u #define MSS_SYS_NONCE_SEED_GEN_ERROR 2u /*-------------------------------------------------------------------------*//** Digest Check service error code MSS_SYS_DIGEST_CHECK_DIGESTERR Digest mismatch occurred */ #define MSS_SYS_DIGEST_CHECK_DIGESTERR 1u /*-------------------------------------------------------------------------*//** SPI COPY SERVICE error codes MSS_SYS_SPI_MASTER_MODE_ERR Device is not configured for master mode MSS_SYS_SPI_AXI_ERR AXI error */ #define MSS_SYS_SPI_MASTER_MODE_ERR 1u #define MSS_SYS_SPI_AXI_ERR 2u /*-------------------------------------------------------------------------*//** Probe services error codes MSS_SYS_PROBE_SECERR The operation was blocked by device security. This will occur if the permanent debug lock UP_DEBUG is set or the user software debug lock SWL_DEBUG is active or the device is in the virgin state. No data is read and PRDATA is invalid. */ #define MSS_SYS_PROBE_SECERR 1u /*-------------------------------------------------------------------------*//** MEM Services error codes MSS_SYS_MEM_SECERR The operation was blocked by device security. This will occur if the permanent debug lock UP_DEBUG is set or the user software debug lock SWL_DEBUG is active or the device is in the virgin state. MSS_SYS_MEM_TIMEOUTERR Timeout occurred. MSS_SYS_MEM_LOCKERR Target memory failed to lock */ #define MSS_SYS_MEM_SECERR 1u #define MSS_SYS_MEM_TIMEOUTERR 2u #define MSS_SYS_MEM_LOCKERR 3u /*-------------------------------------------------------------------------*//** APB services error codes MSS_SYS_APB_SECERR The operation was blocked by device security. This will occur if the permanent debug lock UP_DEBUG is set or the user software debug lock SWL_DEBUG is active or the device is in the virgin state. MSS_SYS_APB_SLVERR The addressed fabric APB peripheral generated a SLVERR response to the bus transaction. MSS_SYS_APB_TIMEOUT The addressed fabric APB peripheral failed to respond before the user-defined APB timeout or the fabric power is not on. */ #define MSS_SYS_APB_SECERR 1u #define MSS_SYS_APB_SLVERR 2u #define MSS_SYS_APB_TIMEOUT 3u /*-------------------------------------------------------------------------*//** Debug snapshot service error codes MSS_SYS_DEBUG_SNAPSHOT_SECERR The operation was blocked by device security. This will occur if the permanent debug lock UP_DEBUG is set or the user software debug lock SWL_DEBUG is active or the device is in the virgin state. MSS_SYS_DEBUG_SNAPSHOT_BUSERR A bus error occurred and the snapshot was aborted. This may occur if: * the fabric power is off, or * the fabric APB slave flagged an error, or * the fabric APB slave was too slow to assert PREADY */ #define MSS_SYS_DEBUG_SNAPSHOT_SECERR 1u #define MSS_SYS_DEBUG_SNAPSHOT_BUSERR 2u /*-------------------------------------------------------------------------*//** GENERATE OTP SERVICE MSS_SYS_SECERR Operation is blocked by device security MSS_SYS_PROTOCOLERR Invalid key provided */ #define MSS_SYS_GENERATE_OTP_SECERR 1u #define MSS_SYS_GENERATE_OTP_PROTOCOLERR 2u /*-------------------------------------------------------------------------*//** MATCH OTP SERVICE MSS_SYS_PROTOCOLERR Keymode not supported. MSS_SYS_MATCH_OTP_MISMATCHERR Calculated validator mismatch. */ #define MSS_SYS_MATCH_OTP_PROTOCOLERR 1u #define MSS_SYS_MATCH_OTP_MISMATCHERR 2u /*-------------------------------------------------------------------------*//** Unlock debug passcode service error codes MSS_SYS_UNLOCK_DEBUG_PASSCODE_SECERR The operation was blocked by device security. Occurs if the lock UL_PLAINTEXT is active or the permanent lock UP_DPK is set. MSS_SYS_UNLOCK_DEBUG_PASSCODE_ERR If the unlock operation fails for any reason then the tamper event PASSCODE_FAIL is generated and all unlocked passcodes are re-locked. */ #define MSS_SYS_UNLOCK_DEBUG_PASSCODE_SECERR 1u #define MSS_SYS_UNLOCK_DEBUG_PASSCODE_ERR 2u /*-------------------------------------------------------------------------*//** One way passcode service error codes MSS_SYS_OWP_OWPERR If the unlock operation fails for any reason then the tamper event PASSCODE_FAIL is generated and all unlocked passcodes are re-locked. */ #define MSS_SYS_OWP_OWPERR 1u /*-------------------------------------------------------------------------*//** System service response data length ============================ The following constants can be used to indicate the length of the data that is written into the mailbox by the system controller in response to the service being requested. MSS_SYS_NO_RESPONSE_LEN This constant is used to indicate that system controller does not return any mailbox data for the service which is being requested MSS_SYS_SERIAL_NUMBER_RESP_LEN Response length serial number service MSS_SYS_USERCODE_RESP_LEN Response length for Usercode service MSS_SYS_DESIGN_INFO_RESP_LEN Response length for Design info service MSS_SYS_DEVICE_CERTIFICATE_RESP_LEN Response length for Device certificate service MSS_SYS_READ_DIGEST_RESP_LEN Response length Read digest service MSS_SYS_QUERY_SECURITY_RESP_LEN Response length Query security service MSS_SYS_READ_DEBUG_INFO_RESP_LEN Response length Read debug info service MSS_SYS_NONCE_SERVICE_RESP_LEN Response length Nonce service MSS_SYS_READ_ENVM_PARAM_RESP_LEN Response length Read eNVM parameters service MSS_SYS_PROBE_READ_SERVICE_RESP_LEN Response length Probe read service MSS_SYS_GENERATE_OTP_RESP_LEN Response length Generate OTP service MSS_SYS_PUF_EMULATION_SERVICE_RESP_LEN Response length PUF emulation service MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE Response length for digital signature service raw format MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE Response length for digital signature service DER format */ #define MSS_SYS_NO_RESPONSE_LEN 0u #define MSS_SYS_SERIAL_NUMBER_RESP_LEN 16u #define MSS_SYS_USERCODE_RESP_LEN 4u #define MSS_SYS_DESIGN_INFO_RESP_LEN 36u #define MSS_SYS_DEVICE_CERTIFICATE_RESP_LEN 1024u #define MSS_SYS_READ_DIGEST_RESP_LEN 544u #define MSS_SYS_QUERY_SECURITY_RESP_LEN 33u #define MSS_SYS_READ_DEBUG_INFO_RESP_LEN 94u #define MSS_SYS_NONCE_SERVICE_RESP_LEN 32u #define MSS_SYS_READ_ENVM_PARAM_RESP_LEN 256u #define MSS_SYS_PUF_EMULATION_SERVICE_RESP_LEN 32u #define MSS_SYS_DIGEST_CHECK_SERVICE_RESP_LEN 4u #define MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_RESP_SIZE 96u #define MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_RESP_SIZE 104u #define MSS_SYS_USER_SECRET_KEY_LEN 12u #define MSS_SYS_PROBE_READ_SERVICE_RESP_LEN 4u #define MSS_SYS_GENERATE_OTP_RESP_LEN 16u /*-------------------------Private constants--------------------------------*/ /*-------------------------------------------------------------------------*//** Service request command opcodes ============================ The following constants can be used as parameter value of the functions to indicate the system service command opcode. */ /*-------------------------------------------------------------------------*//** Device and design information services request command opcodes */ #define MSS_SYS_SERIAL_NUMBER_REQUEST_CMD 0x00u #define MSS_SYS_USERCODE_REQUEST_CMD 0x01u #define MSS_SYS_DESIGN_INFO_REQUEST_CMD 0x02u #define MSS_SYS_DEVICE_CERTIFICATE_REQUEST_CMD 0x03u #define MSS_SYS_READ_DIGEST_REQUEST_CMD 0x04u #define MSS_SYS_QUERY_SECURITY_REQUEST_CMD 0x05u #define MSS_SYS_READ_DEBUG_INFO_REQUEST_CMD 0x06u #define MSS_SYS_READ_ENVM_PARAM_REQUEST_CMD 0x07u /*-------------------------------------------------------------------------*//** Design services request command opcodes */ #define MSS_SYS_BITSTREAM_AUTHENTICATE_CMD 0x23u #define MSS_SYS_IAP_BITSTREAM_AUTHENTICATE_CMD 0x22u #define MSS_SYS_UIC_EXECUTE_SCRIPT_CMD 0x24u #define MSS_SYS_UIC_BITSTREAM_AUTHENTICATE_CMD 0x25u /*-------------------------------------------------------------------------*//** Data security services request command opcodes */ #define MSS_SYS_DIGITAL_SIGNATURE_RAW_FORMAT_REQUEST_CMD 0x19u #define MSS_SYS_DIGITAL_SIGNATURE_DER_FORMAT_REQUEST_CMD 0x1Au #define MSS_SYS_SNVM_NON_AUTHEN_TEXT_REQUEST_CMD 0x10u #define MSS_SYS_SNVM_AUTHEN_TEXT_REQUEST_CMD 0x11u #define MSS_SYS_SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD 0x12u #define MSS_SYS_SNVM_READ_REQUEST_CMD 0x18u #define MSS_SYS_PUF_EMULATION_SERVICE_REQUEST_CMD 0x20u #define MSS_SYS_NONCE_SERVICE_REQUEST_CMD 0x21u /*-------------------------------------------------------------------------*//** Fabric services request command opcodes */ #define MSS_SYS_DIGEST_CHECK_CMD 0x47u #define MSS_SYS_IAP_PROGRAM_BY_SPIIDX_CMD 0x42u #define MSS_SYS_IAP_VERIFY_BY_SPIIDX_CMD 0x44u #define MSS_SYS_IAP_PROGRAM_BY_SPIADDR_CMD 0x43u #define MSS_SYS_IAP_VERIFY_BY_SPIADDR_CMD 0x45u #define MSS_SYS_IAP_AUTOUPDATE_CMD 0x46u /*-------------------------------------------------------------------------*//** MSS services request command opcodes */ #define MSS_SYS_SPI_COPY_CMD 0X50U #define MSS_SYS_PROBE_READ_DEBUG_CMD 0X70U #define MSS_SYS_PROBE_WRITE_DEBUG_CMD 0X71U #define MSS_SYS_LIVE_PROBE_A_DEBUG_CMD 0X72U #define MSS_SYS_LIVE_PROBE_B_DEBUG_CMD 0X73U #define MSS_SYS_MEM_SELECT_DEBUG_CMD 0X74U #define MSS_SYS_MEM_READ_DEBUG_CMD 0X75U #define MSS_SYS_MEM_WRITE_DEBUG_CMD 0X76U #define MSS_SYS_APB_READ_DEBUG_CMD 0X77U #define MSS_SYS_APB_WRITE_DEBUG_CMD 0X78U #define MSS_SYS_DEBUG_SNAPSHOT_CMD 0X79U #define MSS_SYS_GENERATE_OTP_CMD 0X7AU #define MSS_SYS_MATCH_OTP_CMD 0X7BU #define MSS_SYS_UNLOCK_DEBUG_PASSCODE 0X7CU #define MSS_SYS_ONE_WAY_PASSCODE_CMD 0X7DU #define MSS_SYS_TERMINATE_DEBUG_CMD 0X7EU /*-------------------------------------------------------------------------*//** System service mailbox data length ============================ The following constants are used to specify the mailbox data length of each service for the service that is being requested. */ /* This constant is used for the services where no mailbox input data is * required */ #define MSS_SYS_WITHOUT_CMD_DATA 0u #define MSS_SYS_PUF_EMULATION_SERVICE_CMD_LEN 20u #define MSS_SYS_DIGITAL_SIGNATURE_HASH_DATA_LEN 48u /*SNVMADDR + RESERVED + PT*/ #define MSS_SYS_AUTHENTICATED_TEXT_DATA_LEN 252u /*SNVMADDR + RESERVED + PT + USK*/ #define MSS_SYS_NON_AUTHENTICATED_TEXT_DATA_LEN 256u #define MSS_SYS_SECURE_NVM_READ_DATA_LEN 16u #define MSS_SYS_EXECUTE_UIC_SCRIPT_DATA_LEN 8u #define MSS_SYS_UIC_BITSTREAM_AUTHENTICATE_DATA_LEN 4u #define MSS_SYS_BITSTREAM_AUTHENTICATE_DATA_LEN 4u #define MSS_SYS_DIGEST_CHECK_DATA_LEN 4u #define MSS_SYS_IAP_SERVICE_DATA_LEN 4u #define MSS_SYS_SPI_COPY_MAILBOX_DATA_LEN 17u #define MSS_SYS_PROBE_READ_SERVICE_DATA_LEN 2u #define MSS_SYS_PROBE_WRITE_SERVICE_DATA_LEN 11u #define MSS_SYS_LIVE_PROBE_DEBUG_SERVICE_DATA_LEN 6u #define MSS_SYS_MEM_SELECT_DATA_LEN 6u #define MSS_SYS_MEM_READ_WRITE_DATA_LEN 12u #define MSS_SYS_APB_SERVICE_DATA_LEN 24u #define MSS_SYS_DEBUG_SNAPSHOT_DATA_LEN 5u #define MSS_SYS_GENERATE_OTP_DATA_LEN 20u #define MSS_SYS_MATCH_OTP_DATA_LEN 80u #define MSS_SYS_UNLOCK_DEBUG_PASSCODE_DATA_LEN 32u #define MSS_SYS_ONE_WAY_PASSCODE_DATA_LEN 480u /*-------------------------------------------------------------------------*//** System Services mailbox data constants ============================ */ /* KEY MODE for Generate OTP service KM_USER_KEY1 USER Key 1 KM_USER_KEY2 USER Key 2 KM_FACTORY_KEY FK Diversified by UID */ #define MSS_SYS_KM_USER_KEY1 3u #define MSS_SYS_KM_USER_KEY2 4u #define MSS_SYS_KM_FACTORY_KEY 7u /*Digest Check Input options DIGEST_CHECK_FABRIC Carry out digest check on Fabric DIGEST_CHECK_CC Carry out digest check on UFS Fabric Configuration (CC) segment DIGEST_CHECK_SNVM Carry out digest check on ROM digest in SNVM segment DIGEST_CHECK_UL Carry out digest check on UFS UL segment DIGEST_CHECK_UKDIGEST0 Carry out digest check on UKDIGEST0 in User Key segment DIGEST_CHECK_UKDIGEST1 Carry out digest check on UKDIGEST1 in User Key segment DIGEST_CHECK_UKDIGEST2 Carry out digest check on UKDIGEST2 in User Key segment (UPK1) DIGEST_CHECK_UKDIGEST3 Carry out digest check on UKDIGEST3 in User Key segment (UK1) DIGEST_CHECK_UKDIGEST4 Carry out digest check on UKDIGEST4 in User Key segment (DPK) DIGEST_CHECK_UKDIGEST5 Carry out digest check on UKDIGEST5 in User Key segment (UPK2) DIGEST_CHECK_UKDIGEST6 Carry out digest check on UKDIGEST6 in User Key segment (UK2) DIGEST_CHECK_UPERM Carry out digest check on UFS Permanent lock (UPERM) segment DIGEST_CHECK_SYS Carry out digest check on Factory and Factory Key Segments. */ #define MSS_SYS_DIGEST_CHECK_FABRIC (0x01<<0x00u) #define MSS_SYS_DIGEST_CHECK_CC (0x01<<0x01u) #define MSS_SYS_DIGEST_CHECK_SNVM (0x01<<0x02u) #define MSS_SYS_DIGEST_CHECK_UL (0x01<<0x03u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST0 (0x01<<0x04u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST1 (0x01<<0x05u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST2 (0x01<<0x06u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST3 (0x01<<0x07u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST4 (0x01<<0x08u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST5 (0x01<<0x09u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST6 (0x01<<0x0au) #define MSS_SYS_DIGEST_CHECK_UPERM (0x01<<0x0bu) #define MSS_SYS_DIGEST_CHECK_SYS (0x01<<0x0cu) #define MSS_SYS_DIGEST_CHECK_UKDIGEST7 (0x01<<0x0du) #define MSS_SYS_DIGEST_CHECK_ENVM (0x01<<0x0eu) #define MSS_SYS_DIGEST_CHECK_UKDIGEST8 (0x01<<0x0fu) #define MSS_SYS_DIGEST_CHECK_UKDIGEST9 (0x01<<0x10u) #define MSS_SYS_DIGEST_CHECK_UKDIGEST10 (0x01<<0x11u) /*-------------------------------------------------------------------------*//** Mailbox ECC status Provides ECC status when the mailbox is read. The values are as follows: 00: No ECC errors detected, data is correct. 01: Exactly one bit erred and has been corrected. 10: Exactly two bits erred, no correction performed. 11: Reserved. */ #define MSS_SYS_MBOX_ECC_NO_ERROR_MASK 0x00u #define MSS_SYS_MBOX_ONEBIT_ERROR_CORRECTED_MASK 0x40u #define MSS_SYS_MBOX_TWOBIT_ERROR_MASK 0xC0u /*-------------------------------------------------------------------------*//** * Options for system services */ /*Execute UIC script source peripheral options UIC_SOURCE_PERIPH_UPROM Execute UIC from uPROM UIC_SOURCE_PERIPH_NONAUTHEN_SPIFLASH Execute UIC from SPI flash (Not Authenticated) UIC_SOURCE_PERIPH_SNVM Execute UIC from sNVM UIC_SOURCE_PERIPH_AUTHEN_SPIFLASH Execute UIC from SPI flash (Authenticated) */ #define MSS_SYS_UIC_SOURCE_PERIPH_UPROM 0x01u #define MSS_SYS_UIC_SOURCE_PERIPH_NONAUTHEN_SPIFLASH 0x02u #define MSS_SYS_UIC_SOURCE_PERIPH_SNVM 0x03u #define MSS_SYS_UIC_SOURCE_PERIPH_AUTHEN_SPIFLASH 0x06u /* Permitted key modes for one way Pass-code service * *NS -- Not Supported */ #define KM_INIT_FACTORY 0x00u/*NS*/ #define KM_ZERO_RECOVERY 0x01u/*NS*/ #define KM_DEFAULT_KEY 0x02u #define KM_USER_KEY1 0x03u #define KM_USER_KEY2 0x04u #define KM_AUTH_CODE 0x06u/*NS*/ #define KM_FACTORY_KEY 0x07u #define KM_FACTORY_EC 0x08u/*NS*/ #define KM_FACTORY_EC_E 0x09u/*NS*/ #define KM_USER_EC 0x12u/*NS*/ #define KM_USER_EC_E 0x13u/*NS*/ /*-------------------------------------------------------------------------*//** Callback function handler The callback handler is used by the application to indicate the user about the event of interrupt when the driver is configured to execute the system services in interrupt mode. The callback function handler is is registered to the MSS system service driver through the call to MSS_SYS_select_service_mode() function. The actual name of callback function handler is not important. User can select any name. */ typedef void (*mss_sys_service_handler_t)(void); /*-------------------------------------------------------------------------*//** The function MSS_SYS_read_response() is used to read the response after execution of system service in interrupt mode only. For polling mode call to MSS_SYS_read_response is not required, as the drive performs the response read operation. @param This function does not have any parameters. @return This function returns the status code returned by the system controller for requested service. Example: @code status = MSS_SYS_read_response(); @endcode */ uint16_t MSS_SYS_read_response ( void ); /*-------------------------------------------------------------------------*//** The MSS_SYS_service_mode() function is for user to configure system service execution in polling mode or interrupt mode. This function also registers the callback handler to the driver which will be called when message interrupt occurs. @param sys_service_mode User can decide whether to execute the service in polling mode or interrupt mode. Example: MSS_SYS_SERVICE_INTERRUPT_MODE MSS_SYS_SERVICE_POLLING_MODE @param mss_sys_service_interrupt_handler Callback function to the application. This function is invoked when message interrupt occurs. @return This function does not return any value. Example: @code MSS_SYS_service_mode(MSS_SYS_SERVICE_POLLING_MODE, mss_sys_service_interrupt_handler); @endcode */ void MSS_SYS_select_service_mode ( uint8_t sys_service_mode, mss_sys_service_handler_t mss_sys_service_interrupt_handler ); /*-------------------------------------------------------------------------*//** The MSS_SYS_get_serial_number() function fetches the 128-bit Device Serial Number (DSN). This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_serial_number The p_serial_number parameter is a pointer to a buffer in which the data returned by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns the status code returned by the system controller for this service. A '0' status code means that the service was executed successfully. | STATUS | Description | Note | |--------|----------------|-----------------------------| | 0 | Success | | | 1 | Error | DSN could not be read | */ uint16_t MSS_SYS_get_serial_number ( uint8_t * p_serial_number, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_get_user_code() is used to execute "USERCODE" system service. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_user_code The p_user_code parameter is a pointer to a buffer in which the data returned by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|------------------| | 0 | Success | */ uint16_t MSS_SYS_get_user_code ( uint8_t * p_user_code, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_get_design_info() is used to execute "Get Design Info" system service. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_design_info The p_design_info parameter is a pointer to a buffer in which the data returned by system controller will be copied. Total size of debug information is 76 bytes. Below listed fields in the 76 bytes information are "reserved bytes". They do not represent meaningful information and can be ignored. From offset 3 (size 1) From offset 18 (size 1) From offset 37 (size 4) From offset 42 (size 2) From offset 50 (size 2) From offset 65 (size 7) @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|------------------| | 0 | Success | */ uint16_t MSS_SYS_get_design_info ( uint8_t * p_design_info, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_get_device_certificate() is used to execute "Get Device Certificate" system service. @param p_device_certificate The p_device_certificate parameter is a pointer to a buffer in which the data returned by the system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | Note |----------|-------------------|------------------------------------------ | 0 | Success |Certificate is valid & consistent with | | |device | 1 | Signature invalid |Certificate signature is invalid | 2 | Device mismatch |Public key or FSN do not match device | 3 | System error |PUF or storage failure */ uint16_t MSS_SYS_get_device_certificate ( uint8_t * p_device_certificate, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_read_digest() is used to execute "Read Digest" system service. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_digest The p_digest parameter is a pointer to a buffer in which the data returned by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|------------------| | 0 | Success | */ uint16_t MSS_SYS_read_digest ( uint8_t * p_digest, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_query_security() is used to execute "Query Security" system service. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_security_locks The p_security_locks parameter is a pointer to a buffer in which the data returned by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|------------------| | 0 | Success | */ uint16_t MSS_SYS_query_security ( uint8_t * p_security_locks, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_read_debug_info() is used to execute "Read Debug info" system service. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_debug_info The p_debug_info parameter is a pointer to a buffer in which the data returned by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|------------------| | 0 | Success | */ uint16_t MSS_SYS_read_debug_info ( uint8_t * p_debug_info, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_read_envm_parameter() is used to retrieve all parameters needed for eNVM operation and programming. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_envm_param The p_envm_param parameter specifies the the user buffer which will be accumulated with envm parameters after the service completes execution. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | Note | |--------|----------------|--------------------------------| | 0 | Success | | | 1 | Digest Error |Page digest mismatches. | | | |Parameter values still returned.| */ uint16_t MSS_SYS_read_envm_parameter ( uint8_t * p_envm_param, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_execute_uic_script() function is used to execute UCI script service. This service allows the user to invoke a UIC script stored in any of the available non-volatile memory sources. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param src_periph_type The src_periph_type parameter specifies the type of non-volatile memory in which the UIC script is stored. Below is the list of all available peripheral options. SRC Location 0 Reserved 1 PROM 2 SPI flash (Not Authenticated) 3 SNVM 4 Reserved 5 Reserved 6 SPI flash (Authenticated) 7 Reserved @param periph_address The periph_address parameter specifies the address within the selected non-volatile memory where the UIC script is stored. The address format is different for different peripherals. Below is the list of peripherals and corresponding addresses. uPROM memory -- IP Segment/Block Address SNVM memory -- SNVM Module number. SPI FLash (Authenticated or NonAuthenticated) - 24 or 32 bit address. This function will adjust the provided value to fit into the format expected by system controller. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description | |---------|---------------------------------| | 0 | Successful completion | | 1 | SPI Max Frame Error | | 2 | Poll Time out | | 3 | SPI Authentication Error | | 4 | SPI Decryption Error | | 5 | SPI Not Master Error | | 6 | Fabric APB Error | | 7 | SCB Error | | 8 | PNVM Encrypted Error | | 9 | Address out of Range Error | | 10 | Jump Max Error | | 11 | Unexpected Format Error | | 12 | Script Time out Error | */ uint16_t MSS_SYS_execute_uic_script ( uint8_t src_periph_type, uint32_t periph_address, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_authenticate_uic_bitstream() function is used to authenticate the UIC Bitstream which is located in SPI through a system service routine. This service is applicable to UIC scripts stored in SPI Flash memory only. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param spi_flash_address The spi_flash_address parameter specifies the address within SPI Flash memory where the UIC script is stored. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description | |---------|---------------------------------| | 0 | Successful completion | | 1 | SPI Max Frame Error | | 2 | Poll Time out | | 3 | SPI Authentication Error | | 4 | SPI Decryption Error | | 5 | SPI Not Master Error | | 6 | Fabric APB Error | | 7 | SCB Error | | 8 | PNVM Encrypted Error | | 9 | Address out of Range Error | | 10 | Jump Max Error | | 11 | Unexpected Format Error | | 12 | Script Time out Error | */ uint16_t MSS_SYS_authenticate_uic_bitstream ( uint32_t spi_flash_address, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_authenticate_bitstream() function is used to authenticate the Bitstream which is located in SPI through a system service routine. Prior to using the IAP service, it may be required to first validate the new bitstream before committing the device to reprogramming, thus avoiding the need to invoke recovery procedures if the bitstream is invalid. This service is applicable to bitstreams stored in SPI Flash memory only. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param spi_flash_address The spi_flash_address parameter specifies the address within SPI Flash memory where the bit-stream is stored. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description | |----------|-----------------------------------------------| | 0 | No error | | 1 | Validator or hash chaining mismatch | | 2 | Unexpected data received | | 3 | Invalid/corrupt encryption key | | 4 | Invalid component header | | 5 | Back level not satisfied | | 6 | Illegal bitstream mode | | 7 | DSN binding mismatch | | 8 | Illegal component sequence | | 9 | Insufficient device capabilities | | 10 | Incorrect DEVICEID | | 11 | Unsupported bitstream protocol version | | | (regeneration required) | | 12 | Verify not permitted on this bitstream | | 13 | Invalid Device Certificate | | 14 | Invalid DIB | | 21 | Device not in SPI Master Mode | | 22 | No valid images found | | 23 | No valid images found | | 24 | Programmed design version is newer than Auto | | | Update image found | | 25 | Reserved | | 26 | Selected image was invalid and no recovery | | | was performed due to valid design in device | | 27 | Selected and Recovery image failed to program| | 127 | Abort | | 128 | NVMVERIFY | | 129 | PROTECTED | | 130 | NOTENA | | 131 | PNVMVERIFY | | 132 | SYSTEM | | 133 | BADCOMPONENT | | 134 | HVPROGERR | | 135 | HVSTATE | */ uint16_t MSS_SYS_authenticate_bitstream ( uint32_t spi_flash_address, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_authenticate_iap_image() function is used to authenticate the IAP image which is located in SPI through a system service routine. The service checks the image descriptor and the referenced bitstream and optional initialization data. If the image is authenticated successfully, then the image is guaranteed to be valid when used by an IAP function. This service is applicable to bitstreams stored in SPI Flash memory only. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param spi_idx The spi_idx parameter specifies the index in the SPI directory to be used where the IAP bit-stream is stored. Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an empty slot it shouldn't be passed into the system service. @return The MSS_SYS_authenticate_iap_image function returns one of following status codes. The status code indicates the success/failure status of the service execution. | STATUS | Description | |----------|-----------------------------------------------| | 0 | No error | | 1 | Validator or hash chaining mismatch | | 2 | Unexpected data received | | 3 | Invalid/corrupt encryption key | | 4 | Invalid component header | | 5 | Back level not satisfied | | 6 | Illegal bitstream mode | | 7 | DSN binding mismatch | | 8 | Illegal component sequence | | 9 | Insufficient device capabilities | | 10 | Incorrect DEVICEID | | 11 | Unsupported bitstream protocol version | | | (regeneration required) | | 12 | Verify not permitted on this bitstream | | 13 | Invalid Device Certificate | | 14 | Invalid DIB | | 21 | Device not in SPI Master Mode | | 22 | No valid images found | | 23 | No valid images found | | 24 | Programmed design version is newer than Auto | | | Update image found | | 25 | Reserved | | 26 | Selected image was invalid and no recovery | | | was performed due to valid design in device | | 27 | Selected and Recovery image failed to program| | 127 | Abort | | 128 | NVMVERIFY | | 129 | PROTECTED | | 130 | NOTENA | | 131 | PNVMVERIFY | | 132 | SYSTEM | | 133 | BADCOMPONENT | | 134 | HVPROGERR | | 135 | HVSTATE | */ uint16_t MSS_SYS_authenticate_iap_image ( uint32_t spi_idx ); /*-------------------------------------------------------------------------*//** The MSS_SYS_puf_emulation_service() function accept a challenge comprising a 8-bit optype and 128-bit challenge and return a 256-bit response unique to the given challenge and the device. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_challenge The p_challenge parameter specifies the 128-bit challenge to be used to generate the unique 256-bits unique response. @param op_type The op_type parameter specifies the operational parameter to be used to generate the unique 256-bits unique response. @param p_response The p_response parameter is a pointer to a buffer in which the data returned i.e. response by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description |--------|-----------------| | 0 | SUCCESS | | 1 | INTERNAL ERROR| | | | */ uint16_t MSS_SYS_puf_emulation_service ( uint8_t * p_challenge, uint8_t op_type, uint8_t* p_response, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_digital_signature_service() function is used to generate P-384 ECDSA signature based on SHA384 hash value. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param p_hash The p_hash parameter is a pointer to the buffer which contain the 48 bytes SH384 Hash value(input value). @param format The format parameter specifies the output format of generated SIGNATURE field. The different types of output signature formats are as follow: - DIGITAL_SIGNATURE_RAW_FORMAT - DIGITAL_SIGNATURE_DER_FORMAT @param p_response The p_response parameter is a pointer to a buffer which contain the generated ECDSA signature. The field may be 96 bytes or 104 bytes depend upon the output format. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | |-------|--------------------------------------| | 0 | Success | | 1 | FEK Failure Error retrieving FEK | | 2 | DRBG Error Failed to generate nonce | | 3 | ECDSA Error ECDSA failed | */ uint16_t MSS_SYS_digital_signature_service ( uint8_t* p_hash, uint8_t format, uint8_t* p_response, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_secure_nvm_write() function is used to provide write access/write the data in the sNVM region. Data can be stored in the following format: - Non-authenticated plaintext, - Authenticated plaintext - Authenticated ciphertext This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param format The format parameter specifies the format used to write data in sNVM region. The different type of text formats are as follow: - NON_AUTHENTICATED_PLAINTEXT_FORMAT - AUTHENTICATED_PLAINTEXT_FORMAT - AUTHENTICATED_CIPHERTEXT_FORMAT @param snvm_module The snvm_module parameter specifies the the sNVM module in which the data need to be written. @param p_data The p_data parameter is a pointer to a buffer which contains the data to be stored in sNVM region. The data length to be written is if fixed depending on the format parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is selected then you can write 252 bytes in the sNVM module. For other two formats the data length is 236 bytes. @param p_user_key The p_user_key parameter is a pointer to a buffer which contain the 96-bit key USK (user secret key). This user secret key will enhance the security when authentication is used.(i.e. When Authenticated plaintext and Authenticated ciphertext format is selected). @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|-------------------------------------------------| | 0 | Success | | 1 | Invalid SNVMADDR Illegal page address | | 2 | Write failure PNVM program/verify failed | | 3 | System error PUF or storage failure | | 4 | Write Not Permitted ROMFLAG is set | | 5 | Access failure Write Access from either Fabric| | | or MSS was blocked (PolarFire SoC only) | */ uint16_t MSS_SYS_secure_nvm_write ( uint8_t format, uint8_t snvm_module, uint8_t* p_data, uint8_t* p_user_key, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_secure_nvm_read() function is used to read data present in sNVM region. User should provide USK key, if the data was programmed using authentication. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param snvm_module The snvm_module parameter specifies the sNVM module from which the data need to be read. @param p_user_key The p_user_key parameter is a pointer to a buffer which contain the 96-bit key USK (user secret key). User should provide same secret key which is previously used for authentication while writing data in sNVM region. @param p_admin The p_admin parameter is a pointer to the buffer where the output page admin data will be stored. The page admin data is 4 bytes long. @param p_data The p_data parameter is a pointer to a buffer which contains the data read from sNVM region. User should provide the buffer large enough to store the read data. @param data_len The data_len parameter specifies the number of bytes to be read from sNVM. The application should know whether the data written in the chose sNVM module was previously stored using Authentication or not. The data_len should be 236 bytes, for authenticated data, for not authenticated data the data_len should be 252 bytes. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description Note | |--------|-------------------------------------------------| | 0 | Success | | 1 | Invalid SNVMADDR Illegal page address | | 2 | Write failure PNVM program/verify failed | | 3 | System error PUF or storage failure | | 4 | Write Not Permitted ROMFLAG is set | | 5 | Access failure Write Access from either Fabric| | | or MSS was blocked (PolarFire SoC only) | */ uint16_t MSS_SYS_secure_nvm_read ( uint8_t snvm_module, uint8_t* p_user_key, uint8_t* p_admin, uint8_t* p_data, uint16_t data_len, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The function MSS_SYS_nonce_service() is used to issue "Nonce Service" system service to the system controller. @param p_nonce The p_nonce parameter is a pointer to a buffer in which the data returned by system controller will be copied. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns the status code returned by the system controller for this service. A '0' status code means that the service was executed successfully. | STATUS | Description | |------------|------------------------------------------| | 0 | Success completion (exit) | | 1 | Error fetching PUK | | 2 | Error generating seed | */ uint16_t MSS_SYS_nonce_service ( uint8_t * p_nonce, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_digest_check() function is used to Recalculates and compares digests of selected non-volatile memories. This service is applicable to bitstream stored in SPI Flash memory only. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param options The options parameter specifies the digest check options which indicate the area on which the digest check should be performed. Below is the list of options. You can OR these options to indicate to perform digest check on multiple segments. | Options[i] | Description | |-------------|---------------------------------------------| | 0x01 | Fabric digest | | 0x02 | Fabric Configuration (CC) segment | | 0x04 | ROM digest in SNVM segment | | 0x08 | UL segment | | 0x10 | UKDIGEST0 in User Key segment | | 0x20 | UKDIGEST1 in User Key segment | | 0x40 | UKDIGEST2 in User Key segment (UPK1) | | 0x80 | UKDIGEST3 in User Key segment (UK1) | | 0x100 | UKDIGEST4 in User Key segment (DPK) | | 0x200 | UKDIGEST5 in User Key segment (UPK2) | | 0x400 | UKDIGEST6 in User Key segment (UK2) | | 0x800 | UFS Permanent lock (UPERM) segment | | 0x1000 | Factory and Factory Key Segments. | | 0x2000 | UKDIGEST7 in User Key segment (HWM) | | 0x4000 | ENVMDIGEST | | 0x8000 | UKDIGEST8 for MSS Boot Info | | 0x10000 | SNVM_RW_ACCESS_MAP Digest | | 0x20000 | SBIC revocation digest | @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param digesterr The digesterr parameter specifies the set bit in case of DIGESTERR. | DIGESTERR[i]| Description | |-------------|---------------------------------------------| | 0x01 | Fabric digest | | 0x02 | Fabric Configuration (CC) segment | | 0x04 | ROM digest in SNVM segment | | 0x08 | UL segment | | 0x10 | UKDIGEST0 in User Key segment | | 0x20 | UKDIGEST1 in User Key segment | | 0x40 | UKDIGEST2 in User Key segment (UPK1) | | 0x80 | UKDIGEST3 in User Key segment (UK1) | | 0x100 | UKDIGEST4 in User Key segment (DPK) | | 0x200 | UKDIGEST5 in User Key segment (UPK2) | | 0x400 | UKDIGEST6 in User Key segment (UK2) | | 0x800 | UFS Permanent lock (UPERM) segment | | 0x1000 | Factory and Factory Key Segments. | | 0x2000 | UKDIGEST7 in User Key segment (HWM) | | 0x4000 | ENVMDIGEST | | 0x8000 | UKDIGEST8 for MSS Boot Info | | 0x10000 | SNVM_RW_ACCESS_MAP Digest | | 0x20000 | SBIC revocation digest | @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS DIGESTERR[i] | Description | |---------------------|----------------------------------------| | 1 or 0 |1 is returned if any of DIGESTERR bits | | |are set | */ uint16_t MSS_SYS_digest_check ( uint32_t options, uint8_t* digesterr, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_execute_iap() function is used to IAP service. The IAP service allows the user to reprogram the device without the need for an external master. The user design writes the bitstream to be programmed into a SPI Flash connected to the SPI port. When the service is invoked, the System Controller automatically reads the bitstream from the SPI flash and programs the device. The service allows the image to be executed in either VERIFY or PROGRAM modes. Another option for IAP is to perform the auto-update sequence. In this case the newest image of the first two images in the SPI directory is chosen to be programmed. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param iap_cmd The iap_cmd parameter specifies the specific IAP command which depends upon VERIFY or PROGRAM modes and the SPI address method. iap_cmd Description IAP_PROGRAM_BY_SPIIDX_CMD IAP program. IAP_VERIFY_BY_SPIIDX_CMD Fabric Configuration (CC) segment IAP_PROGRAM_BY_SPIADDR_CMD ROM digest in SNVM segment IAP_VERIFY_BY_SPIADDR_CMD UL segment IAP_AUTOUPDATE_CMD UKDIGEST0 in User Key segment @param spiaddr The spiaddr parameter specifies the either the either the index in the SPI directory or the SPI address in the SPI Flash memory. Below is the list of the possible meaning of spiaddr parameter in accordance with the iap_cmd parameter. iap_cmd spiaddr IAP_PROGRAM_BY_SPIIDX_CMD Index in the SPI directory. IAP_VERIFY_BY_SPIIDX_CMD Index in the SPI directory. IAP_PROGRAM_BY_SPIADDR_CMD SPI address in the SPI Flash memory IAP_VERIFY_BY_SPIADDR_CMD SPI address in the SPI Flash memory IAP_AUTOUPDATE_CMD spiaddr is ignored as No index/ address required for this command. Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an empty slot and the recovery image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an empty slot it shouldn't be passed into the system service. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description | |----------|-----------------------------------------------| | 0 | No error | | 1 | Validator or hash chaining mismatch | | 2 | Unexpected data received | | 3 | Invalid/corrupt encryption key | | 4 | Invalid component header | | 5 | Back level not satisfied | | 6 | Illegal bitstream mode | | 7 | DSN binding mismatch | | 8 | Illegal component sequence | | 9 | Insufficient device capabilities | | 10 | Incorrect DEVICEID | | 11 | Unsupported bitstream protocol version | | | (regeneration required) | | 12 | Verify not permitted on this bitstream | | 13 | Invalid Device Certificate | | 14 | Invalid DIB | | 21 | Device not in SPI Master Mode | | 22 | No valid images found | | 23 | No valid images found | | 24 | Programmed design version is newer than Auto | | | Update image found | | 25 | Reserved | | 26 | Selected image was invalid and no recovery | | | was performed due to valid design in device | | 27 | Selected and Recovery image failed to program| | 127 | Abort | | 128 | NVMVERIFY | | 129 | PROTECTED | | 130 | NOTENA | | 131 | PNVMVERIFY | | 132 | SYSTEM | | 133 | BADCOMPONENT | | 134 | HVPROGERR | | 135 | HVSTATE | */ uint16_t MSS_SYS_execute_iap ( uint8_t iap_cmd, uint32_t spiaddr ); /*-------------------------------------------------------------------------*//** The MSS_SYS_spi_copy() function allows data to be copied from the system controller SPI flash to MSS memory. The SPI SCK frequency is specified by a user-defined option allowing for a maximum SCK frequency of 80MHz. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param mss_dest_addr The 64-bit mss_dest_addr parameter specifies the destination address in MSS where system controller copies data from SPI flash. @param mss_spi_flash The 32-bit mss_spi_flash parameter specifies the source address of data to be copied in MSS. @param n_bytes The n_bytes parameter specifies the number of bytes to transfer. @param options The 8 bit options parameter specifies the SPI clk divider configuration. OPTIONS[i] Name Description 1:0 CLKDIV SPI clock divider configuration. 0=80MHz, 1=40MHz, 2=20MHz, 3=13.33MHz 7:2 RESERVED Reserved for future use @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS |Description | |----------|---------------------------------------------| | 0 | Success | | 1 | Device not configured for master mode | | 2 | AXI Error | */ uint16_t MSS_SYS_spi_copy ( uint64_t mss_dest_addr, uint32_t mss_spi_flash, uint32_t n_bytes, uint8_t options, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_read_probe() function will read the content of a probe module (59 x 18b words). This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. Note: The IPROWADDR & IPSEGADDR addresses are not incremented as the associated address space is not contiguous. If PRBADDR is 63 it will wrap back to 0. @param ipseg_addr The ipseg_addr parameter specifies the probe segment address. @param iprow_addr The iprow_addr parameter specifies the probe row address. ipseg_addr and iprow_addr parameters specifies the target address of probe module. @param prdata The prdata parameter specifies the read data for probe word i(0 to 58) within the probe module. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param resp_offset The resp_offset parameter specifies the offset of the start of Mailbox response where the data received from the service will be available. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | | |---------|---------------|-------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by | | | | device security. | */ uint16_t MSS_SYS_debug_read_probe ( uint8_t ipseg_addr, uint8_t iprow_addr, uint8_t *prdata, uint16_t mb_offset, uint8_t resp_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_write_probe() function will writes up to 18 bits of data to selected probe address. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param prb_addr The prb_addr parameter specifies the probe address. @param ipseg_addr The ipseg_addr parameter specifies the probe segment address. @param iprow_addr The iprow_addr parameter specifies the probe row address. prb_addr, ipseg_addr and iprow_addr parameters specifies the target address of one of the 59 words within a probe module. @param pwmask The pwmask parameter specifies the which of the 18 bits of pwdata shall be written to selected probe module. @param pwdata The pwdata parameter specifies the value to be written on selected probe registers. Example: If PWMASK[i] is '1' then probe register i will be written to the value specified by PWDATA[i]. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | | |---------|---------------|-------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by | | | | device security. | */ uint16_t MSS_SYS_debug_write_probe ( uint8_t prb_addr, uint8_t ipseg_addr, uint8_t iprow_addr, uint32_t pwmask, uint32_t pwdata, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_live_probe() function will configures channel a or b of the live probe system. A live probe is enabled by writing a local address register within one of the probe segment modules. Each probe segment module generates its own local channel a live probe outputs which are combined by OR chains to generate a chip-level live probe channel a signal. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. Note: - When configuring channel a, channel b is not affected and vice versa. - Live probes are intentionally not cleared by JTAG reset. They remain in effect until either manually disabled or the device is reset. @param x_addr The parameter x_addr specifies the x co-ordinate within target probe module. @param y_addr The parameter y_addr specifies the y co-ordinate within the target probe module. @param ipseg_addr The ipseg_addr parameter specifies the probe segment address. @param iprow_addr The iprow_addr parameter specifies the probe row address. ipseg_addr and iprow_addr parameters specifies the target address of probe module. @param clear The clear parameter is used to clear the configurations of local channels a or b. If CLEAR is '1', all local channel x (the applicable channel a or b) configurations are cleared before applying the new configuration @param ioen The ioen parameter is used to activate the probe output pad. If IOEN is '1' then the corresponding live probe output pad is activated. Note that setting IOEN to '0' does not disable the internal live probe configuration. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param service_cmd The service_cmd parameter specifies the channel(channel a or b) selected by the user. User have to provide one of the predefined macros to select the channel for live probe debug operation. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | | |---------|---------------|-------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by | | | | device security. | */ uint16_t MSS_SYS_debug_live_probe ( uint8_t x_addr, uint8_t y_addr, uint8_t ipseg_addr, uint8_t iprow_addr, uint8_t clear, uint8_t ioen, uint16_t mb_offset, uint8_t service_cmd ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_select_mem() function will specifies a target fabric memory to be accessed by the MEM read & MEM write services. A handshake mechanism is used to request access to the target memory. The memory lock may be acquired immediately allowing multiple read/write operations to be performed as one logical transaction or the lock may be acquired and released by individual read/write operations. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param ipblk_addr The ipblk_addr parameter specifies the block address of fabric memory. @param ipseg_addr The ipseg_addr parameter specifies the segment address. @param iprow_addr The iprow_addr parameter specifies the row address of fabric memory to be accessed by MEM read and MEM write services. @param memtype The memtype parameter specifies the type of fabric memory to be used for MEM read and write services. MEMTYPE Peripheral MEMSIZE(words) Access Width 0 LSRAM x1 16384 1 1 LSRAM x2 8192 2 2 LSRAM x5 4096 5 3 LSRAM x10 2048 10 4 LSRAM x20 1024 20 5 uRAM 64 12 6 uPROM 256 9 7 LSRAM x20 1024 20 @param memlock_mode The memlock_mode parameter specifies the the memory lock states for supported MEMLOCKMODE values. @param timeout When a lock is requested we must consider a scenario where the user design may not complete the request handshake. To prevent the firmware from waiting indefinitely, the user must specify a timeout after which time the handshake is aborted. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | | |---------|---------------|-------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by | | | | device security. | | 2 | TIMEOUTERR | Timeout occurred. | | 3 | LOCKERR | Target memory failed to lock | */ uint16_t MSS_SYS_debug_select_mem ( uint8_t ipblk_addr, uint8_t ipseg_addr, uint8_t iprow_addr, uint8_t memtype, uint8_t memlock_mode, uint16_t timeout, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_read_mem() function provides an interface to read data from the memory peripheral that is specified. A handshake mechanism is used to request access to the target memory. The memory lock may be acquired immediately allowing multiple read/write operations to be performed as one logical transaction. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param mem_addr The mem_addr parameter sets the target address within the currently selected memory peripheral for subsequent mem write & mem read instructions. @param n_words The n_words parameter value depends on memtype. The maximum limit is the size of memory. @param mss_addr The mss_addr parameter specifies the MSS RAM area where to copy the MEM Read data to. Note that all accesses will be done with MSS User privileges. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | | |---------|---------------|-------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by | | | | device security. | | 2 | TIMEOUTERR | Timeout occurred. | | 3 | LOCKERR | Target memory failed to lock | */ uint16_t MSS_SYS_debug_read_mem ( uint16_t mem_addr, uint16_t n_words, uint64_t mss_addr, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_write_mem() function provides an interface to write data from the memory peripheral that is specified. A handshake mechanism is used to request access to the target memory. The memory lock may be acquired immediately allowing multiple read/write operations to be performed as one logical transaction. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param mem_addr The mem_addr parameter sets the target address within the currently selected memory peripheral for subsequent mem write & mem read instructions. @param n_words The n_words parameter value depends on memtype. The maximum limit is the size of memory. @param mss_addr The mss_addr parameter specifies the MSS RAM area where to copy the MEM Read data to. Note that all accesses will be done with MSS User privileges. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | | |---------|---------------|-------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by | | | | device security. | | 2 | TIMEOUTERR | Timeout occurred. | | 3 | LOCKERR | Target memory failed to lock | */ uint16_t MSS_SYS_debug_write_mem ( uint16_t mem_addr, uint16_t n_words, uint64_t mss_addr, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_read_apb() function reads a specified number of bytes from the fabric APB bus to the specified MSS RAM area. The operation makes the required number of read transactions using the selected transaction size, APBDWSIZE. The addressed fabric peripheral may generate an error or fail to respond within a user-defined window, in which case any subsequent transfers are aborted and corresponding error flags are returned. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param apb_addr The apb_addr parameter specifies the target address and transfer size for the apb write & apb read operations. @param apb_wsize The apb_wsize parameter specifies the data transfer size to be used by the apb write & apb read operations. @param max_bytes The max_bytes parameter is used in calculation specified number of bytes from the fabric APB bus to the Shared Buffer. NBYTES = MAXBYTES + 1 @param mss_addr The mss_addr parameter specifies the MSS RAM area where to copy the MEM Read data to. Note that all accesses will be done with MSS User privileges. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description| | |---------|------------|-------------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by device | | | | security. | | 2 | SLVERR | The addressed fabric APB peripheral | | | | generated a SLVERR response to the | | | | bus transaction. | | 3 | TIMEOUT | The addressed fabric APB peripheral | | | | failed to respond before the | | | | user-defined APB timeout or the | | | | fabric power is not on. | */ uint16_t MSS_SYS_debug_read_apb ( uint32_t apb_addr, uint8_t apb_wsize, uint16_t max_bytes, uint64_t mss_addr, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_write_apb() function writes bytes of data to the current fabric APB address as specified by APBADDR. The addressed fabric peripheral may generate an error or fail to respond within a user-defined window, in which case the corresponding error flags are returned. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param apb_addr The apb_addr parameter specifies the target address and transfer size for the apb write & apb read operations. @param apb_wsize The apb_wsize parameter specifies the data transfer size to be used by the apb write & apb read operations. @param max_bytes The max_bytes parameter is used in calculation specified number of bytes from the fabric APB bus to the Shared Buffer. NBYTES = MAXBYTES + 1 @param mss_addr The mss_addr parameter specifies the MSS RAM area where to copy the MEM Read data to. Note that all accesses will be done with MSS User privileges. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description| | |---------|------------|-------------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by device | | | | security. | | 2 | SLVERR | The addressed fabric APB peripheral | | | | generated a SLVERR response to the | | | | bus transaction. | | 3 | TIMEOUT | The addressed fabric APB peripheral | | | | failed to respond before the | | | | user-defined APB timeout or the | | | | fabric power is not on. | */ uint16_t MSS_SYS_debug_write_apb ( uint32_t apb_addr, uint8_t apb_wsize, uint16_t max_bytes, uint64_t mss_addr, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_fabric_snapshot() function will service generates a snapshot of the volatile fabric content. Data is read from each LSRAM, uRAM and probe module and copied to the fabric APB debug port. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param port_addr The port_addr parameter sets the address of the APB port to be used for bulk access debug instructions which are used in conjunction with Microsemi fabric debug IP. The debug port is a single location on the fabric APB bus through which debug data is streamed. @param apb_fast_write The apb_fast_write parameter specifies whether to use the fast apb protocol. If apb_fast_write is '1' then, during write transfers, the fast APB protocol is used and the address range is limited to port_addr[15:2] and port_addr[28:16] is ignored. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description| | |---------|------------|-------------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by device | | | | security. | | 2 | BUSERR | Bus error occurred and the snapshot | | | | was aborted. | */ uint16_t MSS_SYS_debug_fabric_snapshot ( uint32_t port_addr, uint8_t apb_fast_write, uint16_t mb_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_otp_generate() function is used to set up the device to The receive a one-time passcode. A 128-bit nonce, NFPGA, is generated and The stored in volatile memory for later use in the rest of the protocol. The A 128-bit user nonce, NUSER, is supplied by the user. This service only unlocks the software debug lock SWL_DEBUG. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param keymode keymode parameter specifies the key mode to be used to transport the encrypted passcode. The KEYMODE parameter is not checked for validity until the MATCH OTP service is executed. Both PCTYPE and KEYMODE are stored in volatile memory for use by the MATCH OTP service. Supported values for KEYMODE are shown below. PCTYPE KEYMODE Key Mode KROOT Note 1 3 KM_USER_KEY1 UK1 User key 1 1 4 KM_USER_KEY2 UK2 User key 2 1 7 KM_FACTORY_KEY DFK FK diversified by UID @param n_user The n_user parameter specifies the user nonce, is supplied by the user. @param n_fpga The n_fpga parameter specifies the 128-bit nonce, NFPGA, is generated and stored in volatile memory for later use in the rest of the protocol. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param ret_offset The ret_offset parameter specifies the offset of the start of Mailbox response where the data received from the service will be available. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. If any part of the service fails, then all unlocked passcodes are re-locked and the tamper event PASSCODE_FAIL is generated. | STATUS | Description| | |---------|------------|-------------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by device | | | | security. | | 2 | PROTOCOLERR| If an invalid key mode is specified | | | | fails then the returned nonce is | | | | 0^128, the protocol is aborted and | | | | the tamper event PASSCODE_FAIL is | | | | generated. | */ uint16_t MSS_SYS_otp_generate ( uint8_t keymode, uint8_t* n_user, uint8_t* n_fpga, uint16_t mb_offset, uint16_t resp_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_otp_match() function is the second part of the one-time passcode protocol. Before using this service the GENERATE OTP service must first be used to obtain a nonce, NFPGA, from the device. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param user_id The UID parameter is only used if the KEYMODE used for the GENERATE OTP service was KEYMODE_FACTORY_KEY and the passcode was not the Factory Passcode. @param validator The 256-bit validator parameter store the validator key. @param otp The otp parameter stores the otp value from generate otp service. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param resp_offset The resp_offset parameter specifies the offset from the start of Mailbox response where the data received from the service will be available. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS| Description | |------|-----------------| | 0 | Success | | 1 | PROTOCOLERR | | 2 | MISMATCHERR | */ uint16_t MSS_SYS_otp_match ( uint8_t * user_id, uint8_t * validator, uint8_t * otp, uint16_t mb_offset, uint16_t resp_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_unlock_debug_passcode() function will Attempt to match the user debug pass code using the key loaded into the mailbox. If the match is successful the software debug lock SWL_DEBUG is temporarily inactive. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param cmd_data The parameter cmd_data specifies the device's debug passcode (DPK), configured by the user via bitstream. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param ret_offset The ret_offset parameter specifies the offset from the start of Mailbox response where the data received from the service will be available. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description| | |---------|------------|-------------------------------------| | 0 | Success | | | 1 | SECERR | The operation was blocked by device | | | | security. | | 2 | PROTOCOLERR| If the unlock operation fail for any| | | | reason, then the tamper event | | | | PASSCODE_FAIL is generated. | If any part of the service fails, then all unlocked passcodes are re-locked and the tamper event PASSCODE_FAIL is generated. */ uint16_t MSS_SYS_unlock_debug_passcode ( uint8_t* cmd_data, uint16_t mb_offset, uint16_t resp_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_one_way_passcode() function is used to provide a mechanism for overriding the software debug lock SWL_DEBUG without requiring any interaction with an external intelligence. The following conditions must be met for the OWP to proceed and write the payload HWM to the device: * HWM stored in the device must be valid * OWP passcode matches * Payload HWM is greater than the HWM stored in the device After HWM is written the OWP is successful and SWL_DEBUG is unlocked. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param msg_id The msg_id parameter stores the value of message ID. @param validator The 256-bit validator parameter store the validator key. @param keymode The Keymode parameter specifies the permitted keymodes for OWP service. KEYID Key Mode Permitted 0 KM_INIT_FACTORY No 1 KM_ZERO_RECOVERY No 2 KM_DEFAULT_KEY Yes 3 KM_USER_KEY1 Yes 4 KM_USER_KEY2 Yes 5 - 6 KM_AUTH_CODE No 7 KM_FACTORY_KEY Yes 8 KM_FACTORY_EC No 9 KM_FACTORY_EC_E No 10 - 11 - 12 KM_USER_EC No 13 KM_USER_EC_E No 14 - 15 - @param dsn The dsn parameter stores the value of device serial number. @param hash The hash parameter stores 256-bit hash value. @param plaintext_passcode The plaintext_passcode parameter stores the passcode value. @param hwm The hwm parameter stores the high water mark value. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param ret_offset The ret_offset parameter specifies the offset from the start of Mailbox response where the data received from the service will be available. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. | STATUS | Description| | |---------|------------|-------------------------------------| | 0 | Success | | | 1 | OWPERR | If the unlock operation fail for any| | | | reason, then the tamper event | | | | PASSCODE_FAIL is generated. | If any part of the service fails, then all unlocked passcodes are re-locked and the tamper event PASSCODE_FAIL is generated. */ uint16_t MSS_SYS_one_way_passcode ( uint8_t* msg_id, uint8_t* validator, uint8_t keymode, uint8_t* dsn, uint8_t* hash, uint8_t* plaintext_passcode, uint8_t* hwm, uint16_t mb_offset, uint16_t resp_offset ); /*-------------------------------------------------------------------------*//** The MSS_SYS_debug_terminate() function will terminate the debug session. Its purpose is to re-lock all the software based debug locks (SWL_DEBUG) if needed and to release any memories previously locked using the MEM Select Debug Service. This function is non-blocking in the interrupt mode , in that, it will exit immediately after requesting the service. In polling mode, it becomes a blocking function. It will block until the the service is completed and a response is received from the system controller. @param mb_offset The mb_offset parameter specifies the offset from the start of mailbox where the data related to this service is available. All accesses to the mailbox are of word length (4 bytes). A value 10 (decimal) of this parameter would mean that the data access area for this service, in the mailbox starts from 11th word (offset 10). @param resp_offset The resp_offset parameter specifies the offset from the start of Mailbox, where the data received from the service will be available. @return This function returns a value to indicate whether the service was executed successfully or not. A zero value indicates that the service was executed successfully. A non-zero value can indicate that either the driver was not able to kick-start the service or that the driver was able to kick-start the service and receive a status response code from the system controller. See theory of operations section for detailed information about the return status. The following table lists the service status code from system controller. |STATUS | Description | |-------|--------------| | 0 | Success | */ uint16_t MSS_SYS_debug_terminate ( uint16_t mb_offset, uint16_t resp_offset ); typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t VDETECTOR; volatile uint32_t TVS_CONTROL; volatile uint32_t TVS_TEMP_A; volatile uint32_t TVS_TEMP_B; volatile uint32_t TVS_TEMP_C; volatile uint32_t TVS_VOLT_A; volatile uint32_t TVS_VOLT_B; volatile uint32_t TVS_VOLT_C; volatile uint32_t TVS_OUTPUT0; volatile uint32_t TVS_OUTPUT1; volatile uint32_t TVS_TRIGGER; volatile uint32_t TRIM_VDET1P05; volatile uint32_t TRIM_VDET1P8; volatile uint32_t TRIM_VDET2P5; volatile uint32_t TRIM_TVS; volatile uint32_t TRIM_GDET1P05; volatile uint32_t RESERVED0; volatile uint32_t RESERVED1; volatile uint32_t RESERVED2; volatile uint32_t SERVICES_CR; volatile uint32_t SERVICES_SR; volatile uint32_t USER_DETECTOR_SR; volatile uint32_t USER_DETECTOR_CR; volatile uint32_t MSS_SPI_CR; } SCBCTRL_TypeDef; #define MSS_SCBCTRL ((SCBCTRL_TypeDef*) (0x37020000UL)) /*2kB bytes long mailbox.*/ #define MSS_SCBMAILBOX ((uint32_t*) (0x37020800UL)) /*SCB message register*/ #define MSS_SCBMESSAGE ((uint32_t*) (0x20003190UL)) /*SCB message interrupt register*/ #define MSS_SCBMESSAGE_INT ((uint32_t*) (0x2000318CUL)) #ifdef __cplusplus } #endif #endif /* MSS_SYS_SERVICES_H_ */ mss_sys_services_regs.h000066400000000000000000000040311432224323300434500ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_sys_services /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC MSS system * services * * SVN $Revision$ * SVN $Date$ */ #ifndef MSS_SYS_SERVICES_REGS_H_ #define MSS_SYS_SERVICES_REGS_H_ #ifdef __cplusplus extern "C" { #endif /***************SCBCTRL SERVICES_CR register*************************/ #define SCBCTRL_SERVICESCR_REQ (0u) #define SCBCTRL_SERVICESCR_REQ_MASK (1u << SCBCTRL_SERVICESCR_REQ) #define SCBCTRL_SERVICESCR_BUSY (1u) #define SCBCTRL_SERVICESCR_BUSY_MASK (1u << SCBCTRL_SERVICESCR_BUSY) #define SCBCTRL_SERVICESCR_ABORT (2u) #define SCBCTRL_SERVICESCR_ABORT_MASK (1u << SCBCTRL_SERVICESCR_ABORT) #define SCBCTRL_SERVICESCR_NOTIFY (3u) #define SCBCTRL_SERVICESCR_NOTIFY_MASK (1u << SCBCTRL_SERVICESCR_NOTIFY) #define SCBCTRL_SERVICESCR_COMMAND (16u) #define SCBCTRL_SERVICESCR_COMMAND_MASK (0xFFFFu << SCBCTRL_SERVICESCR_COMMAND) /***************SCBCTRL SERVICES_SR registers*************************/ #define SCBCTRL_SERVICESSR_REQ (0u) #define SCBCTRL_SERVICESSR_REQ_MASK (1u << SCBCTRL_SERVICESSR_REQ) #define SCBCTRL_SERVICESSR_BUSY (1u) #define SCBCTRL_SERVICESSR_BUSY_MASK (1u << SCBCTRL_SERVICESSR_BUSY) #define SCBCTRL_SERVICESSR_ABORT (2u) #define SCBCTRL_SERVICESSR_ABORT_MASK (1u << SCBCTRL_SERVICESSR_ABORT) #define SCBCTRL_SERVICESSR_NOTIFY (3u) #define SCBCTRL_SERVICESSR_NOTIFY_MASK (1u << SCBCTRL_SERVICESSR_NOTIFY) #define SCBCTRL_SERVICESSR_STATUS (16u) #define SCBCTRL_SERVICESSR_STATUS_MASK (0xFFFFu << SCBCTRL_SERVICESSR_STATUS) #ifdef __cplusplus } #endif #endif /* MSS_SYS_SERVICES_REGS_H_ */ mss_timer/000077500000000000000000000000001432224323300352555ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_timer.h000066400000000000000000000725441432224323300374440ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_timer/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire microprocessor subsystem (MSS) Timer bare metal software driver * public API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire MSS Timer Bare Metal Driver. @section intro_sec Introduction The PolarFire microprocessor Subsystem (MSS) includes a timer hardware block which can be used as two independent 32-bits timers or as a single 64-bits timer in periodic or one-shot mode. This driver provides a set of functions for controlling the MSS timer as part of a bare metal system where no operating system is available. These drivers can be adapted for use as part of an operating system but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. @section theory_op Theory of Operation The PolarFire MSS Timer can be used in one of two mutually exclusive modes; either as a single 64-bits timer or as two independent 32-bits timers. The MSS Timer can be used in either periodic mode or one-shot mode. A timer configured for periodic mode operations will generate an interrupt and reload its down-counter when it reaches 0. The timer will then continue decrementing from its reload value without waiting for the interrupt to be cleared. A timer configured for one-shot mode will only generate an interrupt once when its down-counter reaches 0. It must be explicitly reloaded to start decrementing again. The MSS Timer driver functions are grouped into the following categories: - Initialization and Configuration - Timer control - Interrupt control The MSS Timer driver provides three initialization functions: - MSS_TIM1_init() - MSS_TIM2_init() - MSS_TIM64_init() The MSS Timer driver is initialized through calls to these functions and at least one of them must be called before any other MSS Timer driver functions can be called. You should only use the MSS_TIM1_init() and MSS_TIM2_init() functions if you intend to use the timer in 32-bits mode. Use the MSS_TIM64_init() function is you intend to use the MSS Timer as a single 64-bits timer. The initialization functions take a single parameter specifying the operating mode of the timer being initialized. Once initialized a timer can be controlled using the following functions: - MSS_TIM1_load_immediate() - MSS_TIM1_load_background() - MSS_TIM1_get_current_value() - MSS_TIM1_start() - MSS_TIM1_stop() - MSS_TIM2_load_immediate() - MSS_TIM2_load_background() - MSS_TIM2_get_current_value() - MSS_TIM2_start() - MSS_TIM2_stop() - MSS_TIM64_load_immediate() - MSS_TIM64_load_background() - MSS_TIM64_get_current_value() - MSS_TIM64_start() - MSS_TIM64_stop() Timer interrupts are controlled using the following functions: - MSS_TIM1_enable_irq() - MSS_TIM1_disable_irq() - MSS_TIM1_clear_irq() - MSS_TIM2_enable_irq() - MSS_TIM2_disable_irq() - MSS_TIM2_clear_irq() - MSS_TIM64_enable_irq() - MSS_TIM64_disable_irq() - MSS_TIM64_clear_irq() The function prototypes for the timer interrupt handlers are: - void Timer1_IRQHandler( void ) - void Timer2_IRQHandler( void ) Entries for these interrupt handlers are provided in the PolarFire RISC-V HAL vector table. To add a Timer 1 interrupt handler, you must implement a Timer1_IRQHandler( ) function as part of your application code. To add a Timer 2 interrupt handler, you must implement a Timer2_IRQHandler( ) function as part of your application code. When using the MSS Timer as a 64-bit timer, you must implement a Timer1_IRQHandler( ) function as part of your application code. The Timer 2 interrupt is not used when the MSS Timer is configured as a 64-bit timer. *//*=========================================================================*/ #ifndef __PSE_TIMER_H_ #define __PSE_TIMER_H_ #include "mss_plic.h" #include "drivers/mss/mss_timer/mss_timer_regs.h" #ifdef __cplusplus extern "C" { #endif /******************************************************************************/ /* Peripheral declaration */ /******************************************************************************/ #define TIMER_LO ((TIMER_TypeDef *) TIMER_LO_BASE) #define TIMER_HI ((TIMER_TypeDef*) TIMER_HI_BASE) /*-------------------------------------------------------------------------*//** * Timer mode selection. This enumeration is used to select between the two * possible timer modes of operation: periodic and one-shot mode. It is used as * an argument to the MSS_TIM1_init(), MSS_TIM2_init() and MSS_TIM64_init() * functions. * MSS_TIMER_PERIODIC_MODE: * In periodic mode the timer generates interrupts at constant intervals. On * reaching zero, the timer's counter is reloaded with a value held in a * register and begins counting down again. * MSS_TIMER_ONE_SHOT_MODE: * The timer generates a single interrupt in this mode. On reaching zero, the * timer's counter halts until reprogrammed by the user. */ typedef enum __mss_timer_mode { MSS_TIMER_PERIODIC_MODE = 0,//!< MSS_TIMER_PERIODIC_MODE MSS_TIMER_ONE_SHOT_MODE = 1 //!< MSS_TIMER_ONE_SHOT_MODE } mss_timer_mode_t; /*-------------------------------------------------------------------------*//** * Timer operation mask defines. */ /* Timer 1 interrupt enable bits */ #define TIM1_INTEN_MASK 0x00000004u /* Timer 1 Mode bits */ #define TIM1_MODE_SHIFT 1u #define TIM1_MODE_MASK 0x00000002u /* Timer 1 enable bits */ #define TIM1_ENABLE_MASK 0x00000001u /* Timer 2 interrupt enable bits */ #define TIM2_INTEN_MASK 0x00000004u /* Timer 2 Mode bits */ #define TIM2_MODE_SHIFT 1u #define TIM2_MODE_MASK 0x00000002u /* Timer 2 enable bits */ #define TIM2_ENABLE_MASK 0x00000001u /* Timer 64 interrupt enable bits */ #define TIM64_INTEN_MASK 0x00000004u /* Timer 64 mode bits */ #define TIM64_MODE_SHIFT 1u #define TIM64_MODE_MASK 0x00000002u /* Timer 64 enable bits */ #define TIM64_ENABLE_MASK 0x00000001u static uint32_t readvalue[52] = {0}; /*--------------------------------------------------------------------------*//** The MSS_TIM1_init() function initializes the MSS Timer block for use as a 32-bit timer and selects the operating mode for Timer 1. The MSS Timer block is out of reset before executing this function. The MSS_TIM1_init() function stops Timer 1, disables its interrupt, and sets the Timer 1 operating mode. @param timer The timer parameter specifies the Timer block to configure. @param mode The mode parameter specifies whether the timer will operate in periodic or one-shot mode. Allowed values for this parameter are: - MSS_TIMER_PERIODIC_MODE - MSS_TIMER_ONE_SHOT_MODE Note:The MSS Timer block cannot be used both as a 64-bit and 32-bit timer. Calling MSS_TIM1_init() will overwrite any previous configuration of the MSS Timer as a 64-bit timer. */ static inline void MSS_TIM1_init(TIMER_TypeDef* timer, mss_timer_mode_t mode) { PLIC_DisableIRQ(TIMER1_PLIC); /* Disable timer 1 irq */ timer->TIM64_MODE = 0u; /* switch to 32 bits mode */ readvalue[1] = timer->TIM64_MODE; /* Disable timer and interrupt and set mode (continuous/one-shot) */ timer->TIM1_CTRL = TIM1_MODE_MASK & ((uint32_t)mode << TIM1_MODE_SHIFT); readvalue[2] = timer->TIM1_CTRL; timer->TIM1_RIS = 1u; /* clear timer 1 interrupt */ readvalue[3] = timer->TIM1_RIS; } /*-------------------------------------------------------------------------*//** The MSS_TIM1_start() function enables Timer 1 and starts its down-counter decrementing from the load_value specified in previous calls to the MSS_TIM1_load_immediate() or MSS_TIM1_load_background() functions. @param timer The timer parameter specifies the Timer block to configure. Note: The MSS_TIM1_start() function is also used to resume the down-counter if previously stopped using the MSS_TIM1_stop() function. */ static inline void MSS_TIM1_start(TIMER_TypeDef* timer) { timer->TIM1_CTRL |= TIM1_ENABLE_MASK; } /*-------------------------------------------------------------------------*//** The MSS_TIM1_stop() function disables Timer 1 and stops its down-counter decrementing. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM1_stop(TIMER_TypeDef* timer) { timer->TIM1_CTRL &= ~((uint32_t)TIM1_ENABLE_MASK); /* disable timer */ } /*-------------------------------------------------------------------------*//** The MSS_TIM1_get_current_value() returns the current value of the Timer 1 down-counter. @param timer The timer parameter specifies the Timer block to configure. @return This function returns the 32-bits current value of the Timer 1 down-counter. */ static inline uint32_t MSS_TIM1_get_current_value(TIMER_TypeDef* timer) { return timer->TIM1_VAL; } /*-------------------------------------------------------------------------*//** The MSS_TIM1_load_immediate() function loads the value passed by the load_value parameter into the Timer 1 down-counter. The counter will decrement immediately from this value once Timer 1 is enabled. The MSS Timer will generate an interrupt when the counter reaches zero, if Timer 1 interrupts are enabled. This function is intended to be used when Timer 1 is configured for one-shot mode to time a single delay. Note: The value passed by the load_value parameter is loaded immediately into the down-counter regardless of whether Timer 1 is operating in periodic or one-shot mode. @param timer The timer parameter specifies the Timer block to configure. @param load_value The load_value parameter specifies the value from which the Timer 1 down-counter will start decrementing from. */ static inline void MSS_TIM1_load_immediate(TIMER_TypeDef* timer, uint32_t load_value) { timer->TIM1_LOADVAL = load_value; } /*-------------------------------------------------------------------------*//** The MSS_TIM1_load_background() function is used to specify the value that will be reloaded into the Timer 1 down-counter the next time the counter reaches zero. This function is typically used when Timer 1 is configured for periodic mode operation to select or change the delay period between the interrupts generated by Timer 1. @param timer The timer parameter specifies the Timer block to configure. @param load_value The load_value parameter specifies the value that will be loaded into the Timer 1 down-counter the next time the down-counter reaches zero. The Timer 1 down-counter will start decrementing from this value after the current count expires. */ static inline void MSS_TIM1_load_background(TIMER_TypeDef* timer, uint32_t load_value) { timer->TIM1_BGLOADVAL = load_value; } /*-------------------------------------------------------------------------*//** The MSS_TIM1_enable_irq() function is used to enable interrupt generation for Timer 1. This function also enables the interrupt in the RISC-V PLIC. The Timer1_IRQHandler() function will be called when a Timer 1 interrupt occurs. Note:A Timer1_IRQHandler() default implementation is defined, with weak linkage, in the MPFS HAL. You must provide your own implementation of the Timer1_IRQHandler() function, which will override the default implementation, to suit your application. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM1_enable_irq(TIMER_TypeDef* timer) { timer->TIM1_CTRL |= TIM1_INTEN_MASK; readvalue[8] = timer->TIM1_CTRL; PLIC_EnableIRQ(TIMER1_PLIC); } /*-------------------------------------------------------------------------*//** The MSS_TIM1_disable_irq() function is used to disable interrupt generation for Timer 1. This function also disables the interrupt in the RISC-V PLIC. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM1_disable_irq(TIMER_TypeDef* timer) { timer->TIM1_CTRL &= ~((uint32_t)TIM1_INTEN_MASK); PLIC_DisableIRQ(TIMER1_PLIC); /* Disable timer 1 irq */ } /*-------------------------------------------------------------------------*//** The MSS_TIM1_clear_irq() function is used to clear a pending interrupt from Timer 1. This function also clears the interrupt in the RISC-V PLIC. Note:You must call the MSS_TIM1_clear_irq() function as part of your implementation of the Timer1_IRQHandler() Timer 1 interrupt service routine (ISR) in order to prevent the same interrupt event retriggering a call to the ISR. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM1_clear_irq(TIMER_TypeDef* timer) { timer->TIM1_RIS = 1u; } /*-------------------------------------------------------------------------*//** The MSS_TIM2_init() function initializes the MSS Timer block for use as a 32-bit timer and selects the operating mode for Timer 2. The MSS Timer block is already out of reset before executing MSS_TIM2_init() function. This function stops Timer 2, disables its interrupt and sets the Timer 2 operating mode. Note:The MSS Timer block cannot be used both as a 64-bit and 32-bit timer. Calling MSS_TIM2_init() will overwrite any previous configuration of the MSS Timer as a 64-bit timer. @param timer The timer parameter specifies the Timer block to configure. @param mode The mode parameter specifies whether the timer will operate in periodic or one-shot mode. Allowed values for this parameter are: - MSS_TIMER_PERIODIC_MODE - MSS_TIMER_ONE_SHOT_MODE */ static inline void MSS_TIM2_init(TIMER_TypeDef* timer, mss_timer_mode_t mode) { PLIC_DisableIRQ(TIMER2_PLIC); /* Disable timer 2 irq */ timer->TIM64_MODE = 0u; /* switch to 32 bits mode */ /* Disable timer and interrupt. Set mode (continuous/one-shot) */ timer->TIM2_CTRL = TIM2_MODE_MASK & ((uint32_t)mode << TIM2_MODE_SHIFT); timer->TIM2_RIS = 1u; /* clear timer 2 interrupt */ } /*-------------------------------------------------------------------------*//** The MSS_TIM2_start() function enables Timer 2 and starts its down-counter decrementing from the load_value specified in previous calls to the MSS_TIM2_load_immediate() or MSS_TIM2_load_background() functions. @param timer The timer parameter specifies the Timer block to configure. Note:The MSS_TIM2_start() function is also used to resume the down-counter if previously stopped using the MSS_TIM2_stop() function. */ static inline void MSS_TIM2_start(TIMER_TypeDef* timer) { timer->TIM2_CTRL |= TIM2_ENABLE_MASK; /* enable timer */ } /*-------------------------------------------------------------------------*//** The MSS_TIM2_stop() function disables Timer 2 and stops its down-counter decrementing. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM2_stop(TIMER_TypeDef* timer) { timer->TIM2_CTRL &= ~((uint32_t)TIM2_ENABLE_MASK); /* disable timer */ } /*-------------------------------------------------------------------------*//** The MSS_TIM2_get_current_value() returns the current value of the Timer 2 down-counter. @param timer The timer parameter specifies the Timer block to configure. */ static inline uint32_t MSS_TIM2_get_current_value(TIMER_TypeDef* timer) { return timer->TIM2_VAL; } /*-------------------------------------------------------------------------*//** The MSS_TIM2_load_immediate() function loads the value passed by the load_value parameter into the Timer 2 down-counter. The counter will decrement immediately from this value once Timer 2 is enabled. The MSS Timer will generate an interrupt when the counter reaches zero if Timer 2 interrupts are enabled. This function is intended to be used when Timer 2 is configured for one-shot mode to time a single delay. Note:The value passed by the load_value parameter is loaded immediately into the down-counter regardless of whether Timer 2 is operating in periodic or one-shot mode. @param timer The timer parameter specifies the Timer block to configure. @param load_value The load_value parameter specifies the value from which the Timer 2 down-counter will start decrementing. */ static inline void MSS_TIM2_load_immediate(TIMER_TypeDef* timer, uint32_t load_value) { timer->TIM2_LOADVAL = load_value; } /*-------------------------------------------------------------------------*//** The MSS_TIM2_load_background() function is used to specify the value that will be reloaded into the Timer 2 down-counter the next time the counter reaches zero. This function is typically used when Timer 2 is configured for periodic mode operation to select or change the delay period between the interrupts generated by Timer 2. @param timer The timer parameter specifies the Timer block to configure. @param load_value The load_value parameter specifies the value that will be loaded into the Timer 2 down-counter the next time the down-counter reaches zero. The Timer 2 down-counter will start decrementing from this value after the current count expires. */ static inline void MSS_TIM2_load_background(TIMER_TypeDef* timer, uint32_t load_value) { timer->TIM2_BGLOADVAL = load_value; } /*-------------------------------------------------------------------------*//** The MSS_TIM2_enable_irq() function is used to enable interrupt generation for Timer 2. This function also enables the interrupt in the RISC-V PLIC. The Timer2_IRQHandler() function will be called when a Timer 2 interrupt occurs. Note:A Timer2_IRQHandler() default implementation is defined, with weak linkage, in the MPFS HAL. You must provide your own implementation of the Timer2_IRQHandler() function, which will override the default implementation, to suit your application. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM2_enable_irq(TIMER_TypeDef* timer) { timer->TIM2_CTRL |= TIM2_INTEN_MASK; PLIC_EnableIRQ(TIMER2_PLIC); } /*-------------------------------------------------------------------------*//** The MSS_TIM2_disable_irq() function is used to disable interrupt generation for Timer 2. This function also disables the interrupt in the RISC-V PLIC. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM2_disable_irq(TIMER_TypeDef* timer) { timer->TIM2_CTRL &= ~((uint32_t)TIM2_INTEN_MASK); PLIC_DisableIRQ(TIMER2_PLIC); /* Disable timer 2 irq */ } /*-------------------------------------------------------------------------*//** The MSS_TIM2_clear_irq() function is used to clear a pending interrupt from Timer 2. This function also clears the interrupt in the RISC-V PLIC. Note:You must call the MSS_TIM2_clear_irq() function as part of your implementation of the Timer2_IRQHandler() Timer 2 interrupt service routine (ISR) in order to prevent the same interrupt event retriggering a call to the ISR. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM2_clear_irq(TIMER_TypeDef* timer) { timer->TIM2_RIS = 1u; } /*-------------------------------------------------------------------------*//** The MSS_TIM64_init() function initializes the MSS Timer block for use as a single 64-bit timer and selects the operating mode of the timer. The MSS Timer block is already out of reset before executing MSS_TIM64_init() function. This function stops the timer, disables its interrupts, and sets the timer's operating mode. Note:The MSS Timer block cannot be used both as a 64-bit and 32-bit timer. Calling MSS_TIM64_init() will overwrite any previous configuration of the MSS Timer as a 32-bit timer. @param timer The timer parameter specifies the Timer block to configure. @param mode The mode parameter specifies whether the timer will operate in periodic or one-shot mode. Allowed values for this parameter are: - MSS_TIMER_PERIODIC_MODE - MSS_TIMER_ONE_SHOT_MODE */ static inline void MSS_TIM64_init(TIMER_TypeDef* timer, mss_timer_mode_t mode) { PLIC_DisableIRQ(TIMER1_PLIC); /* Disable timer 1 irq */ PLIC_DisableIRQ(TIMER2_PLIC); /* Disable timer 2 irq */ timer->TIM64_MODE = 1u; /* switch to 64 bits mode */ /* Disable timer and interrupt and set mode (continuous/one-shot) */ timer->TIM64_CTRL = TIM64_MODE_MASK & ((uint32_t)mode << TIM64_MODE_SHIFT); timer->TIM1_RIS = 1u; /* clear timer 1 interrupt */ timer->TIM2_RIS = 1u; /* clear timer 2 interrupt */ } /*-------------------------------------------------------------------------*//** The MSS_TIM64_start() function enables the 64-bit timer and starts its down-counter decrementing from the load_value specified in previous calls to the MSS_TIM64_load_immediate() or MSS_TIM64_load_background() functions. Note: The MSS_TIM64_start() function is also used to resume the down-counter if previously stopped using the MSS_TIM64_stop() function. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM64_start(TIMER_TypeDef* timer) { timer->TIM64_CTRL |= TIM64_ENABLE_MASK; /* enable timer */ } /*-------------------------------------------------------------------------*//** The MSS_TIM64_stop() function disables the 64-bit timer and stops its down-counter decrementing. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM64_stop(TIMER_TypeDef* timer) { timer->TIM64_CTRL &= ~((uint32_t)TIM64_ENABLE_MASK); /* disable timer */ } /*-------------------------------------------------------------------------*//** The MSS_TIM64_get_current_value() is used to read the current value of the 64-bit timer down-counter. @param timer The timer parameter specifies the Timer block to configure. @param load_value_u The load_value_u parameter is a pointer to a 32-bit variable where the upper 32 bits of the current value of the 64-bit timer down-counter will be copied. @param load_value_l The load_value_l parameter is a pointer to a 32-bit variable where the lower 32 bits of the current value of the 64-bit timer down-counter will be copied. Example: @code uint32_t current_value_u = 0; uint32_t current_value_l = 0; MSS_TIM64_get_current_value( ¤t_value_u, ¤t_value_l ); @endcode */ static inline void MSS_TIM64_get_current_value ( TIMER_TypeDef* timer, uint32_t * load_value_u, uint32_t * load_value_l ) { *load_value_l = timer->TIM64_VAL_L; *load_value_u = timer->TIM64_VAL_U; } /*-------------------------------------------------------------------------*//** The MSS_TIM64_load_immediate() function loads the values passed by the load_value_u and load_value_l parameters into the 64-bit timer down-counter. The counter will decrement immediately from the concatenated 64-bit value once the 64-bit timer is enabled. The MSS Timer will generate an interrupt when the counter reaches zero if 64-bit timer interrupts are enabled. This function is intended to be used when the 64-bit timer is configured for one-shot mode to time a single delay. Note: The value passed by the load_value parameter is loaded immediately into the down-counter regardless of whether the 64-bit timer is operating in periodic or one-shot mode. @param timer The timer parameter specifies the Timer block to configure. @param load_value_u The load_value_u parameter specifies the upper 32 bits of the 64-bit timer load value from which the 64-bit timer down-counter will start decrementing. @param load_value_l The load_value_l parameter specifies the lower 32 bits of the 64-bit timer load value from which the 64-bit timer down-counter will start decrementing. */ static inline void MSS_TIM64_load_immediate ( TIMER_TypeDef* timer, uint32_t load_value_u, uint32_t load_value_l ) { timer->TIM64_LOADVAL_U = load_value_u; timer->TIM64_LOADVAL_L = load_value_l; } /*-------------------------------------------------------------------------*//** The MSS_TIM64_load_background() function is used to specify the 64-bit value that will be reloaded into the 64-bit timer down-counter the next time the counter reaches zero. This function is typically used when the 64-bit timer is configured for periodic mode operation to select or change the delay period between the interrupts generated by the 64-bit timer. @param timer The timer parameter specifies the Timer block to configure. @param load_value_u The load_value_u parameter specifies the upper 32 bits of the 64-bit timer load value. The concatenated 64-bit value formed from load_value_u and load_value_l will be loaded into the 64-bit timer down-counter the next time the down-counter reaches zero. The 64-bit timer down-counter will start decrementing from the concatenated 64-bit value after the current count expires. @param load_value_l The load_value_l parameter specifies the lower 32 bits of the 64-bit timer load value. The concatenated 64-bit value formed from load_value_u and load_value_l will be loaded into the 64-bit timer down-counter the next time the down-counter reaches zero. The 64-bit timer down-counter will start decrementing from the concatenated 64-bit value after the current count expires. */ static inline void MSS_TIM64_load_background ( TIMER_TypeDef* timer, uint32_t load_value_u, uint32_t load_value_l ) { timer->TIM64_BGLOADVAL_U = load_value_u; timer->TIM64_BGLOADVAL_L = load_value_l; } /*-------------------------------------------------------------------------*//** The MSS_TIM64_enable_irq() function is used to enable interrupt generation for the 64-bit timer. This function also enables the interrupt in the RISC-V PLIC. The Timer1_IRQHandler() function will be called when a 64-bit timer interrupt occurs. Note:A Timer1_IRQHandler() default implementation is defined, with weak linkage, in the MPFS HAL. You must provide your own implementation of the Timer1_IRQHandler() function, which will override the default implementation, to suit your application. Note:The MSS_TIM64_enable_irq() function enables and uses Timer 1 interrupts for the 64-bit timer. Timer 2 interrupts remain disabled. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM64_enable_irq(TIMER_TypeDef* timer) { timer->TIM64_CTRL |= TIM64_INTEN_MASK; PLIC_EnableIRQ(TIMER1_PLIC); } /*-------------------------------------------------------------------------*//** The MSS_TIM64_disable_irq() function is used to disable interrupt generation for the 64-bit timer. This function also disables the interrupt in the RISC-V PLIC. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM64_disable_irq(TIMER_TypeDef* timer) { timer->TIM64_CTRL &= ~((uint32_t)TIM64_INTEN_MASK); PLIC_DisableIRQ(TIMER1_PLIC); } /*-------------------------------------------------------------------------*//** The MSS_TIM64_clear_irq() function is used to clear a pending interrupt from the 64-bit timer. This function also clears the interrupt in the RISC-V PLIC. Note:You must call the MSS_TIM64_clear_irq() function as part of your implementation of the Timer1_IRQHandler() 64-bit timer interrupt service routine (ISR) in order to prevent the same interrupt event retriggering a call to the ISR. @param timer The timer parameter specifies the Timer block to configure. */ static inline void MSS_TIM64_clear_irq(TIMER_TypeDef* timer) { timer->TIM64_RIS = 1u; } #ifdef __cplusplus } #endif #endif /*__PSE_TIMER_H_*/ mss_timer_regs.h000066400000000000000000000037071432224323300404570ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_timer /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for PolarFire SoC MSS Timer * * SVN $Revision$ * SVN $Date$ */ #ifndef __PSE_TIMER_REG_H_ #define __PSE_TIMER_REG_H_ #ifdef __cplusplus extern "C" { #endif /*----------------------------------------------------------------------------*/ /*--------------------------PSE MSS Timer register map------------------------*/ /*----------------------------------------------------------------------------*/ typedef struct { /*Timer 1 register declaration*/ const volatile uint32_t TIM1_VAL; volatile uint32_t TIM1_LOADVAL; volatile uint32_t TIM1_BGLOADVAL; volatile uint32_t TIM1_CTRL; volatile uint32_t TIM1_RIS; const volatile uint32_t TIM1_MIS; /*Timer 2 register declaration*/ const volatile uint32_t TIM2_VAL; volatile uint32_t TIM2_LOADVAL; volatile uint32_t TIM2_BGLOADVAL; volatile uint32_t TIM2_CTRL; volatile uint32_t TIM2_RIS; const volatile uint32_t TIM2_MIS; /*Timer 64 register declaration*/ const volatile uint32_t TIM64_VAL_U; const volatile uint32_t TIM64_VAL_L; volatile uint32_t TIM64_LOADVAL_U; volatile uint32_t TIM64_LOADVAL_L; volatile uint32_t TIM64_BGLOADVAL_U; volatile uint32_t TIM64_BGLOADVAL_L; volatile uint32_t TIM64_CTRL; volatile uint32_t TIM64_RIS; const volatile uint32_t TIM64_MIS; volatile uint32_t TIM64_MODE; } TIMER_TypeDef; /******************************************************************************/ /* Peripheral memory map */ /******************************************************************************/ #define TIMER_LO_BASE 0x20125000 #define TIMER_HI_BASE 0x28125000 #ifdef __cplusplus } #endif #endif /* __PSE_TIMER_REG_H_ */ mss_usb/000077500000000000000000000000001432224323300347265ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mssmss_usb_common_cif.c000066400000000000000000000654461432224323300407550ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF driver * * USB-CIF driver implementation: * This source file implements MSS USB Interrupt handler functions. This file * also implements core interface function for the logical layer to control * the MSS USB core. These interface functions are independent of the USB mode. * * * SVN $Revision$ * SVN $Date$ */ #include "mss_usb_common_cif.h" #include "mss_assert.h" #include "mss_usb_common_reg_io.h" #include "mss_usb_core_regs.h" #include "mss_plic.h" #ifdef MSS_USB_HOST_ENABLED #include "mss_usb_host_cif.h" #include "mss_usb_host_reg_io.h" #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED static uint8_t MSS_USB_CIF_host_rx_errchk(mss_usb_ep_num_t ep_num); static uint8_t MSS_USB_CIF_host_tx_errchk(mss_usb_ep_num_t ep_num); #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_DEVICE_ENABLED static uint8_t MSS_USB_CIF_device_rx_errchk(mss_usb_ep_num_t ep_num); static uint8_t MSS_USB_CIF_device_tx_errchk(mss_usb_ep_num_t ep_num); #endif /* MSS_USB_HOST_ENABLED */ /***************************************************************************//** * Global variables shared by mss_usb_device_cif.c and mss_usb_common_cif.c */ #ifdef MSS_USB_DEVICE_ENABLED extern mss_usbd_cb_t g_mss_usbd_cb; extern volatile mss_usbd_cep_state_t cep_state; #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_HOST_ENABLED extern mss_usbh_cb_t g_mss_usbh_cb; #endif /* MSS_USB_HOST_ENABLED */ /***************************************************************************//** * Private functions declarations of USB-CIF. ******************************************************************************/ static void MSS_USB_CIF_handle_cep_irq ( void ); static void MSS_USB_CIF_handle_tx_ep_irq ( uint16_t irq_num ); static void MSS_USB_CIF_handle_rx_ep_irq ( uint16_t irq_num ); /***************************************************************************//** * Main USB interrupt handler. It checks for TX/RX endpoint interrupts and USB * system level interrupts and calls the appropriate routine. */ uint8_t PLIC_usb_mc_IRQHandler ( void ) { volatile uint8_t usb_irq; volatile uint16_t tx_ep_irq; volatile uint16_t rx_ep_irq; volatile uint8_t role; usb_irq = MSS_USB_CIF_read_irq_reg(); tx_ep_irq = MSS_USB_CIF_read_tx_ep_irq_reg(); rx_ep_irq = MSS_USB_CIF_read_rx_ep_irq_reg(); /* When operating in Host mode, on detecting Disconnect event, Disconnect Interrupt occurs but the HostMode bit in DevCtl is also cleared. Hence moving Disconnect handling out of get_mode condition. In the event of Disconnection, The decision is made based on the B-Device bit(DevCtl-D7). */ if (usb_irq & DISCONNECT_IRQ_MASK) { role = MSS_USB_CIF_get_role(); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_DEVICE_ROLE_DEVICE_B == role) { MSS_USB_CIF_enable_usbirq(RESET_IRQ_MASK); g_mss_usbd_cb.usbd_disconnect(); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_DEVICE_ROLE_DEVICE_A == role) { /*In Host mode, On removing the attached B-device the session bit somehow remains set. This bit need to be cleared otherwise RESET interrupt is not occurring when B-Device is connected after removing A-Device*/ if (MSS_USB_CIF_is_session_on()) { MSS_USB_CIF_stop_session(); } MSS_USBH_CIF_read_vbus_level(); g_mss_usbh_cb.usbh_disconnect(); } #endif /* MSS_USB_HOST_ENABLED */ } #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { if (usb_irq & RESUME_IRQ_MASK) { g_mss_usbd_cb.usbd_resume(); } if (usb_irq & SUSPEND_IRQ_MASK) { g_mss_usbd_cb.usbd_suspend(); } if (usb_irq & RESET_IRQ_MASK) { MSS_USB_CIF_set_index_reg(MSS_USB_CEP); MSS_USB_CIF_enable_usbirq(DISCONNECT_IRQ_MASK | SUSPEND_IRQ_MASK); cep_state = MSS_USB_CTRL_EP_IDLE; MSS_USB_CIF_clr_usb_irq_reg(); MSS_USB_CIF_cep_clr_setupend(); MSS_USB_CIF_cep_clr_stall_sent(); g_mss_usbd_cb.usbd_reset(); } } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { role = MSS_USB_CIF_get_role(); if (usb_irq & RESUME_IRQ_MASK) { /* Resume interrupt in Host mode means Remote Wakeup request */ } /* Vbus_err and session request interrupts are valid only in A device */ if (MSS_USB_DEVICE_ROLE_DEVICE_A == role) { if (usb_irq & SESSION_REQUEST_IRQ_MASK) { /* This means SRP initiated by Target device. */ } if (usb_irq & VBUS_ERROR_IRQ_MASK) { /* Power management */ MSS_USBH_CIF_read_vbus_level(); } } if (usb_irq & CONNECT_IRQ_MASK) { MSS_USBH_CIF_handle_connect_irq(); } if (usb_irq & BABBLE_IRQ_MASK) { /* Not supported yet */ } #if 0 /* SOF interrupt is not processed */ if (usb_irq & SOF_IRQ_MASK) { g_mss_usbd_cb.usb_device_sof(0); } #endif /* SOF interrupt is not processed */ } #endif /* MSS_USB_HOST_ENABLED */ if (tx_ep_irq & 0x0001u) { /* handle EP0 IRQ */ MSS_USB_CIF_handle_cep_irq(); } if (tx_ep_irq & 0xFFFEu) /* EP0 is handled above */ { /* Handle TX EP here, pass on the EP numbers.Mask EP0 bit */ tx_ep_irq &= 0xFFFEu; MSS_USB_CIF_handle_tx_ep_irq(tx_ep_irq); } if (rx_ep_irq & 0xFFFEu) /* bit0 is not defined */ { /* Handle RX EP here, pass on the EP numbers */ MSS_USB_CIF_handle_rx_ep_irq(rx_ep_irq); } return EXT_IRQ_KEEP_ENABLED; } /***************************************************************************//** * Routine to handle the interrupt on Control Endpoint.(EP0) */ static void MSS_USB_CIF_handle_cep_irq ( void ) { uint8_t status = 0u; MSS_USB_CIF_set_index_reg(MSS_USB_CEP); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { if (MSS_USB_CIF_cep_is_stall_sent()) { status |= CTRL_EP_STALL_ERROR; MSS_USB_CIF_cep_clr_stall_sent(); g_mss_usbd_cb.usbd_cep_setup(status); } else { if (MSS_USB_CIF_cep_is_setupend()) { MSS_USB_CIF_cep_clr_setupend(); if (!MSS_USB_CIF_cep_is_rxpktrdy()) { status |= CTRL_EP_SETUP_END_ERROR; } else { status &= ~CTRL_EP_SETUP_END_ERROR; } g_mss_usbd_cb.usbd_cep_setup(status); } else { if (cep_state == MSS_USB_CTRL_EP_IDLE) { if (MSS_USB_CIF_cep_is_rxpktrdy()) { g_mss_usbd_cb.usbd_cep_setup(status); } } else if (cep_state == MSS_USB_CTRL_EP_TX) { g_mss_usbd_cb.usbd_cep_tx_complete(status); } else if (cep_state == MSS_USB_CTRL_EP_RX) { if (MSS_USB_CIF_cep_is_rxpktrdy()) { g_mss_usbd_cb.usbd_cep_rx(status); } } else { ASSERT(0); } } } } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { if (MSS_USBH_CIF_cep_is_rxstall_err()) { status |= MSS_USB_EP_STALL_RCVD; MSS_USBH_CIF_cep_clr_rxstall_err(); } if (MSS_USBH_CIF_cep_is_retry_err()) { status |= MSS_USB_EP_NO_RESPONSE; MSS_USBH_CIF_cep_clr_retry_err(); } if (MSS_USBH_CIF_cep_is_naktimeout_err()) { status |= MSS_USB_EP_NAK_TOUT; MSS_USBH_CIF_cep_clr_naktimeout_err(); } if (status == 0u) /* No error was found */ { status = MSS_USB_EP_TXN_SUCCESS; } g_mss_usbh_cb.usbh_cep(status); } #endif /* MSS_USB_HOST_ENABLED */ } /***************************************************************************//** * Routine to handle the interrupt on TX_EP */ static void MSS_USB_CIF_handle_tx_ep_irq ( uint16_t irq_num ) { mss_usb_ep_num_t ep_num = MSS_USB_TX_EP_1; uint8_t status = 0u; while (irq_num) { irq_num >>= 1u; /*EP1 starts from D1*/ if (irq_num & MSS_USB_WORD_BIT_0_MASK) { MSS_USB_CIF_tx_ep_disable_irq(ep_num); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_device_tx_errchk(ep_num); g_mss_usbd_cb.usbd_ep_tx_complete(ep_num,status); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_host_tx_errchk(ep_num); g_mss_usbh_cb.usbh_tx_complete((uint8_t)ep_num, status); } #endif /* MSS_USB_HOST_ENABLED */ MSS_USB_CIF_tx_ep_enable_irq(ep_num); } status = 0u; /*resetting for next EP status*/ ++ep_num; } } /***************************************************************************//** * Routine to handle the interrupt on RX EP */ static void MSS_USB_CIF_handle_rx_ep_irq ( uint16_t irq_num ) { mss_usb_ep_num_t ep_num = MSS_USB_RX_EP_1; uint8_t status = 0u; while (irq_num) { irq_num >>= 1u; /*EP1 starts from D1*/ if (irq_num & MSS_USB_WORD_BIT_0_MASK) { MSS_USB_CIF_rx_ep_disable_irq(ep_num); #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_device_rx_errchk(ep_num); g_mss_usbd_cb.usbd_ep_rx(ep_num, status); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { status = MSS_USB_CIF_host_rx_errchk(ep_num); g_mss_usbh_cb.usbh_rx((uint8_t)ep_num, status); } #endif /* MSS_USB_HOST_ENABLED */ MSS_USB_CIF_rx_ep_enable_irq(ep_num); } status = 0u; /*resetting for next EP status*/ ++ep_num; } } /***************************************************************************//** * Handler for DMA interrupt. Checks for the DMA channel on which interrupt has * Occurred and corresponding EP number then calls-back to upper layer to indicate * the event. */ uint8_t PLIC_usb_dma_IRQHandler(void) { mss_usb_dma_channel_t dma_channel= MSS_USB_DMA_CHANNEL1; uint8_t status = 0; mss_usb_dma_dir_t dma_dir; mss_usb_ep_num_t ep_num; uint8_t dma_irq; uint32_t increamented_addr=0; dma_irq = MSS_USB_CIF_dma_read_irq(); while (dma_irq) { if (dma_irq & MSS_USB_BYTE_BIT_0_MASK) { /* DMA Transfer for this channel is complete.Clear Start_transfer bit */ MSS_USB_CIF_dma_stop_xfr(dma_channel); ep_num = (mss_usb_ep_num_t)MSS_USB_CIF_dma_get_epnum(dma_channel); dma_dir = (mss_usb_dma_dir_t)MSS_USB_CIF_dma_get_dir(dma_channel); if (MSS_USB_CIF_dma_is_bus_err(dma_channel)) { status |=DMA_XFR_ERROR; MSS_USB_CIF_dma_clr_bus_err(dma_channel); } else { increamented_addr = MSS_USB_CIF_dma_read_addr(dma_channel); if (MSS_USB_DMA_READ == dma_dir) /*TX EP*/ { if (MSS_USB_CIF_tx_ep_is_dma_enabled(ep_num)) { MSS_USB_CIF_tx_ep_disable_dma(ep_num); } } #ifdef MSS_USB_HOST_ENABLED if (MSS_USB_CORE_MODE_HOST == MSS_USB_CIF_get_mode()) { /* Call the host mode logical layer driver callback function */ g_mss_usbh_cb.usbh_dma_handler(ep_num, dma_dir, status, increamented_addr); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_DEVICE_ENABLED if (MSS_USB_CORE_MODE_DEVICE == MSS_USB_CIF_get_mode()) { /* Call the device mode logical layer driver callback function */ g_mss_usbd_cb.usbd_dma_handler(ep_num, dma_dir, status, increamented_addr); } #endif /* MSS_USB_DEVICE_ENABLED */ } } dma_channel++; dma_irq >>= 1u; } return EXT_IRQ_KEEP_ENABLED; } /***************************************************************************//** * Prepares the RX EP for receiving data as per parameters provided by upper layer */ void MSS_USB_CIF_rx_ep_read_prepare ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length ) { /* * Fixed Buffer overwriting issue found with printer driver and issue with * interrupt transfer with DMA by moving the location of interrupt enable * function */ if (DMA_ENABLE == dma_enable) { /*Make sure that address is Modulo-4.Bits D0-D1 are read only.*/ ASSERT(!(((ptrdiff_t)buf_addr) & 0x00000002U)); MSS_USB_CIF_dma_write_addr(dma_channel, (ptrdiff_t)buf_addr); /* * DMA Count register will be loaded after receive interrupt occurs. * Mode need to be set every time since M1 to M0 transition might have * happened for "short packet". */ if (MSS_USB_XFR_BULK == xfr_type) { MSS_USB_CIF_rx_ep_set_dma_mode1(ep_num); MSS_USB_CIF_rx_ep_set_autoclr(ep_num); MSS_USB_CIF_rx_ep_enable_dma(ep_num); MSS_USB_CIF_dma_write_count(dma_channel, xfr_length); /* Handling single NULL packet reception */ if (0u != xfr_length ) { MSS_USB_CIF_dma_start_xfr(dma_channel); } } else { MSS_USB_CIF_rx_ep_clr_autoclr(ep_num); MSS_USB_CIF_rx_ep_set_dma_mode0(ep_num); MSS_USB_CIF_rx_ep_disable_dma(ep_num); } } } /***************************************************************************//** * Writes packet on TX EP */ void MSS_USB_CIF_ep_write_pkt ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length, uint32_t txn_length ) { if (ep_num && (buf_addr != 0)) { if (DMA_ENABLE == dma_enable) { /* Make sure that address is Modulo-4.Bits D0-D1 are read only.*/ ASSERT(!(((ptrdiff_t)buf_addr) & 0x00000002u)); MSS_USB_CIF_dma_write_addr(dma_channel,(ptrdiff_t)(buf_addr)); if (MSS_USB_XFR_BULK == xfr_type) { MSS_USB_CIF_tx_ep_enable_dma(ep_num); /* * DMA-m1 will take care of transferring 'xfr_length' data * as IN packets arrive. * DMA interrupt will occur when all TxMaxPkt size packets * are transferred. */ MSS_USB_CIF_dma_write_count(dma_channel, xfr_length); } else { /* * DMA Enable bit in TxCSR is not needed. If set,TX EP * Interrupt will not occur. */ MSS_USB_CIF_tx_ep_disable_dma(ep_num); /* Transfer only one packet with DMA-m0 */ MSS_USB_CIF_dma_write_count(dma_channel, txn_length); } /* * This will start DMA transfer. * TODO: For Null transfer DMA is not needed, but not setting * TxPktRdy bit here, is not invoking EP interrupt. * EP interrupt does get called when Null DMA transfer is done. */ MSS_USB_CIF_dma_start_xfr(dma_channel); /* * DMA interrupt will occur when all bytes are written to FIFO * TxPktRdy should be set when the DMA interrupt occurs. */ } else /* no DMA */ { MSS_USB_CIF_load_tx_fifo(ep_num, buf_addr, txn_length); MSS_USB_CIF_tx_ep_set_txpktrdy(ep_num); } } } /***************************************************************************//** * Configures DMA for data transfer operations. */ void MSS_USB_CIF_configure_ep_dma ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_dir_t dma_dir, mss_usb_dma_mode_t dma_mode, mss_usb_dma_burst_mode_t burst_mode, mss_usb_ep_num_t ep_num, uint32_t buf_addr ) { MSS_USB_CIF_dma_assign_to_epnum(dma_channel, ep_num); MSS_USB_CIF_dma_set_dir(dma_channel, dma_dir); MSS_USB_CIF_dma_set_mode(dma_channel, dma_mode); MSS_USB_CIF_dma_set_burst_mode(dma_channel, burst_mode); MSS_USB_CIF_dma_write_addr(dma_channel, buf_addr); MSS_USB_CIF_dma_enable_irq(dma_channel); } /***************************************************************************//** * Configures the TX EP for data transfer operations as per the parameters * provided by upper layer. */ void MSS_USB_CIF_tx_ep_configure ( mss_usb_ep_t* core_ep ) { uint8_t dpb = 1u; mss_usb_dma_mode_t mode; if (DPB_ENABLE == core_ep->dpb_enable) { dpb = 2u; } MSS_USB_CIF_tx_ep_set_fifo_size(core_ep->num, ((core_ep->fifo_size) / dpb), core_ep->dpb_enable); MSS_USB_CIF_tx_ep_set_fifo_addr(core_ep->num, core_ep->fifo_addr); if (DPB_ENABLE == core_ep->dpb_enable) { MSS_USB_enable_tx_ep_dpb(core_ep->num); } else if (DPB_DISABLE == core_ep->dpb_enable) { MSS_USB_disable_tx_ep_dpb(core_ep->num); } else { ASSERT(0); } MSS_USB_CIF_tx_ep_set_max_pkt(core_ep->num, core_ep->xfr_type, core_ep->max_pkt_size, core_ep->num_usb_pkt); MSS_USB_CIF_tx_ep_clr_data_tog(core_ep->num); if (DMA_ENABLE == core_ep->dma_enable) { if (MSS_USB_XFR_BULK == core_ep->xfr_type ) { MSS_USB_CIF_tx_ep_set_dma_mode1(core_ep->num); MSS_USB_CIF_tx_ep_enable_dma(core_ep->num); mode = MSS_USB_DMA_MODE1; } else { /* * DMA_ENable bit in TXCSRL is not required to be set for m0. if it * is set TX interrupt would not occur. */ MSS_USB_CIF_tx_ep_set_dma_mode0(core_ep->num); MSS_USB_CIF_tx_ep_disable_dma(core_ep->num); mode = MSS_USB_DMA_MODE0; } MSS_USB_CIF_configure_ep_dma(core_ep->dma_channel, MSS_USB_DMA_READ, mode, MSS_USB_DMA_BURST_MODE3, core_ep->num, (ptrdiff_t)(core_ep->buf_addr)); } MSS_USB_CIF_tx_ep_enable_irq(core_ep->num); } /***************************************************************************//** * Configures the RX EP for data transfer operations as per the parameters * provided by upper layer. */ void MSS_USB_CIF_rx_ep_configure ( mss_usb_ep_t* core_ep ) { uint8_t dpb = 1u; mss_usb_dma_mode_t mode; if (DPB_ENABLE == core_ep->dpb_enable) { dpb = 2u; } MSS_USB_CIF_rx_ep_set_fifo_size(core_ep->num, ((core_ep->fifo_size) / dpb), core_ep->dpb_enable); MSS_USB_CIF_rx_ep_set_fifo_addr(core_ep->num, core_ep->fifo_addr); if (DPB_ENABLE == core_ep->dpb_enable) { MSS_USB_CIF_enable_rx_ep_dpb(core_ep->num); } else if (DPB_DISABLE == core_ep->dpb_enable) { MSS_USB_CIF_disable_rx_ep_dpb(core_ep->num); } else { ASSERT(0); } MSS_USB_CIF_rx_ep_set_max_pkt(core_ep->num, core_ep->xfr_type, core_ep->max_pkt_size, core_ep->num_usb_pkt); MSS_USB_CIF_rx_ep_clr_data_tog(core_ep->num); MSS_USB_CIF_rx_ep_clr_rxpktrdy(core_ep->num); if (DMA_ENABLE == core_ep->dma_enable) { if (MSS_USB_XFR_BULK == core_ep->xfr_type) { MSS_USB_CIF_rx_ep_set_dma_mode1(core_ep->num); MSS_USB_CIF_rx_ep_enable_dma(core_ep->num); mode = MSS_USB_DMA_MODE1; } else { /* * DMA_ENable bit in RXCSRL is not required to be set in m0. if it is * set RX interrupt would not occur. */ MSS_USB_CIF_rx_ep_set_dma_mode0(core_ep->num); MSS_USB_CIF_rx_ep_disable_dma(core_ep->num); mode = MSS_USB_DMA_MODE0; } MSS_USB_CIF_configure_ep_dma(core_ep->dma_channel, MSS_USB_DMA_WRITE, mode, MSS_USB_DMA_BURST_MODE3, core_ep->num, (ptrdiff_t)(core_ep->buf_addr)); } MSS_USB_CIF_rx_ep_enable_irq(core_ep->num); } /***************************************************************************//** * Starts sending Test packet as specified in the USB2.0 * This is USB-IF certification requirement. */ void MSS_USB_CIF_start_testpacket(void) { uint8_t test_pkt[53] = { 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xEEU, 0xFEU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFCU, 0x7EU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0x7EU }; MSS_USB_CIF_load_tx_fifo(MSS_USB_CEP, test_pkt, 53u); MSS_USB_CIF_start_testpacket_bit(); MSS_USB_CIF_cep_set_txpktrdy(); MSS_USB_CIF_cep_disable_irq(); } #ifdef MSS_USB_HOST_ENABLED static uint8_t MSS_USB_CIF_host_rx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0u; if (MSS_USBH_CIF_rx_ep_is_rxpktrdy(ep_num)) { status = 0u; } if (MSS_USBH_CIF_rx_ep_is_rxstall_err(ep_num)) { status |= MSS_USB_EP_STALL_RCVD; MSS_USBH_CIF_rx_ep_clr_rxstall_err(ep_num); } if (MSS_USBH_CIF_rx_ep_is_naktimeout_err(ep_num)) { status |= MSS_USB_EP_NAK_TOUT; /* Not clearing NAKTIMEOUT error here. Application may want to abort * transfer. Clearing it here makes Scheduler keep trying the transfer */ } if (MSS_USBH_CIF_rx_ep_is_retry_err(ep_num)) { status |= MSS_USB_EP_NO_RESPONSE; MSS_USBH_CIF_rx_ep_clr_retry_err(ep_num); } return (status); } static uint8_t MSS_USB_CIF_host_tx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0; if (MSS_USBH_CIF_tx_ep_is_retry_err(ep_num)) { status |= MSS_USB_EP_NO_RESPONSE; MSS_USBH_CIF_tx_ep_clr_retry_err(ep_num); } if (MSS_USBH_CIF_tx_ep_is_rxstall_err(ep_num)) { status |= MSS_USB_EP_STALL_RCVD; MSS_USBH_CIF_tx_ep_clr_rxstall_err(ep_num); } if (MSS_USBH_CIF_tx_ep_is_naktimeout_err(ep_num)) { status |= MSS_USB_EP_NAK_TOUT; /* Not clearing NAKTIMEOUT error here. Application may want to abort * transfer. Clearing it here makes Scheduler keep trying the transfer */ } return(status); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef MSS_USB_DEVICE_ENABLED static uint8_t MSS_USB_CIF_device_rx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0u; if (MSS_USB_CIF_rx_ep_is_overrun(ep_num)) { status |= RX_EP_OVER_RUN_ERROR; MSS_USB_CIF_rx_ep_clr_overrun(ep_num); } if (MSS_USB_CIF_rx_ep_is_stall_sent_bit(ep_num)) { status |= RX_EP_STALL_ERROR; /* * "sent stall" bit should be cleared."Send Stall" bit is still set. * it should be cleared via Clear feature command or reset" */ MSS_USB_CIF_rx_ep_clr_stall_sent_bit(ep_num); } if (MSS_USB_CIF_rx_ep_is_dataerr(ep_num)) { /* This error will be cleared when RxPktRdy bit is cleared. */ status |= RX_EP_DATA_ERROR; } #if 0 /* * PID error and INCOMP error should be checked only in ISO transfers. * This should be moved to logical layer */ if (MSS_USB_CIF_rx_ep_is_piderr(ep_num)) { status |= RX_EP_PID_ERROR; /* Data sheet doesn't mention about how this error bit is cleared * Assuming that this will be cleared when RxPKTRdy is cleared.*/ } if (MSS_USB_CIF_rx_ep_is_isoincomp(ep_num)) { status |= RX_EP_ISO_INCOMP_ERROR; /* This error will be cleared when RxPktRdy bit is cleared.*/ } #endif /* if 0 */ return(status); } static uint8_t MSS_USB_CIF_device_tx_errchk(mss_usb_ep_num_t ep_num) { uint8_t status = 0u; if (MSS_USB_CIF_tx_ep_is_underrun(ep_num)) { /* Under-run errors should happen only for ISO endpoints.*/ status |= TX_EP_UNDER_RUN_ERROR; MSS_USB_CIF_tx_ep_clr_underrun(ep_num); } if (MSS_USB_CIF_tx_ep_is_stall_sent_bit(ep_num)) { status |= TX_EP_STALL_ERROR; MSS_USB_CIF_tx_ep_clr_stall_sent_bit(ep_num); } return(status); } #endif /* MSS_USB_DEVICE_ENABLED */ #ifdef __cplusplus } #endif mss_usb_common_cif.h000066400000000000000000000372271432224323300407560ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF driver * * USB-CIF driver public API. * * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_COMMON_CIF_H_ #define __MSS_USB_COMMON_CIF_H_ #include "mss_usb_config.h" #include "mss_usb_core_regs.h" #define __INLINE inline #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** Constant values internally used by the driver. */ #define CEP_MAX_PKT_SIZE 64u #define SETUP_PKT_SIZE 8u #define DPB_DISABLE 0u #define DPB_ENABLE 1u #ifdef MSS_USB_HOST_ENABLED #define SUSPENDM_DISABLE 0x0000u #define SUSPENDM_ENABLE 0x0001u #endif #define MSS_USB_WORD_BIT_0_MASK 0x0001u #define MSS_USB_BYTE_BIT_0_MASK 0x01u #define MSS_USB_BOOLEAN_FALSE 0x00u #define MSS_USB_BOOLEAN_TRUE 0x01u #define TX_EP_UNDER_RUN_ERROR 0x01u #define TX_EP_STALL_ERROR 0x02u #define RX_EP_OVER_RUN_ERROR 0x01u #define RX_EP_STALL_ERROR 0x02u #define RX_EP_DATA_ERROR 0x04u #define RX_EP_PID_ERROR 0x06u #define RX_EP_ISO_INCOMP_ERROR 0x08u #define CTRL_EP_SETUP_END_ERROR 0x01u #define CTRL_EP_STALL_ERROR 0x02u #define DMA_XFR_ERROR 0x40u #define MIN_EP_FIFO_SZ 0x0008u #define EP_FIFO_ADDR_STEP 0x0008u #define DMA_DISABLE 0u #define DMA_ENABLE 1u #define NO_ZLP_TO_XFR 0u #define ADD_ZLP_TO_XFR 1u /*-------------------------------------------------------------------------*//** INTRUSBE register - USB interrupts masks */ #define SUSPEND_IRQ_MASK 0x01u #define RESUME_IRQ_MASK 0x02u #define RESET_IRQ_MASK 0x04u /*Device mode*/ #define BABBLE_IRQ_MASK 0x04u /*Host mode*/ #define SOF_IRQ_MASK 0x08u #define CONNECT_IRQ_MASK 0x10u #define DISCONNECT_IRQ_MASK 0x20u #define SESSION_REQUEST_IRQ_MASK 0x40u #define VBUS_ERROR_IRQ_MASK 0x80u /*-------------------------------------------------------------------------*//** Types which can be used by LDL layer or the application. */ typedef enum { MSS_USB_XFR_CONTROL, MSS_USB_XFR_ISO, MSS_USB_XFR_BULK, MSS_USB_XFR_INTERRUPT, MSS_USB_XFR_HB_INTERRUPT, MSS_USB_XFR_HB_ISO } mss_usb_xfr_type_t; typedef enum { MSS_USB_DEVICE_HS, MSS_USB_DEVICE_FS, MSS_USB_DEVICE_LS } mss_usb_device_speed_t; typedef enum { MSS_USB_CEP = 0, MSS_USB_TX_EP_1, MSS_USB_TX_EP_2, MSS_USB_TX_EP_3, MSS_USB_TX_EP_4, MSS_USB_RX_EP_1 = 1, MSS_USB_RX_EP_2, MSS_USB_RX_EP_3, MSS_USB_RX_EP_4 } mss_usb_ep_num_t; typedef enum { MSS_USB_DMA_CHANNEL1, MSS_USB_DMA_CHANNEL2, MSS_USB_DMA_CHANNEL3, MSS_USB_DMA_CHANNEL4, MSS_USB_DMA_CHANNEL_NA } mss_usb_dma_channel_t; /*-------------------------------------------------------------------------*//** Types which are used internally by the driver. */ /* Device mode: states of the device */ typedef enum { MSS_USB_NOT_ATTACHED_STATE, MSS_USB_ATTACHED_STATE, MSS_USB_POWERED_STATE, MSS_USB_DEFAULT_STATE, MSS_USB_ADDRESS_STATE, MSS_USB_CONFIGURED_STATE, MSS_USB_SUSPENDED_STATE } mss_usb_state_t; typedef enum { MSS_USB_CORE_MODE_HOST, MSS_USB_CORE_MODE_DEVICE } mss_usb_core_mode_t; typedef enum { MSS_USB_EP_VALID = 0u, MSS_USB_EP_STALLED, MSS_USB_EP_NAK, MSS_USB_EP_NYET, MSS_USB_CEP_IDLE, MSS_USB_CEP_SETUP, MSS_USB_CEP_TX, MSS_USB_CEP_RX, #ifdef MSS_USB_HOST_ENABLED MSS_USB_CEP_STATUS_AFTER_IN, MSS_USB_CEP_STATUS_AFTER_OUT, MSS_USB_EP_TXN_SUCCESS, MSS_USB_EP_NAK_TOUT, MSS_USB_EP_NO_RESPONSE, MSS_USB_EP_STALL_RCVD, MSS_USB_EP_XFR_SUCCESS, MSS_USB_EP_ABORTED #endif //MSS_USB_HOST_ENABLED } mss_usb_ep_state_t; typedef enum mss_usb_pkt_type { MSS_USB_SETUP_PKT, MSS_USB_IN_DATA_PKT, MSS_USB_OUT_DATA_PKT, MSS_USB_STATUS_PKT_AFTER_IN, MSS_USB_STATUS_PKT_AFTER_OUT }mss_usb_pkt_type_t; /* Type of device - Detected through DevCTL.D7 register bit depending on the type of connector connected to on-board receptacle. */ typedef enum mss_usb_device_role { MSS_USB_DEVICE_ROLE_DEVICE_A, MSS_USB_DEVICE_ROLE_DEVICE_B } mss_usb_device_role_t; typedef enum { MSS_USB_DMA_WRITE, MSS_USB_DMA_READ } mss_usb_dma_dir_t; typedef enum { MSS_USB_DMA_MODE0=0, MSS_USB_DMA_MODE1=1 } mss_usb_dma_mode_t; typedef enum { MSS_USB_DMA_BURST_MODE0 = 0, MSS_USB_DMA_BURST_MODE1, MSS_USB_DMA_BURST_MODE2, MSS_USB_DMA_BURST_MODE3 } mss_usb_dma_burst_mode_t; typedef enum { VBUS_BLOW_SESSIONEND, VBUS_ABV_SESSIONEND_BLOW_AVALID, VBUS_ABV_AVALID_BLOW_VB_VALID, VBUS_ABV_VB_VALID } mss_usb_vbus_level_t; #ifdef MSS_USB_DEVICE_ENABLED typedef enum { MSS_USB_CTRL_EP_IDLE, MSS_USB_CTRL_EP_TX, MSS_USB_CTRL_EP_RX } mss_usbd_cep_state_t; #endif /* MSS_USB_DEVICE_ENABLED */ /*-------------------------------------------------------------------------*//** Data structures of USB-CIFL which are shared with USB-LL. */ typedef struct { /*EP configuration info*/ mss_usb_ep_num_t num; uint8_t dpb_enable; /*0 or 1*/ uint16_t fifo_size; /*number of bytes*/ uint16_t fifo_addr; /*number of bytes*/ uint8_t dma_enable; mss_usb_dma_channel_t dma_channel; uint16_t max_pkt_size; /*Maxpktsize register value*/ uint8_t stall; mss_usb_ep_state_t state; /*EP data Transfer related info*/ mss_usb_xfr_type_t xfr_type; uint32_t add_zlp; /* Number of pkts in one uFrame in case of Interrupt/ISO HB transfers. Number of split packets in case of Bulk transfers.Should always be more than 0. */ uint8_t num_usb_pkt; uint8_t* buf_addr; /* Transfer level info, used mainly for control transfer where the total length of data transfer is prior know through setup transaction In case of bulk transfer with Autospliting/amalgamation, this value is used when length of transfer is bigger than one amalgamated packet. */ uint32_t xfr_length; uint32_t xfr_count; /* Single packet Transaction level info In case of bulk transfer with Autospliting/amalgamation, this value represents the amalgamated packet. */ uint32_t txn_length; uint32_t txn_count; #ifdef MSS_USB_HOST_ENABLED /* Manual toggle enable is required only when dynamic switching of EP is supported. We don't support it. HubAddr and HubPortNum registers are needed for talking to LS/FS devices connected through Hub - We don't support hub connected devices yet. LS/FS device directly connected to SF2 is supported though. */ uint8_t cep_data_dir; uint8_t* cep_cmd_addr; uint8_t disable_ping; /*Depends on target speed*/ uint32_t req_pkt_n; /*No of IN packets*/ /* Interval Must be in terms of frame/uframe. Indicates NAKLIMIT0 register value for EP0. TX/RXInterval register value for TX/RX EP. */ uint32_t interval; /*This index will be used to choose a particular connected device out of the Multiple connected devices when Multiple devices are supported. Currently we support only one device hence this will always evalueate to 0*/ uint8_t tdev_idx; #endif /* MSS_USB_HOST_ENABLED */ }mss_usb_ep_t; /*-------------------------------------------------------------------------*//** Data structures which are used internally by the driver. */ /*Device mode configuration information*/ typedef struct { uint8_t device_addr; uint8_t device_total_interfaces; uint8_t device_total_ep; mss_usb_state_t device_state; mss_usb_state_t device_state_at_suspend; uint8_t device_status; mss_usb_device_speed_t device_speed; /*USB speed in Device mode*/ uint8_t active_config_num; /*SetConfig command*/ uint8_t active_interface_num;/*SetInterface command*/ uint16_t config_feature_status; uint8_t remote_wakeup; } mss_usbd_dev_conf_t; /* Device mode call-back function called from CIF layer */ typedef struct { void (*usbd_ep_rx)( mss_usb_ep_num_t num, uint8_t status ); void (*usbd_ep_tx_complete)( mss_usb_ep_num_t num, uint8_t status ); void (*usbd_cep_setup)( uint8_t status ); void (*usbd_cep_rx)( uint8_t status ); void (*usbd_cep_tx_complete)( uint8_t status ); void (*usbd_sof)( uint8_t status ); void (*usbd_reset)( void ); void (*usbd_suspend)( void ); void (*usbd_resume)( void ); void (*usbd_disconnect)( void ); void (*usbd_dma_handler)(mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val); } mss_usbd_cb_t; /* MSS USB Hardware core information. This is read-only */ typedef struct { uint8_t core_max_nbr_of_tx_ep; uint8_t core_max_nbr_of_rx_ep; uint8_t core_max_nbr_of_dma_chan; uint8_t core_ram_bus_width; uint8_t core_WTCON; uint8_t core_WTID; uint8_t core_VPLEN; uint8_t core_HS_EOF1; uint8_t core_FS_EOF1; uint8_t core_LS_EOF1; uint8_t core_configdata; } mss_usb_core_info_t; /* Internal DMA Configuration data */ typedef struct { uint8_t dma_channel; uint8_t dma_dir; uint8_t dma_assigned_ep; uint8_t dma_mode; uint8_t dma_burst_mode; uint8_t dma_status; } mss_usb_dma_t; /*----------------------------------------------------------------------------*/ /*_------------------------USB-CIF Public APIs--------------------------------*/ /*----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_cep_flush_fifo(void) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 |= CSR0H_DEV_FLUSH_FIFO_MASK; } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_tx_ep_flush_fifo(mss_usb_ep_num_t ep_num) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_FLUSH_FIFO_MASK; } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_rx_ep_flush_fifo(mss_usb_ep_num_t ep_num) { USB->ENDPOINT[ep_num].RX_CSR |= RxCSRL_REG_EPN_FLUSH_FIFO_MASK; } /*-------------------------------------------------------------------------*//** */ static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_fifo_full(mss_usb_ep_num_t ep_num) { return(((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_RX_FIFO_FULL_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** * Enables USB interrupts. */ static __INLINE void MSS_USB_CIF_enable_usbirq(uint8_t irq_mask) { USB->USB_ENABLE |= (irq_mask); } /*-------------------------------------------------------------------------*//** Disables USB interrupts. */ static __INLINE void MSS_USB_CIF_disable_usbirq(uint8_t irq_mask) { USB->USB_ENABLE &= ~(irq_mask); } /*-------------------------------------------------------------------------*//** Indicates that there is at least one byte available to be transmitted from TX FIFO */ static __INLINE uint8_t MSS_USB_CIF_is_txepfifo_notempty(mss_usb_ep_num_t ep_num) { return(((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_TX_FIFO_NE_MASK) ? 1u : 0u)); } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_cep_enable_irq ( void ) { USB->TX_IRQ_ENABLE |= (uint16_t)(TX_IRQ_ENABLE_REG_CEP_MASK); } /*-------------------------------------------------------------------------*//** */ static __INLINE void MSS_USB_CIF_cep_disable_irq ( void ) { USB->TX_IRQ_ENABLE &= (uint16_t)(~TX_IRQ_ENABLE_REG_CEP_MASK); } /*-------------------------------------------------------------------------*//** INDEX register related APIs */ static __INLINE void MSS_USB_CIF_set_index_reg ( uint8_t index ) { USB->INDEX = index; } static __INLINE void MSS_USB_CIF_start_testse0nak(void) { USB->TEST_MODE = TESTMODE_SE0NAK_MASK; } static __INLINE void MSS_USB_CIF_start_testj(void) { USB->TEST_MODE = TESTMODE_TESTJ_MASK; } static __INLINE void MSS_USB_CIF_start_testk(void) { USB->TEST_MODE = TESTMODE_TESTK_MASK; } static __INLINE void MSS_USB_CIF_start_testpacket_bit(void) { USB->TEST_MODE = TESTMODE_TESTPACKET_MASK; } static __INLINE void MSS_USB_CIF_start_forcehost_ena(void) { USB->TEST_MODE = TESTMODE_FORCEHOST_MASK | TESTMODE_FORCEHS_MASK; } static __INLINE void MSS_USB_CIF_end_testmode(void) { USB->TEST_MODE = 0x00U; } /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_configure_ep_dma ( mss_usb_dma_channel_t channel, mss_usb_dma_dir_t dir, mss_usb_dma_mode_t dma_mode, mss_usb_dma_burst_mode_t burst_mode, mss_usb_ep_num_t ep_num, uint32_t buf_addr ); /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_tx_ep_configure ( mss_usb_ep_t* core_ep ); /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_rx_ep_configure ( mss_usb_ep_t* core_ep ); /*-------------------------------------------------------------------------*//** Prepares the RX EP for receiving data as per parameters provided by upper layer */ void MSS_USB_CIF_rx_ep_read_prepare ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length ); /*-------------------------------------------------------------------------*//** */ void MSS_USB_CIF_ep_write_pkt ( mss_usb_ep_num_t ep_num, uint8_t* buf_addr, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t xfr_length, uint32_t txn_length ); /*-------------------------------------------------------------------------*//** USB2.0 test mode functions */ void MSS_USB_CIF_start_testpacket ( void ); #ifdef __cplusplus } #endif #endif /*__MSS_USB_COMMON_CIF_H_*/ mss_usb_common_reg_io.h000066400000000000000000000733151432224323300414570ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF. * * This file provides interfaces to perform register bit level * I\O operations which are independent of USB Device/host mode. * * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_COMMON_REG_IO_H_ #define __MSS_USB_COMMON_REG_IO_H_ #include #include "mss_usb_common_cif.h" #include "mss_usb_core_regs.h" #define __INLINE inline #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** * Common function for DEVICE and HOST mode. */ /*-------------------------------------------------------------------------*//** SOFT_RST register related APIs */ static __INLINE void MSS_USB_CIF_soft_reset ( void ) { volatile uint8_t soft_reset; USB->SOFT_RST = SOFT_RESET_REG_MASK; do { soft_reset = USB->SOFT_RST; } while (soft_reset != 0x00u); } /*-------------------------------------------------------------------------*//** POWER register related APIs */ static __INLINE void MSS_USB_CIF_enable_hs_mode ( void ) { USB->POWER |= POWER_REG_ENABLE_HS_MASK; } static __INLINE void MSS_USB_CIF_disable_hs_mode ( void ) { USB->POWER &= ~POWER_REG_ENABLE_HS_MASK; } /*-------------------------------------------------------------------------*//** Read USB interrupt register to know which interrupt has occurred. */ static __INLINE uint8_t MSS_USB_CIF_read_irq_reg ( void ) { return (USB->USB_IRQ); } /*-------------------------------------------------------------------------*//** EP IRQ related APIs */ /* TX IRQ related APIs */ static __INLINE uint16_t MSS_USB_CIF_read_tx_ep_irq_reg ( void ) { return (USB->TX_IRQ); } static __INLINE uint16_t MSS_USB_CIF_read_rx_ep_irq_reg ( void ) { return (USB->RX_IRQ); } static __INLINE void MSS_USB_CIF_clr_usb_irq_reg ( void ) { USB->USB_IRQ = 0u; } static __INLINE void MSS_USB_CIF_tx_ep_enable_irq ( mss_usb_ep_num_t ep_num ) { USB->TX_IRQ_ENABLE |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num); } static __INLINE void MSS_USB_CIF_tx_ep_disable_irq ( mss_usb_ep_num_t ep_num ) { USB->TX_IRQ_ENABLE &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num)); } static __INLINE void MSS_USB_CIF_tx_ep_disable_irq_all ( void ) { /* Keep D0, CEP interrupt bit unaltered.*/ USB->TX_IRQ_ENABLE = (USB->TX_IRQ_ENABLE & TX_IRQ_ENABLE_REG_CEP_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_enable_irq ( mss_usb_ep_num_t ep_num ) { USB->RX_IRQ_ENABLE |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num); } static __INLINE void MSS_USB_CIF_rx_ep_disable_irq ( mss_usb_ep_num_t ep_num ) { USB->RX_IRQ_ENABLE &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << (uint8_t)ep_num)); } static __INLINE void MSS_USB_CIF_rx_ep_disable_irq_all ( void ) { USB->RX_IRQ_ENABLE = 0u ; } /*-------------------------------------------------------------------------*//** FRAME register related APIs */ static __INLINE uint16_t MSS_USB_CIF_get_last_frame_nbr ( void ) { return (USB->FRAME); } /*-------------------------------------------------------------------------*//** DEVCTL register related APIs */ static __INLINE mss_usb_core_mode_t MSS_USB_CIF_get_mode ( void ) { return (((USB->DEV_CTRL & DEV_CTRL_HOST_MODE_MASK) ? MSS_USB_CORE_MODE_HOST : MSS_USB_CORE_MODE_DEVICE)); } static __INLINE mss_usb_vbus_level_t MSS_USB_CIF_get_vbus_level ( void ) { uint8_t vbus; mss_usb_vbus_level_t ret_val = VBUS_BLOW_SESSIONEND; vbus = (USB->DEV_CTRL & DEV_CTRL_VBUS_MASK); switch (vbus) { case VBUS_BELOW_SESSION_END: ret_val = VBUS_BLOW_SESSIONEND; break; case VBUS_ABOVE_SESSION_END: ret_val = VBUS_ABV_SESSIONEND_BLOW_AVALID; break; case VBUS_ABOVE_AVALID: ret_val = VBUS_ABV_AVALID_BLOW_VB_VALID; break; case VBUS_ABOVE_VBUS_VALID: ret_val = VBUS_ABV_VB_VALID; break; default: /* Empty */ break; } return ret_val; } static __INLINE mss_usb_device_role_t MSS_USB_CIF_get_role ( void ) { /* TODO:only valid when session bit is set */ return (((USB->DEV_CTRL & DEV_CTRL_B_DEVICE_MASK) ? MSS_USB_DEVICE_ROLE_DEVICE_B : MSS_USB_DEVICE_ROLE_DEVICE_A)); } static __INLINE uint8_t MSS_USB_CIF_is_session_on ( void ) { /* TODO:only valid when session bit is set */ return (((USB->DEV_CTRL & DEV_CTRL_SESSION_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_start_session(void) { USB->DEV_CTRL |= DEV_CTRL_SESSION_MASK; } static __INLINE void MSS_USB_CIF_stop_session(void) { USB->DEV_CTRL &= ~DEV_CTRL_SESSION_MASK; } /*-------------------------------------------------------------------------*//** INDEXED registers */ /*-------------------------------------------------------------------------*//** CSR0L register related APIs */ static __INLINE uint8_t MSS_USB_CIF_cep_is_rxpktrdy ( void ) { return (((USB->INDEXED_CSR.DEVICE_EP0.CSR0 & CSR0L_DEV_RX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_cep_set_txpktrdy ( void ) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 |= CSR0L_DEV_TX_PKT_RDY_MASK; } static __INLINE void MSS_USB_CIF_cep_clr_stall_sent ( void ) { USB->INDEXED_CSR.DEVICE_EP0.CSR0 &= ~CSR0L_DEV_STALL_SENT_MASK; } static __INLINE uint8_t MSS_USB_CIF_cep_is_stall_sent ( void ) { return (((USB->INDEXED_CSR.DEVICE_EP0.CSR0 & CSR0L_DEV_STALL_SENT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_cep_clr_setupend ( void ) { /* Setting SERVICED_SETUP_END bit clears SetupEnd bit */ USB->INDEXED_CSR.DEVICE_EP0.CSR0 |= CSR0L_DEV_SERVICED_SETUP_END_MASK; } static __INLINE uint8_t MSS_USB_CIF_cep_is_setupend ( void ) { return (((USB->INDEXED_CSR.DEVICE_EP0.CSR0 & CSR0L_DEV_SETUP_END_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_cep_reset_csr0_reg ( void ) { /* load the reset value for the register */ USB->INDEXED_CSR.DEVICE_EP0.CSR0 = 0u; } /*-------------------------------------------------------------------------*//** CNTRH0 register related APIs */ static __INLINE uint8_t MSS_USB_CIF_cep_rx_byte_count ( void ) { /* TODO:confirm CSR0.D0 bit before returning */ return (USB->INDEXED_CSR.DEVICE_EP0.COUNT0 & COUNT0_REG_MASK); } /*-------------------------------------------------------------------------*//** TXMAXP register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_max_pkt ( mss_usb_ep_num_t ep_num, mss_usb_xfr_type_t xfr_type, uint16_t max_pkt_size, uint8_t num_usb_pkt ) { /* TODO:make sure that there is no data in FIFO before writing into the maxP reg */ if ((ep_num > MSS_USB_CEP) && ((max_pkt_size % 8) == 0u) && (num_usb_pkt > 0u)) { if((num_usb_pkt > 31u)) { /* not allowed */ } else { USB->ENDPOINT[ep_num].TX_MAX_P = 0u; USB->ENDPOINT[ep_num].TX_MAX_P = num_usb_pkt - 1u; USB->ENDPOINT[ep_num].TX_MAX_P <<= TX_MAX_P_REG_NUM_USB_PKT_SHIFT; USB->ENDPOINT[ep_num].TX_MAX_P |= (max_pkt_size); } } } /*-------------------------------------------------------------------------*//** TXCSRL register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_txpktrdy ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_TX_PKT_RDY_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_txpktrdy ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_TX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_set_send_stall_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_SEND_STALL_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_send_stall_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_REG_EPN_SEND_STALL_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_REG_EPN_STALL_SENT_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { return (uint8_t)(((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_STALL_SENT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_clr_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_REG_EPN_CLR_DATA_TOG_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_isoincomp ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_ISO_INCOMP_TX_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** TXCSRH register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_dma_mode1 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_DMA_MODE_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_set_dma_mode0 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_DMA_MODE_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_get_dma_mode ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_REG_EPN_DMA_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_set_force_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_FRC_DAT_TOG_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_force_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_FRC_DAT_TOG_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_enable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_ENABLE_DMA_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_disable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_ENABLE_DMA_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_dma_enabled ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_REG_EPN_ENABLE_DMA_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_set_tx_mode ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_TXRX_MODE_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_set_rx_mode ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_TXRX_MODE_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_enable_iso ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_ENABLE_ISO_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_disable_iso ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_ENABLE_ISO_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_set_autoset ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_autoset ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK; } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_autoset ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USB_CIF_tx_ep_is_underrun ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_REG_EPN_UNDERRUN_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_tx_ep_clr_underrun ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_REG_EPN_UNDERRUN_MASK; } static __INLINE void MSS_USB_CIF_tx_ep_clr_csrreg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR = 0x0000U; } /*-------------------------------------------------------------------------*//** RXMAXP register related APIs */ static __INLINE void MSS_USB_CIF_rx_ep_set_max_pkt ( mss_usb_ep_num_t ep_num, mss_usb_xfr_type_t xfr_type, uint16_t max_pkt_size, uint8_t num_usb_pkt ) { /* TODO:make sure that there is no data in FIFO before writing into the maxP reg */ if ((ep_num > MSS_USB_CEP) && (max_pkt_size > 0u) && ((max_pkt_size % 8) == 0u)) { if ((num_usb_pkt > 31u)) { /*not allowed*/ } else { USB->ENDPOINT[ep_num].RX_MAX_P = 0u; USB->ENDPOINT[ep_num].RX_MAX_P = num_usb_pkt - 1u; USB->ENDPOINT[ep_num].RX_MAX_P <<= RX_MAX_P_REG_NUM_USB_PKT_SHIFT; USB->ENDPOINT[ep_num].RX_MAX_P |= (max_pkt_size); } } } /*-------------------------------------------------------------------------*//** RXCSRL register related APIs */ static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_rxpktrdy ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_RX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_rxpktrdy ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RxCSRL_REG_EPN_RX_PKT_RDY_MASK; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_overrun ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_OVERRUN_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_overrun ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_OVERRUN_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_dataerr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_DATA_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_set_send_stall_bit ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_SEND_STALL_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_clr_send_stall_bit ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_SEND_STALL_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_STALL_SENT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_stall_sent_bit ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_STALL_SENT_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_clr_data_tog ( mss_usb_ep_num_t ep_num ) { /* setting CLR_DAT_TOG bit clears USB Data toggle bit */ USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_CLR_DAT_TOG_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } /*-------------------------------------------------------------------------*//** RXCSRH register related APIs */ static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_isoincomp ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_RX_ISO_INCOMP) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE mss_usb_dma_mode_t MSS_USB_CIF_rx_ep_get_dma_mode ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_DMA_MODE_MASK) ? MSS_USB_DMA_MODE1 : MSS_USB_DMA_MODE0)); } static __INLINE void MSS_USB_CIF_rx_ep_set_dma_mode1 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_DMA_MODE_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_set_dma_mode0 ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_DMA_MODE_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_enable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_ENABLE_DMA_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_disable_dma ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_ENABLE_DMA_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_dma_enabled ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_ENABLE_DMA_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_piderr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_ISO_PID_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_disable_nyet ( mss_usb_ep_num_t ep_num ) { /* Setting BI_DIS_NYET mask disables NYET */ USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_BI_DIS_NYET_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_enable_nyet ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_BI_DIS_NYET_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_disable_iso ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_ENABLE_ISO_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE void MSS_USB_CIF_rx_ep_enable_iso ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_ENABLE_ISO_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_set_autoclr ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= (RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK | RxCSRL_REG_EPN_RX_PKT_RDY_MASK); } static __INLINE void MSS_USB_CIF_rx_ep_clr_autoclr ( mss_usb_ep_num_t ep_num ) { uint16_t reg_val = USB->ENDPOINT[ep_num].RX_CSR; reg_val &= ~RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK; reg_val |= RxCSRL_REG_EPN_RX_PKT_RDY_MASK; USB->ENDPOINT[ep_num].RX_CSR = reg_val; } static __INLINE uint8_t MSS_USB_CIF_rx_ep_is_autoclr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_rx_ep_clr_csrreg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR = 0x0000U; } /*-------------------------------------------------------------------------*//** RXCOUNT register related APIs */ static __INLINE uint16_t MSS_USB_CIF_rx_ep_read_count ( mss_usb_ep_num_t ep_num ) { /* only valid when rxpktrdy is set */ return (USB->ENDPOINT[ep_num].RX_COUNT); } /*-------------------------------------------------------------------------*//** FIFOx register related APIs */ static __INLINE void MSS_USB_CIF_load_tx_fifo ( mss_usb_ep_num_t ep_num, void * in_data, uint32_t length ) { uint32_t idx; uint32_t* temp; uint8_t* temp_8bit; uint16_t words = length / 4; temp = in_data; temp_8bit = in_data; for(idx = 0u; idx < words; ++idx) { USB->FIFO[ep_num].WORD.VALUE = (uint32_t)temp[idx]; } for(idx = (length - (length % 4)); idx < length; ++idx) { USB->FIFO[ep_num].BYTE.VALUE = (uint8_t)temp_8bit[idx]; } } static __INLINE void MSS_USB_CIF_read_rx_fifo ( mss_usb_ep_num_t ep_num, void * out_data, uint32_t length ) { uint32_t idx; volatile uint32_t* temp; uint8_t* temp_8bit; uint16_t words = length / 4; temp = out_data; temp_8bit = out_data; for(idx = 0u; idx < words; ++idx) { temp[idx] = USB->FIFO[ep_num].WORD.VALUE; } for(idx = (length - (length % 4u)); idx < length; ++idx) { temp_8bit[idx] = USB->FIFO[ep_num].BYTE.VALUE; } } static __INLINE uint8_t MSS_USB_CIF_read_rx_fifo_byte ( mss_usb_ep_num_t ep_num ) { return (uint8_t)(USB->FIFO[ep_num].BYTE.VALUE); } static __INLINE uint16_t MSS_USB_CIF_read_rx_fifo_halfword ( mss_usb_ep_num_t ep_num ) { return (uint16_t)(USB->FIFO[ep_num].HALFWORD.VALUE); } static __INLINE uint32_t MSS_USB_CIF_read_rx_fifo_word ( mss_usb_ep_num_t ep_num ) { return (uint32_t)(USB->FIFO[ep_num].WORD.VALUE); } /*-------------------------------------------------------------------------*//** DynFIFOSIZE register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_fifo_size ( mss_usb_ep_num_t ep_num, uint16_t fifo_size, uint8_t dpb ) { uint16_t temp; uint8_t i = 0; /* Valid FIFO sizes are 8,16,32,64,128,512,1024,2048,4096 */ if ((ep_num > MSS_USB_CEP) && (fifo_size >= MIN_EP_FIFO_SZ)) { USB->INDEX = ep_num; temp = (fifo_size / MIN_EP_FIFO_SZ); while (!(temp & MSS_USB_WORD_BIT_0_MASK)) { temp >>= 1u; i++; } USB->TX_FIFO_SIZE = ((dpb << TXFIFOSZ_REG_DPB_SHIFT) | i); } } static __INLINE void MSS_USB_CIF_rx_ep_set_fifo_size ( mss_usb_ep_num_t ep_num, uint16_t fifo_size, uint8_t dpb ) { /* fifo_size is the size in terms of number of bytes.*/ uint16_t temp; uint8_t i = 0u; /* Valid FIFO sizes are 8,16,32,64,128,512,1024,2048,4096 */ if ((ep_num > MSS_USB_CEP) && (fifo_size >= MIN_EP_FIFO_SZ)) { USB->INDEX = ep_num; temp= (fifo_size / MIN_EP_FIFO_SZ); while (!(temp & MSS_USB_WORD_BIT_0_MASK)) { temp >>= 1u; i++; } USB->RX_FIFO_SIZE = ((dpb << RXFIFOSZ_REG_DPB_SHIFT) | i); } } /*-------------------------------------------------------------------------*//** DynFIFOAD register related APIs */ static __INLINE void MSS_USB_CIF_tx_ep_set_fifo_addr ( mss_usb_ep_num_t ep_num, uint16_t addr ) { /* Valid address values are from 0 to FFF8 in steps of 8 */ if (ep_num > MSS_USB_CEP) { USB->INDEX = ep_num; USB->TX_FIFO_ADDR = (addr / EP_FIFO_ADDR_STEP); } } static __INLINE void MSS_USB_CIF_rx_ep_set_fifo_addr ( mss_usb_ep_num_t ep_num, uint16_t addr ) { /* Valid address values are from 0 to FFF8 in steps of 8 */ if (ep_num > MSS_USB_CEP) { USB->INDEX = ep_num; USB->RX_FIFO_ADDR = (addr / EP_FIFO_ADDR_STEP); } } /*-------------------------------------------------------------------------*//** RX_DPKTBUFDIS register related APIs */ static __INLINE void MSS_USB_CIF_disable_rx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->RX_DPBUF_DIS |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << ep_num); } static __INLINE void MSS_USB_CIF_enable_rx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->RX_DPBUF_DIS &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << ep_num)); } /*-------------------------------------------------------------------------*//** TX_DPKTBUFDIS register related APIs */ static __INLINE void MSS_USB_disable_tx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->TX_DPBUF_DIS |= (uint16_t)(MSS_USB_WORD_BIT_0_MASK << ep_num); } static __INLINE void MSS_USB_enable_tx_ep_dpb ( mss_usb_ep_num_t ep_num ) { USB->TX_DPBUF_DIS &= (uint16_t)(~(MSS_USB_WORD_BIT_0_MASK << ep_num)); } /*-------------------------------------------------------------------------*//** DMA_INTR register related APIs */ static __INLINE uint32_t MSS_USB_CIF_dma_read_irq ( void ) { return (USB->DMA_CHANNEL[0].IRQ); } /*-------------------------------------------------------------------------*//** * DMA_CNTL register related APIs */ static __INLINE void MSS_USB_CIF_dma_start_xfr ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL |= DMA_CNTL_REG_START_XFR_MASK; } static __INLINE void MSS_USB_CIF_dma_stop_xfr ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL &= ~DMA_CNTL_REG_START_XFR_MASK; } static __INLINE void MSS_USB_CIF_dma_set_dir ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_dir_t dir ) { /* dir = 1 => DMA read (TX EP) dir = 0 => DMA write (RX EP) */ USB->DMA_CHANNEL[dma_channel].CNTL |= (dir << DMA_CNTL_REG_DMA_DIR_SHIFT); } static __INLINE mss_usb_dma_dir_t MSS_USB_CIF_dma_get_dir ( mss_usb_dma_channel_t dma_channel ) { return(((USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_DIR_MASK) ? MSS_USB_DMA_READ : MSS_USB_DMA_WRITE)); } static __INLINE void MSS_USB_CIF_dma_set_mode ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_mode_t dma_mode ) { USB->DMA_CHANNEL[dma_channel].CNTL |= (dma_mode << DMA_CNTL_REG_DMA_MODE_SHIFT); } static __INLINE mss_usb_dma_mode_t MSS_USB_CIF_dma_get_mode ( mss_usb_dma_channel_t dma_channel ) { return (((USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_MODE_MASK) ? MSS_USB_DMA_MODE1: MSS_USB_DMA_MODE0)); } static __INLINE void MSS_USB_CIF_dma_enable_irq ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL |= DMA_CNTL_REG_ENABLE_DMA_IRQ_MASK; } static __INLINE void MSS_USB_CIF_dma_disable_irq ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL &= ~DMA_CNTL_REG_ENABLE_DMA_IRQ_MASK; } static __INLINE void MSS_USB_CIF_dma_assign_to_epnum ( mss_usb_dma_channel_t dma_channel, mss_usb_ep_num_t ep_num ) { USB->DMA_CHANNEL[dma_channel].CNTL |= ((ep_num << DMA_CNTL_REG_DMA_EP_NUM_SHIFT) & DMA_CNTL_REG_DMA_EP_NUM_MASK); } static __INLINE mss_usb_ep_num_t MSS_USB_CIF_dma_get_epnum ( mss_usb_dma_channel_t dma_channel ) { /* This API will return numbers from 0 to 15, mss_usb_ep_num_t maps it to TX EP numbers. Using DMA DIR, CIF driver should correctly map it as TX EP or RX EP. */ volatile uint8_t ep_num; ep_num = (USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_EP_NUM_MASK); return (mss_usb_ep_num_t)(ep_num >> DMA_CNTL_REG_DMA_EP_NUM_SHIFT); } static __INLINE uint8_t MSS_USB_CIF_dma_is_bus_err ( mss_usb_dma_channel_t dma_channel ) { return (((USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_BUS_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USB_CIF_dma_clr_bus_err ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL &= ~DMA_CNTL_REG_DMA_BUS_ERR_MASK; } static __INLINE void MSS_USB_CIF_dma_set_burst_mode ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_burst_mode_t burst_mode ) { USB->DMA_CHANNEL[dma_channel].CNTL |= ((burst_mode << DMA_CNTL_REG_DMA_BURST_MODE_SHIFT) & DMA_CNTL_REG_DMA_BURST_MODE_MASK); } static __INLINE mss_usb_dma_burst_mode_t MSS_USB_CIF_dma_get_burst_mode ( mss_usb_dma_channel_t dma_channel, mss_usb_dma_burst_mode_t burst_mode ) { uint8_t mode; mode = (USB->DMA_CHANNEL[dma_channel].CNTL & DMA_CNTL_REG_DMA_BURST_MODE_MASK); return (mss_usb_dma_burst_mode_t)(mode >> DMA_CNTL_REG_DMA_BURST_MODE_SHIFT); } static __INLINE void MSS_USB_CIF_dma_clr_ctrlreg ( mss_usb_dma_channel_t dma_channel ) { USB->DMA_CHANNEL[dma_channel].CNTL = 0x0000U; } /*-------------------------------------------------------------------------*//** DMA_ADDR register related APIs */ static __INLINE uint32_t MSS_USB_CIF_dma_read_addr ( mss_usb_dma_channel_t dma_channel ) { return (USB->DMA_CHANNEL[dma_channel].ADDR); } static __INLINE void MSS_USB_CIF_dma_write_addr ( mss_usb_dma_channel_t dma_channel, uint32_t addr ) { USB->DMA_CHANNEL[dma_channel].ADDR = addr; } /*-------------------------------------------------------------------------*//** DMA_COUNT register related APIs */ static __INLINE uint32_t MSS_USB_CIF_dma_read_count ( mss_usb_dma_channel_t dma_channel ) { return (USB->DMA_CHANNEL[dma_channel].COUNT); } static __INLINE void MSS_USB_CIF_dma_write_count ( mss_usb_dma_channel_t dma_channel, uint32_t count ) { USB->DMA_CHANNEL[dma_channel].COUNT = count; } #ifdef __cplusplus } #endif #endif /* __MSS_USB_COMMON_REG_IO_H_ */ mss_usb_config.h000066400000000000000000000055671432224323300401140ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Microchip PolarFire SoC MSS USB Driver Stack * * MSS USB Driver stack configuration parameters. * User must choose the constant definitions in this file to select the mode of * operation. * The constants defined in this file are used by MSS USB driver stack to * function as per configuration. * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_CONFIG_H_ #define __MSS_USB_CONFIG_H_ /*-------------------------------------------------------------------------*//** User should choose the Mode in which PolarFire SoC MSS USB should operate */ /* #define MSS_USB_OTG_DUAL_ROLE_MODE */ /* #define MSS_USB_OTG_PERIPHERAL_MODE*/ /* Configures the MSS USB Driver Stack to operate in USB Host mode. */ #define MSS_USB_OTG_HOST_MODE /* Configures the MSS USB Driver Stack to operate in USB Device mode. */ /* #define MSS_USB_PERIPHERAL_MODE */ /* Used for internal testing of the driver. Not for Application use. */ /* #define MSS_USB_DEVICE_TEST_MODE */ /*-------------------------------------------------------------------------*//** Definitions Internally generated for use in the Core and logical layer. */ #ifdef MSS_USB_OTG_DUAL_ROLE_MODE #define MSS_USB_HOST_ENABLED #define MSS_USB_DEVICE_ENABLED #define MSS_USB_OTG_SRP_ENABLED #define MSS_USB_OTG_HNP_ENABLED #endif #ifdef MSS_USB_OTG_PERIPHERAL_MODE #define MSS_USB_DEVICE_ENABLED #define MSS_USB_OTG_SRP_ENABLED #endif #ifdef MSS_USB_PERIPHERAL_MODE #define MSS_USB_DEVICE_ENABLED #define MSS_USB_DEVICE_PRINTER #endif #ifdef MSS_USB_OTG_HOST_MODE #define MSS_USB_HOST_ENABLED #define MSS_USB_OTG_SRP_ENABLED #endif #endif /* __MSS_USB_CONFIG_H_ */ mss_usb_core_regs.h000066400000000000000000000457561432224323300406230ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF driver * * * Register bit offset and mask definitions for PolarFire SoC MSS USB. * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_CORE_REGS_H_ #define __MSS_USB_CORE_REGS_H_ #include #include /****************************************************************************** * Power register */ #define POWER_REG_ENABLE_SUSPENDM_MASK 0x01u #define POWER_REG_SUSPEND_MODE_MASK 0x02u #define POWER_REG_RESUME_SIGNAL_MASK 0x04u #define POWER_REG_BUS_RESET_SIGNAL_MASK 0x08u #define POWER_REG_HS_MODE_MASK 0x10u #define POWER_REG_ENABLE_HS_MASK 0x20u #define POWER_REG_SOFT_CONN_MASK 0x40u #define POWER_REG_ISO_UPDATE_MASK 0x80u /****************************************************************************** * Soft_reset_mask */ #define SOFT_RESET_REG_MASK 0x03u /****************************************************************************** * DevCTL register bit masks */ #define DEV_CTRL_SESSION_MASK 0x01u #define DEV_CTRL_HOST_REQ_MASK 0x02u #define DEV_CTRL_HOST_MODE_MASK 0x04u #define DEV_CTRL_VBUS_MASK 0x18u #define DEV_CTRL_LS_DEV_MASK 0x20u #define DEV_CTRL_FS_DEV_MASK 0x40u #define DEV_CTRL_B_DEVICE_MASK 0x80u #define VBUS_BELOW_SESSION_END 0x00u #define VBUS_ABOVE_SESSION_END 0x08u #define VBUS_ABOVE_AVALID 0x10u #define VBUS_ABOVE_VBUS_VALID 0x18u /****************************************************************************** * CSR0L bit masks (peripheral mode) */ #define CSR0L_DEV_RX_PKT_RDY_MASK 0x0001u #define CSR0L_DEV_TX_PKT_RDY_MASK 0x0002u #define CSR0L_DEV_STALL_SENT_MASK 0x0004u #define CSR0L_DEV_DATA_END_MASK 0x0008u #define CSR0L_DEV_SETUP_END_MASK 0x0010u #define CSR0L_DEV_SEND_STALL_MASK 0x0020u #define CSR0L_DEV_SERVICED_RX_PKT_RDY_MASK 0x0040u #define CSR0L_DEV_SERVICED_SETUP_END_MASK 0x0080u /****************************************************************************** * CSR0H bit masks (peripheral mode) */ #define CSR0H_DEV_FLUSH_FIFO_MASK 0x0100u /****************************************************************************** * COUNT0 register masks */ #define COUNT0_REG_MASK 0x7fu /****************************************************************************** * Endpoint TxMAXP register bit masks */ #define TX_MAX_P_REG_NUM_USB_PKT_SHIFT 11u /****************************************************************************** * Endpoint TxCSRL register bit masks */ #define TxCSRL_REG_EPN_TX_PKT_RDY_MASK 0x0001u #define TxCSRL_REG_EPN_TX_FIFO_NE_MASK 0x0002u #define TxCSRL_REG_EPN_UNDERRUN_MASK 0x0004u #define TxCSRL_REG_EPN_FLUSH_FIFO_MASK 0x0008u #define TxCSRL_REG_EPN_SEND_STALL_MASK 0x0010u #define TxCSRL_REG_EPN_STALL_SENT_MASK 0x0020u #define TxCSRL_REG_EPN_CLR_DATA_TOG_MASK 0x0040u #define TxCSRL_REG_EPN_ISO_INCOMP_TX_MASK 0x0080u /****************************************************************************** * Endpoint TxCSRH register bit masks */ /*D0,D1 are un-used*/ #define TxCSRH_REG_EPN_DMA_MODE_MASK 0x0400u #define TxCSRH_REG_EPN_FRC_DAT_TOG_MASK 0x0800u #define TxCSRH_REG_EPN_ENABLE_DMA_MASK 0x1000u #define TxCSRH_REG_EPN_TXRX_MODE_MASK 0x2000u #define TxCSRH_REG_EPN_ENABLE_ISO_MASK 0x4000u #define TxCSRH_REG_EPN_ENABLE_AUTOSET_MASK 0x8000u /****************************************************************************** * Endpoint TxMAXP register bit masks */ #define RX_MAX_P_REG_NUM_USB_PKT_SHIFT 11u /****************************************************************************** * Endpoint RxCSRL register bit masks */ #define RxCSRL_REG_EPN_RX_PKT_RDY_MASK 0x0001u #define RxCSRL_REG_EPN_RX_FIFO_FULL_MASK 0x0002u #define RxCSRL_REG_EPN_OVERRUN_MASK 0x0004u #define RxCSRL_REG_EPN_DATA_ERR_MASK 0x0008u #define RxCSRL_REG_EPN_FLUSH_FIFO_MASK 0x0010u #define RxCSRL_REG_EPN_SEND_STALL_MASK 0x0020u #define RxCSRL_REG_EPN_STALL_SENT_MASK 0x0040u #define RxCSRL_REG_EPN_CLR_DAT_TOG_MASK 0x0080u /****************************************************************************** * Endpoint RxCSRH register bit masks */ #define RxCSRL_REG_EPN_RX_ISO_INCOMP 0x0100u /*D1,D2 are unused*/ #define RxCSRL_REG_EPN_DMA_MODE_MASK 0x0800u #define RxCSRL_REG_EPN_ISO_PID_ERR_MASK 0x1000u #define RxCSRL_REG_EPN_BI_DIS_NYET_MASK 0x1000u #define RxCSRL_REG_EPN_ENABLE_DMA_MASK 0x2000u #define RxCSRL_REG_EPN_ENABLE_ISO_MASK 0x4000u #define RxCSRL_REG_EPN_ENABLE_AUTOCLR_MASK 0x8000u /****************************************************************************** * Endpoint DMA_CNTL register bit masks */ #define DMA_CNTL_REG_START_XFR_MASK 0x00000001u #define DMA_CNTL_REG_DMA_DIR_MASK 0x00000002u #define DMA_CNTL_REG_DMA_MODE_MASK 0x00000004u #define DMA_CNTL_REG_ENABLE_DMA_IRQ_MASK 0x00000008u #define DMA_CNTL_REG_DMA_EP_NUM_MASK 0x000000F0u #define DMA_CNTL_REG_DMA_BUS_ERR_MASK 0x00000100u #define DMA_CNTL_REG_DMA_BURST_MODE_MASK 0x00000600u #define DMA_CNTL_REG_DMA_BURST_MODE_SHIFT 9u #define DMA_CNTL_REG_DMA_EP_NUM_SHIFT 4u #define DMA_CNTL_REG_DMA_DIR_SHIFT 1u #define DMA_CNTL_REG_DMA_MODE_SHIFT 2u /****************************************************************************** * TX Endpoint Fifo size masks */ #define TXFIFOSZ_REG_DPB_SHIFT 4u /****************************************************************************** * RX Endpoint Fifo size masks */ #define RXFIFOSZ_REG_DPB_SHIFT 4u /****************************************************************************** * TX_IRQ_ENABLE register masks */ #define TX_IRQ_ENABLE_REG_CEP_MASK 0x0001u /****************************************************************************** * Host Side register definitions */ /****************************************************************************** * CSR0L bit masks */ #define CSR0L_HOST_RX_PKT_RDY_MASK 0x0001u #define CSR0L_HOST_TX_PKT_RDY_MASK 0x0002u #define CSR0L_HOST_STALL_RCVD_MASK 0x0004u #define CSR0L_HOST_SETUP_PKT_MASK 0x0008u #define CSR0L_HOST_RETRY_ERR_MASK 0x0010u #define CSR0L_HOST_IN_PKT_REQ_MASK 0x0020u #define CSR0L_HOST_STATUS_PKT_MASK 0x0040u #define CSR0L_HOST_NAK_TIMEOUT_MASK 0x0080u /****************************************************************************** * CSR0H bit masks */ #define CSR0H_HOST_FLUSH_FIFO_MASK 0x0100u/*Self Clearing*/ #define CSR0H_HOST_DATA_TOG_MASK 0x0200u #define CSR0H_HOST_DATA_TOG_WE_MASK 0x0400u/*Self Clearing*/ #define CSR0H_HOST_DISABLE_PING_MASK 0x0800u /****************************************************************************** * Type0 register bit masks */ #define TYPE0_HOST_MP_TARGET_SPEED_MASK 0xC0u #define TYPE0_HOST_MP_TARGET_SPEED_HIGH 0x40u #define TYPE0_HOST_MP_TARGET_SPEED_FULL 0x80u #define TYPE0_HOST_MP_TARGET_SPEED_LOW 0xC0u #define TYPE0_HOST_MP_TARGET_SPEED_SELF 0x00u #define TYPE0_HOST_MP_TARGET_SPEED_SHIFT 6u /****************************************************************************** * NAKLIMIT0 register bit masks */ #define NAKLIMIT0_REG_MASK 0x00u /****************************************************************************** * Endpoint TxCSRL register bit masks */ #define TxCSRL_HOST_EPN_TX_PKT_RDY_MASK 0x0001u #define TxCSRL_HOST_EPN_TX_FIFO_NE_MASK 0x0002u #define TxCSRL_HOST_EPN_RESPONSE_ERR_MASK 0x0004u #define TxCSRL_HOST_EPN_FLUSH_FIFO_MASK 0x0008u #define TxCSRL_HOST_EPN_SETUP_PKT_MASK 0x0010u #define TxCSRL_HOST_EPN_STALL_RCVD_MASK 0x0020u #define TxCSRL_HOST_EPN_CLR_DATA_TOG_MASK 0x0040u #define TxCSRL_HOST_EPN_NAK_TIMEOUT_MASK 0x0080u /****************************************************************************** * Endpoint TxCSRH register bit masks */ #define TxCSRH_HOST_EPN_DATA_TOG_MASK 0x0100u #define TxCSRH_HOST_EPN_DATA_TOG_WE_MASK 0x0200u #define TxCSRH_HOST_EPN_DMA_MODE_MASK 0x0400u #define TxCSRH_HOST_EPN_FRC_DATA_TOG_MASK 0x0800u #define TxCSRH_HOST_EPN_ENABLE_DMA_MASK 0x1000u #define TxCSRH_HOST_EPN_TXRX_MODE_MASK 0x2000u /*D6 is unused*/ #define TxCSRH_HOST_EPN_ENABLE_AUTOSET_MASK 0x8000u /****************************************************************************** * Endpoint RxCSRL register bit masks */ #define RXCSRL_HOST_EPN_RX_PKT_RDY_MASK 0x0001u #define RXCSRL_HOST_EPN_RX_FIFO_FULL_MASK 0x0002u #define RXCSRL_HOST_EPN_RESPONSE_ERR_MASK 0x0004u #define RXCSRL_HOST_EPN_NAK_TIMEOUT_ERR_MASK 0x0008u #define RXCSRL_HOST_EPN_FLUSH_FIFO_MASK 0x0010u #define RXCSRL_HOST_EPN_IN_PKT_REQ_MASK 0x0020u #define RXCSRL_HOST_EPN_STALL_RCVD_MASK 0x0040u #define RXCSRL_HOST_EPN_CLR_DATA_TOG_MASK 0x0080u /****************************************************************************** * Endpoint RxCSRH register bit masks */ #define RXCSRH_HOST_EPN_RX_ISO_INCOMP 0x0100u #define RXCSRH_HOST_EPN_DATA_TOG_MASK 0x0200u #define RXCSRH_HOST_EPN_DATA_TOG_WE_MASK 0x0400u #define RXCSRH_HOST_EPN_DMA_MODE_MASK 0x0800u #define RXCSRH_HOST_EPN_PID_ERR_MASK 0x1000u #define RXCSRH_HOST_EPN_ENABLE_DMA_MASK 0x2000u #define RXCSRH_HOST_EPN_ENABLE_AUTOREQ_MASK 0x4000u #define RXCSRH_HOST_EPN_ENABLE_AUTOCLR_MASK 0x8000u /****************************************************************************** * TXType register bit masks */ #define TXTYPE_HOST_TARGET_EP_NUM_MASK 0x0Fu #define TXTYPE_HOST_TARGET_EP_PROTOCOL_MASK 0x30u #define TXTYPE_HOST_TARGET_EP_SPEED_MASK 0xC0u #define TXTYPE_HOST_TARGET_EP_NUM_SHIFT 0u #define TXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT 4u #define TXTYPE_HOST_TARGET_EP_SPEED_SHIFT 6u /****************************************************************************** TXINTERVAL register bit masks */ #define TXINTERVAL_HOST_REG_MASK 0x00 /****************************************************************************** TXType register bit masks */ #define RXTYPE_HOST_TARGET_EP_NUM_MASK 0x0Fu #define RXTYPE_HOST_TARGET_EP_PROTOCOL_MASK 0x30u #define RXTYPE_HOST_TARGET_EP_SPEED_MASK 0xC0u #define RXTYPE_HOST_TARGET_EP_NUM_SHIFT 0u #define RXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT 4u #define RXTYPE_HOST_TARGET_EP_SPEED_SHIFT 6u /****************************************************************************** RXINTERVAL register bit masks */ #define RXINTERVAL_HOST_REG_MASK 0x00u /****************************************************************************** TX/RXFUNCTIONADDR register bit masks */ #define TARGET_DEVICE_ADDR_MASK 0x7Fu /****************************************************************************** TX/RXHUBADDR register bit masks */ #define TARGET_DEVICE_HUB_ADDR_MASK 0x7Fu #define TARGET_DEVICE_HUB_MT_MASK 0x10u #define TARGET_DEVICE_HUB_MT_SHIFT 7u /****************************************************************************** TX/RXHUBPORT register bit masks */ #define TARGET_DEVICE_HUB_PORT_MASK 0x7Fu /****************************************************************************** TESTMODE register bit masks */ #define TESTMODE_SE0NAK_MASK 0x01u #define TESTMODE_TESTJ_MASK 0x02u #define TESTMODE_TESTK_MASK 0x04u #define TESTMODE_TESTPACKET_MASK 0x08u #define TESTMODE_FORCEHS_MASK 0x10u #define TESTMODE_FORCEFS_MASK 0x20u #define TESTMODE_FIFOACCESS_MASK 0x40u/*Self Clearing*/ #define TESTMODE_FORCEHOST_MASK 0x80u typedef struct { volatile uint16_t TX_MAX_P; volatile uint16_t TX_CSR; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t RX_COUNT; volatile uint8_t TX_TYPE; volatile uint8_t TX_INTERVAL; volatile uint8_t RX_TYPE; volatile uint8_t RX_INTERVAL; volatile uint8_t RESERVED; volatile uint8_t FIFO_SIZE; } USB_endpoint_regs_t; typedef struct { volatile uint8_t TX_FUNC_ADDR; volatile uint8_t UNUSED0; volatile uint8_t TX_HUB_ADDR; volatile uint8_t TX_HUB_PORT; volatile uint8_t RX_FUNC_ADDR; volatile uint8_t UNUSED1; volatile uint8_t RX_HUB_ADDR; volatile uint8_t RX_HUB_PORT; } USB_tar_t; typedef union { struct { volatile uint32_t VALUE; } WORD; struct { volatile uint8_t VALUE; volatile uint8_t RESERVED1; volatile uint8_t RESERVED2; volatile uint8_t RESERVED3; } BYTE; struct { volatile uint16_t VALUE; volatile uint16_t RESERVED; } HALFWORD; } USB_fifo_t; typedef union { struct { volatile uint16_t TX_MAX_P; volatile uint16_t CSR0; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t COUNT0; volatile uint8_t RESERVED0; volatile uint8_t RESERVED1; volatile uint8_t RESERVED2; volatile uint8_t RESERVED3; volatile uint8_t RESERVED4; volatile uint8_t CONFIG_DATA; } DEVICE_EP0; struct { volatile uint16_t TX_MAX_P; volatile uint16_t TX_CSR; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t RX_COUNT; volatile uint8_t RESERVED0; volatile uint8_t RESERVED1; volatile uint8_t RESERVED2; volatile uint8_t RESERVED3; volatile uint8_t RESERVED4; volatile uint8_t FIFO_SIZE; } DEVICE_EPN; struct { volatile uint16_t TX_MAX_P; volatile uint16_t CSR0; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t COUNT0; volatile uint8_t TYPE0; volatile uint8_t NAK_LIMIT0; volatile uint8_t RX_TYPE; volatile uint8_t RX_INTERVAL; volatile uint8_t RESERVED0; volatile uint8_t CONFIG_DATA; } HOST_EP0; struct { volatile uint16_t TX_MAX_P; volatile uint16_t TX_CSR; volatile uint16_t RX_MAX_P; volatile uint16_t RX_CSR; volatile uint16_t RX_COUNT; volatile uint8_t TX_TYPE; volatile uint8_t TX_INTERVAL; volatile uint8_t RX_TYPE; volatile uint8_t RX_INTERVAL; volatile uint8_t RESERVED0; volatile uint8_t FIFO_SIZE; } HOST_EPN; } USB_indexed_csr_t; typedef struct { volatile uint32_t IRQ; volatile uint32_t CNTL; volatile uint32_t ADDR; volatile uint32_t COUNT; } USB_DMA_channel; typedef struct { /* * Common USB Registers */ volatile uint8_t FADDR; volatile uint8_t POWER; volatile uint16_t TX_IRQ; volatile uint16_t RX_IRQ; volatile uint16_t TX_IRQ_ENABLE; volatile uint16_t RX_IRQ_ENABLE; volatile uint8_t USB_IRQ; volatile uint8_t USB_ENABLE; volatile uint16_t FRAME; volatile uint8_t INDEX; volatile uint8_t TEST_MODE; /* * Indexed CSR */ USB_indexed_csr_t INDEXED_CSR; /* * Endpoint FIFOs */ USB_fifo_t FIFO[16]; /* * OTG, dynamic FIFO and version */ volatile uint8_t DEV_CTRL; volatile uint8_t MISC; volatile uint8_t TX_FIFO_SIZE; volatile uint8_t RX_FIFO_SIZE; volatile uint16_t TX_FIFO_ADDR; volatile uint16_t RX_FIFO_ADDR; volatile uint32_t VBUS_CSR; volatile uint16_t HW_VERSION; volatile uint16_t RESERVED; /* * ULPI and configuration registers */ volatile uint8_t ULPI_VBUS_CTRL; volatile uint8_t ULPI_CARKIT_CTRL; volatile uint8_t ULPI_IRQ_MASK; volatile uint8_t ULPI_IRQ_SRC; volatile uint8_t ULPI_DATA_REG; volatile uint8_t ULPI_ADDR_REG; volatile uint8_t ULPI_CTRL_REG; volatile uint8_t ULPI_RAW_DATA; volatile uint8_t EP_INFO; volatile uint8_t RAM_INFO; volatile uint8_t LINK_INFO; volatile uint8_t VP_LEN; volatile uint8_t HS_EOF1; volatile uint8_t FS_EOF1; volatile uint8_t LS_EOF1; volatile uint8_t SOFT_RST; /* * Target Address registers */ USB_tar_t TAR[16]; /* * Endpoints CSR */ USB_endpoint_regs_t ENDPOINT[16]; /* * DMA */ USB_DMA_channel DMA_CHANNEL[8]; volatile uint32_t RESERVED_EXT[32]; volatile uint32_t RQ_PKT_CNT[16]; volatile uint16_t RX_DPBUF_DIS; volatile uint16_t TX_DPBUF_DIS; volatile uint16_t C_T_UCH; volatile uint16_t C_T_HHSRTN; volatile uint16_t C_T_HSBT; } MSS_USB_TypeDef; #define USB ((MSS_USB_TypeDef *) USB_BASE) #define USB_BASE 0x20201000u #endif /*__MSS_USB_CORE_REGS_H_*/ mss_usb_host.c000066400000000000000000002140421432224323300376050ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBH driver * * USBH driver implementation: * This source file implements the common functionality of USB host mode * * SVN $Revision$ * SVN $Date$ */ #include "mss_assert.h" #include #include #include "mss_usb_common_cif.h" #include "mss_usb_common_reg_io.h" #include "mss_usb_host.h" #include "mss_usb_host_cif.h" #include "mss_usb_host_reg_io.h" #include "mss_usb_std_def.h" #include "mss_plic.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /***************************************************************************//** Constant values internally used by USBH driver. */ #define MSS_USB_1ms_DIVISION_VAL 1000u /*In miliSeconds*/ #define MSS_USB_TARGET_RESET_DELAY 20u /*In miliSeconds*/ #define MSS_USB_TARGET_VRISE_DELAY 20u /*In miliSeconds*/ #define MSS_USB_TARGET_SUSPEND_DELAY 20u /*In miliSeconds*/ /***************************************************************************//** Types internally used by USBH driver. */ typedef enum enum_state { ENUM_IDLE, ENUM_GET_DEF_DEV_DESC, ENUM_WAIT_GET_DEF_DEV_DESC, ENUM_RESET_TDEV, ENUM_CLR_RESET_TDEV, ENUM_SET_TDEV_ADDR, ENUM_WAIT_SET_TDEV_ADDR, ENUM_GET_FUL_DEV_DESC, ENUM_WAIT_GET_FUL_DEV_DESC, ENUM_GET_DEF_CONFG_DESC, ENUM_WAIT_GET_DEF_CONFG_DESC, ENUM_GET_FUL_CONFG_DESC, ENUM_WAIT_GET_FUL_CONFG_DESC, ENUM_CHECK_TDEV_CLASS_SUPPORT, ENUM_SUCCESS, ENUM_ERROR, ENUM_PET_SET_CONFIG, ENUM_PET_WAIT_SET_CONFIG } mss_usb_enum_state_t; typedef enum host_state { HOST_IDLE, HOST_ROOT_TARGET_DETECTED, HOST_ROOT_TARGET_RESETING, HOST_ROOT_TARGET_ENUMERATING, HOST_ROOT_TARGET_ALLOCATE_CLASSD, HOST_ROOT_TARGET_SERVICING, HOST_ROOT_TARGET_ERROR } mss_usbh_state_t; typedef enum { TDEV_R, TDEV_RHP1, TDEV_RHP2 } tdev_id_t; /***************************************************************************//** Data structures internally used by USBH driver. */ typedef struct { uint8_t alloc_state; mss_usbh_class_cb_t* class_handle; } class_driver_info_t; /* This structure type is used to read device and config descriptor from pen drive. At a time only one descriptor is operated upon.*/ typedef struct { union { uint8_t da[20]; dev_desc_t ds; }dev_desc; union { /* Def_confg + First Interface Desc+AddressAlign */ uint8_t ca[20]; def_conf_desc_t cs; }conf_desc; int8_t desc_err_code; } tdev_desc_t; /****************************************************************************** Global variable declarations for this file (USBH Driver). */ /* Flags to indicate the Callback Events */ uint8_t volatile gh_tdev_connect_event = 0u; uint8_t volatile gh_tdev_discon_event = 0u; uint8_t volatile gh_cep_cb_event = 0u; /* Track the physically connected number of target devices */ tdev_id_t tdev_idx = TDEV_R; /* * Information about the connected target devices * Index of this array is tdev_idx i.e. physical location on SF2 receptacle. */ static mss_usbh_tdev_info_t g_tdev[1]; int8_t g_tdev_error_code = 0; /* * Holds the Target device descriptor information. * Currently we support only one device. Still an array is used so that future * support for multiple devices would be easy. * MPH:Number of connected target Devices. */ static tdev_desc_t g_tdev_desc[1]; /* General purpose milliseconds count */ volatile uint32_t ms = 0; /* Track current state of the Host */ static mss_usbh_state_t g_host_state = HOST_IDLE; /* Track current state of ENUMERATION FSM */ static mss_usb_enum_state_t g_enum_state = ENUM_IDLE; /* MSS USB has 4 Transmit, 4 Receive and one control Endpoint */ mss_usb_ep_t gh_tx_ep[5]; /*[0] ==> Control EP*/ mss_usb_ep_t gh_rx_ep[5]; /*[0] ==> Empty*/ /* Use this at time of class allocation after device is enumerated * Currently we support only one device.Hence one Class allocation, still an * array is used so that future support for multiple devices would be easy.*/ /* MPH:Number of registered classes */ static class_driver_info_t g_rcd[1]; static volatile uint8_t g_cep_xfr_result = MSS_USB_EP_XFR_SUCCESS; /* User application call-back handler */ static mss_usbh_user_cb_t* g_user_cb; /* Apart from this driver, Class drivers can also do a CEP transfers as per * need. This variable is to differentiate between transfers started by this * driver and CRP transfers started by Class driver. */ static volatile uint8_t g_internal_cep_xfr = 0u; extern volatile uint8_t txep_irq; /****************************************************************************** Private function declarations for this file (USBH driver). */ static void mss_usbh_enum_fsm(void); static void mss_usbh_control_xfr_fsm(void); /* Call-back functions used by Host CIF layer to communicate with this layer */ static void mss_usbh_ep_tx_complete_cb(uint8_t ep_num, uint8_t status); static void mss_usbh_ep_rx_cb(uint8_t ep_num, uint8_t status); static void mss_usbh_cep_cb(uint8_t status); static void mss_usbh_sof_cb(uint32_t frame_number); static void mss_usbh_connect_cb(mss_usb_device_speed_t target_speed, mss_usb_vbus_level_t vbus_level); static void mss_usbh_disconnect_cb(void); static void mss_usbh_vbus_err_cb(mss_usb_vbus_level_t vbus_level); static void mss_usbh_babble_err_cb(void); static void mss_usbh_session_request_cb(void); static void mss_usbh_dma_handler_cb(mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val); static int8_t host_enum_check_class_support(tdev_id_t tid); static int8_t validate_dev_desc(dev_desc_t* p_desc); static int8_t validate_def_conf_desc(def_conf_desc_t* p_desc); static void mss_usbh_fsm(void); static void mss_usbh_reset_enum_fsm(void); static void mss_usbh_start_enum_fsm(void); static mss_usb_enum_state_t mss_usbh_get_enum_fsm_state(void); static void mss_usbh_handle_discon_event(void); /* Host call-back functions */ mss_usbh_cb_t g_mss_usbh_cb = { mss_usbh_ep_tx_complete_cb, mss_usbh_ep_rx_cb, mss_usbh_cep_cb, mss_usbh_sof_cb, mss_usbh_connect_cb, mss_usbh_disconnect_cb, mss_usbh_vbus_err_cb, mss_usbh_babble_err_cb, mss_usbh_session_request_cb, mss_usbh_dma_handler_cb }; /******************************************************************************* * EXPORTED API Functions *******************************************************************************/ /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_init ( mss_usbh_user_cb_t* app_cb ) { /* * By Default Prepare CEP for HS target. * Actual speed will be found in Enumeration FSM */ g_tdev[TDEV_R].addr = USB_DEFAULT_TARGET_ADDR; g_tdev[TDEV_R].speed = MSS_USB_DEVICE_HS; g_tdev[TDEV_R].state = MSS_USB_NOT_ATTACHED_STATE; g_tdev[TDEV_R].hub_addr = 0u; g_tdev[TDEV_R].hub_port = 0u; g_tdev[TDEV_R].hub_mtt = 0u; g_tdev[TDEV_R].tdev_maxpktsz0 = CEP_MAX_PKT_SIZE; g_tdev[TDEV_R].class_handle = 0u; g_user_cb = app_cb; /* Initialize host core interface layer */ MSS_USBH_CIF_init(); MSS_USBH_configure_control_pipe(TDEV_R); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_register_class_driver ( void* class_handle ) { volatile int8_t value = 0; g_rcd[0].alloc_state = 0u; if ((mss_usbh_class_cb_t*)0 != class_handle) { g_rcd[0].class_handle = (mss_usbh_class_cb_t*)class_handle; value = 0; } else { value = 1; } return(value); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_configure_control_pipe ( uint8_t target_addr ) { tdev_id_t tid = (tdev_id_t)0u; mss_usb_ep_t* cep_ptr = &gh_tx_ep[MSS_USB_CEP]; /* * Find the physical location of Target Device from Assigned address. * This will be used to call the correct call-back function assigned to this * address. * For multiple devices support using a HUB will be must. we intent to assign * non-zero device addresses starting with 1 (This will be HUB).This will be * done by this driver in mss_usbh_enum_fsm() function. This way array indexing * will be easier. But all this only when Multiple devices are supported. * Currently we assign 0x10 as the non-zero address for single connected device * and this will evaluate tdex_idx to 0. */ tid = (tdev_id_t)(target_addr & 0x03u); cep_ptr->tdev_idx = tid; cep_ptr->num = MSS_USB_CEP; cep_ptr->fifo_size = 64u; cep_ptr->max_pkt_size = g_tdev[tid].tdev_maxpktsz0; cep_ptr->num_usb_pkt = 1u; cep_ptr->state = MSS_USB_CEP_IDLE; /* Control Endpoint Config is fixed. NakLimit = MaxVal.*/ cep_ptr->interval = 32768u; MSS_USBH_CIF_cep_configure(cep_ptr); /* Type0:Default target speed */ MSS_USBH_CIF_cep_set_type0_reg(g_tdev[tid].speed); MSS_USBH_CIF_tx_ep_set_target_func_addr(MSS_USB_CEP,target_addr); return (0); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_configure_out_pipe ( uint8_t target_addr, uint8_t outpipe_num, uint8_t target_ep, uint16_t fifo_addr, uint16_t fifo_size, uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp, uint32_t interval ) { mss_usb_ep_t* txep_ptr = &gh_tx_ep[outpipe_num]; /* TODO: Error check for all the parameters. */ tdev_id_t tid = (tdev_id_t)0u; tid = (tdev_id_t)(target_addr & 0x03u); txep_ptr->tdev_idx = tid; txep_ptr->num = (mss_usb_ep_num_t)outpipe_num; txep_ptr->dpb_enable = DPB_DISABLE; txep_ptr->fifo_size = fifo_size; txep_ptr->fifo_addr =fifo_addr; txep_ptr->dma_enable =dma_enable; txep_ptr->dma_channel =dma_channel; txep_ptr->max_pkt_size = max_pkt_size; txep_ptr->stall = 0u; txep_ptr->state = MSS_USB_EP_VALID; txep_ptr->xfr_type = xfr_type; txep_ptr->add_zlp = add_zlp; txep_ptr->num_usb_pkt = 1u; txep_ptr->buf_addr = 0u; txep_ptr->xfr_length = 0u; txep_ptr->xfr_count = 0u; txep_ptr->txn_length = 0u; txep_ptr->txn_count = 0u; txep_ptr->disable_ping = 1u; txep_ptr->req_pkt_n = 0u; txep_ptr->interval = interval; /* Configure MP Registers with Target Device informations */ MSS_USBH_CIF_tx_ep_mp_configure(outpipe_num, target_ep, target_addr, g_tdev[tid].hub_addr, g_tdev[tid].hub_port, g_tdev[tid].hub_mtt, g_tdev[tid].speed, interval, xfr_type ); MSS_USBH_CIF_tx_ep_configure(txep_ptr); return (0); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_configure_in_pipe ( uint8_t target_addr, uint8_t inpipe_num, uint8_t target_ep, uint16_t fifo_addr, uint16_t fifo_size, uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp, uint32_t interval ) { /* TODO: Error check for all the parameters.*/ tdev_id_t tid = (tdev_id_t)0u; mss_usb_ep_t* rxep_ptr = &gh_rx_ep[inpipe_num]; tid = (tdev_id_t)(target_addr & 0x03u); rxep_ptr->tdev_idx = tid; rxep_ptr->num = (mss_usb_ep_num_t)inpipe_num; rxep_ptr->dpb_enable = DPB_DISABLE; rxep_ptr->fifo_size = fifo_size; rxep_ptr->fifo_addr = fifo_addr; rxep_ptr->dma_enable = dma_enable; rxep_ptr->dma_channel = dma_channel; rxep_ptr->max_pkt_size = max_pkt_size; rxep_ptr->stall = 0u; rxep_ptr->state = MSS_USB_EP_VALID; rxep_ptr->xfr_type = xfr_type; rxep_ptr->add_zlp = add_zlp; rxep_ptr->num_usb_pkt = 1u; rxep_ptr->buf_addr = 0u; rxep_ptr->xfr_length = 0u; rxep_ptr->xfr_count = 0u; rxep_ptr->txn_length = 0u; rxep_ptr->txn_count = 0u; rxep_ptr->disable_ping = 1u; rxep_ptr->req_pkt_n = 0u; rxep_ptr->interval = interval; /* Configure MP Registers with Target Device informations */ MSS_USBH_CIF_rx_ep_mp_configure(inpipe_num, target_ep, target_addr, g_tdev[tid].hub_addr, g_tdev[tid].hub_port, g_tdev[tid].hub_mtt, g_tdev[tid].speed, interval, xfr_type); MSS_USBH_CIF_rx_ep_configure(rxep_ptr); return (0); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_write_out_pipe ( uint8_t target_addr, uint8_t outpipe_num, uint8_t tdev_ep_num, uint16_t maxpktsz, uint8_t* buf, uint32_t length ) { mss_usb_ep_t* txep_ptr = &gh_tx_ep[outpipe_num]; /* TODO: Error check for all the parameters. */ tdev_id_t tid = (tdev_id_t)0u; ASSERT(target_addr); ASSERT(outpipe_num); ASSERT(tdev_ep_num); ASSERT(maxpktsz); ASSERT(buf); if ((target_addr != 0) && (outpipe_num != 0) && (tdev_ep_num != 0) && (maxpktsz != 0u) && (buf != NULL) ) { tid = (tdev_id_t)(target_addr & 0x03u); txep_ptr->tdev_idx = tid; txep_ptr->xfr_length = length; if (length > maxpktsz) { txep_ptr->txn_length = maxpktsz; } else { txep_ptr->txn_length = length; } txep_ptr->xfr_count = 0u; txep_ptr->txn_count = 0u; txep_ptr->buf_addr = buf; txep_ptr->state = MSS_USB_EP_VALID; MSS_USB_CIF_ep_write_pkt(txep_ptr->num, txep_ptr->buf_addr, txep_ptr->dma_enable, txep_ptr->dma_channel, txep_ptr->xfr_type, txep_ptr->xfr_length, txep_ptr->txn_length); return (0); } else { return (1); } } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_read_in_pipe ( uint8_t target_addr, uint8_t inpipe_num, uint8_t tdev_ep_num, uint16_t tdev_ep_maxpktsz, uint8_t* buf, uint32_t length ) { mss_usb_ep_t* rxep_ptr = &gh_rx_ep[inpipe_num]; /* TODO: Error check for all the parameters. */ tdev_id_t tid = (tdev_id_t)0u; ASSERT(target_addr); ASSERT(inpipe_num); ASSERT(tdev_ep_num); ASSERT(tdev_ep_maxpktsz); ASSERT(buf); if ((target_addr != 0) && (inpipe_num != 0) && (tdev_ep_num != 0) && (tdev_ep_maxpktsz != 0u) && (buf != NULL)) { tid = (tdev_id_t)(target_addr & 0x03u); rxep_ptr->tdev_idx = tid; rxep_ptr->xfr_length = length; if (length > tdev_ep_maxpktsz) { rxep_ptr->txn_length = tdev_ep_maxpktsz; } else { rxep_ptr->txn_length = length; } rxep_ptr->xfr_count = 0u; rxep_ptr->txn_count = 0u; rxep_ptr->buf_addr = buf; if ((DMA_ENABLE == rxep_ptr->dma_enable) && (MSS_USB_XFR_BULK == rxep_ptr->xfr_type)) { if (rxep_ptr->xfr_length >= rxep_ptr->max_pkt_size) { MSS_USBH_CIF_rx_ep_set_reqpkt_count(rxep_ptr->num, (rxep_ptr->xfr_length/ rxep_ptr->max_pkt_size)); } MSS_USBH_CIF_rx_ep_set_autoreq(rxep_ptr->num); } if ((rxep_ptr->max_pkt_size <= rxep_ptr->fifo_size) && (rxep_ptr->txn_length <= rxep_ptr->fifo_size)) { MSS_USB_CIF_rx_ep_read_prepare(rxep_ptr->num, rxep_ptr->buf_addr, rxep_ptr->dma_enable, rxep_ptr->dma_channel, rxep_ptr->xfr_type, rxep_ptr->xfr_length); MSS_USBH_CIF_rx_ep_set_reqpkt((mss_usb_ep_num_t)inpipe_num); } return (0); } else { return (1); } } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ mss_usb_state_t MSS_USBH_get_tdev_state ( uint8_t target_addr ) { tdev_id_t tid = (tdev_id_t)0; if (target_addr) { tid = (tdev_id_t)(target_addr & 0x03u); } ASSERT(g_tdev[tid].addr == target_addr); return (g_tdev[tid].state); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_task ( void ) { mss_usbh_control_xfr_fsm(); mss_usbh_enum_fsm(); mss_usbh_fsm(); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ uint8_t MSS_USBH_start_control_xfr ( uint8_t* cbuf_addr, uint8_t* dbuf_addr, uint8_t data_dir, uint32_t data_len /*Add tdev_addr, speed and tdevmaxpktsz as the parameter*/ ) { mss_usb_ep_t* cep_ptr = &gh_tx_ep[MSS_USB_CEP]; ASSERT(cbuf_addr != (uint8_t*)0); ASSERT(dbuf_addr != (uint8_t*)0); ASSERT(!(((ptrdiff_t)cbuf_addr) & 0x00000002U)); ASSERT(!(((ptrdiff_t)dbuf_addr) & 0x00000002U)); ASSERT((data_dir == USB_STD_REQ_DATA_DIR_IN) || (data_dir == USB_STD_REQ_DATA_DIR_OUT)); cep_ptr->buf_addr = dbuf_addr; cep_ptr->cep_cmd_addr = cbuf_addr; cep_ptr->xfr_length = data_len; /* Set the logical MaxPktSize of Host CEP to the MazPktsz of the associated * Target CEP */ /* TODO: Copy from Parameter*/ /* cep_ptr->max_pkt_size = cep_ptr->tdev_addr */ cep_ptr->cep_data_dir = data_dir; cep_ptr->xfr_count = 0u; cep_ptr->txn_count = 0u; cep_ptr->xfr_type = MSS_USB_XFR_CONTROL; g_cep_xfr_result = 0u; MSS_USBH_CIF_load_tx_fifo(MSS_USB_CEP, cbuf_addr, USB_SETUP_PKT_LEN); cep_ptr->state = MSS_USB_CEP_SETUP; MSS_USBH_CIF_cep_set_setuppktrdy(); return (0); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_construct_get_descr_command ( uint8_t* buf, uint8_t xfr_dir, uint8_t req_type, uint8_t recip_type, uint8_t request, uint8_t desc_type, uint8_t strng_idx, uint16_t length ) { /* bmRequestType */ buf[0] = (xfr_dir| req_type| recip_type); /* bRequest */ buf[1] = request; /* wValue-MSB = desc_type */ buf[3] = desc_type; if ((request == USB_STD_REQ_GET_DESCRIPTOR) && (desc_type == USB_STRING_DESCRIPTOR_TYPE)) { /* We support only one LANGID 0x0409. * Refer USB standards for list of all supported LangIDs */ buf[2] = strng_idx; /* wValue-LSB = string_idx */ buf[4] = (uint8_t)0x09u; /* wIndex-LSB = LangID for string Desc */ buf[5] = (uint8_t)0x04u; /* wIndex-MSB */ } else { /* * wValue-LSB = Conf_idx, Field should be used only for Conf_desc or * String Desc. * Since we support only one configuration, we set it to zero for * Conf_desc. For all other descriptors this field must be zero */ buf[2] = 0x00U; /* wIndex-LSB and MSB => other than String Desc, these values must be * zero */ buf[4] = 0x00U; buf[5] = 0x00U; } /* wLength-LSB and MSB, Length of data to be received */ buf[6] = (uint8_t)length; buf[7] = (uint8_t)(length >> 8u); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ mss_usb_ep_state_t MSS_USBH_get_cep_state ( void ) { return (gh_tx_ep[MSS_USB_CEP].state); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_1ms_tick ( void ) { ms++; } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ uint32_t MSS_USBH_get_milis ( void ) { return (ms); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ int8_t MSS_USBH_get_std_dev_descr ( uint8_t* buffer ) { uint8_t command_buf[USB_SETUP_PKT_LEN] = {0}; g_internal_cep_xfr = 1u; /* 0x10 is the fixed non-zero device address we are using */ MSS_USBH_configure_control_pipe(0x10u); memset(command_buf, 0u, USB_SETUP_PKT_LEN *(sizeof(uint8_t))); /* Read first 8 bytes of the Device descriptor */ MSS_USBH_construct_get_descr_command(command_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_DEVICE_DESCRIPTOR_TYPE, 0u, 8u); MSS_USBH_start_control_xfr(command_buf, buffer, USB_STD_REQ_DATA_DIR_IN, 8u); /* Wait for internal CEP transfer to complete */ while ((0u == g_cep_xfr_result) && (g_internal_cep_xfr == 1u)) { ; } if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { return 0; } else { return -1; } } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_test_mode ( uint8_t test_case ) { switch (test_case) { case USB_TEST_MODE_SELECTOR_TEST_PACKET: MSS_USB_CIF_start_testpacket(); break; case USB_TEST_MODE_SELECTOR_TEST_J: MSS_USB_CIF_start_testj(); break; case USB_TEST_MODE_SELECTOR_TEST_K: MSS_USB_CIF_start_testk(); break; case USB_TEST_MODE_SELECTOR_TEST_SE0NAK: MSS_USB_CIF_start_testse0nak(); break; case USB_TEST_MODE_SELECTOR_TEST_FORCE_ENA: MSS_USB_CIF_start_forcehost_ena(); break; default: /* Empty default */ break; } } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_suspend ( void ) { /* suspendM enabled. RemoteWakeup not supported. */ MSS_USBH_CIF_bus_suspend(0u); } /****************************************************************************** * See mss_usb_host.h for details of how to use this function. */ void MSS_USBH_resume ( void ) { static volatile uint32_t resume_milis = 0u; resume_milis = MSS_USBH_get_milis(); MSS_USBH_CIF_clr_suspend_bus(); MSS_USBH_CIF_assert_bus_resume(); /* This delay should be at lease 20ms */ while ((MSS_USBH_get_milis() - resume_milis) <= 40u) { asm volatile(" "); } MSS_USBH_CIF_clr_bus_resume(); } void MSS_USBH_abort_in_pipe ( mss_usb_ep_num_t inpipe_num ) { MSS_USBH_CIF_rx_ep_clr_reqpkt(inpipe_num); MSS_USBH_CIF_rx_ep_clr_naktimeout_err(inpipe_num); MSS_USBH_CIF_rx_ep_clr_rxstall_err(inpipe_num); MSS_USBH_CIF_rx_ep_clr_retry_err(inpipe_num); if (MSS_USBH_CIF_rx_ep_is_rxpktrdy(inpipe_num)) { MSS_USBH_CIF_rx_ep_flush_fifo_reg(inpipe_num); MSS_USB_CIF_rx_ep_clr_rxpktrdy(inpipe_num); } } void MSS_USBH_abort_out_pipe ( mss_usb_ep_num_t outpipe_num ) { gh_tx_ep[outpipe_num].state = MSS_USB_EP_ABORTED; MSS_USBH_CIF_tx_ep_clr_autoset(outpipe_num); MSS_USBH_CIF_tx_ep_flush_fifo_reg(outpipe_num); MSS_USB_CIF_tx_ep_disable_dma(outpipe_num); MSS_USBH_CIF_tx_ep_clr_retry_err(outpipe_num); MSS_USBH_CIF_tx_ep_clr_rxstall_err(outpipe_num); MSS_USBH_CIF_tx_ep_clr_naktimeout_err(outpipe_num); } /******************************************************************************* * Internal Functions *******************************************************************************/ /* * This function is the main FSM of the USB Host. It handles connect/disconnect * events, initiate enumeration FSM when device is detected and handles allocation * of class driver to the device. */ static void mss_usbh_fsm ( void ) { static uint32_t reset_milis = 0u; mss_usb_enum_state_t enum_st; if (1u == gh_tdev_discon_event) { mss_usbh_handle_discon_event(); gh_tdev_discon_event = 0u; g_host_state = HOST_IDLE; } switch (g_host_state) { case HOST_IDLE: /* * Repeatedly enable session bit so that MUSB sample Idig pin to * detect device connection */ MSS_USB_CIF_start_session(); if (gh_tdev_connect_event) { gh_tdev_connect_event = 0u; g_tdev[tdev_idx].state = MSS_USB_ATTACHED_STATE; reset_milis = MSS_USBH_get_milis(); g_host_state = HOST_ROOT_TARGET_DETECTED; } break; case HOST_ROOT_TARGET_DETECTED: /* Wait for at least 100ms for target power de-bounce as per spec */ if ((MSS_USBH_get_milis() - reset_milis) >= 100u) { MSS_USB_CIF_enable_usbirq(VBUS_ERROR_IRQ_MASK); g_tdev[TDEV_R].state = MSS_USB_POWERED_STATE; reset_milis = MSS_USBH_get_milis(); MSS_USBH_CIF_assert_bus_reset(); /*Reset Root device*/ g_host_state = HOST_ROOT_TARGET_RESETING; } break; case HOST_ROOT_TARGET_RESETING: /* Keep target device in reset, at least for 20ms as per spec */ if ((MSS_USBH_get_milis() - reset_milis) == 20u) { MSS_USBH_CIF_clr_bus_reset(); } else if ((MSS_USBH_get_milis() - reset_milis) >= 40u) { /* If target was operating at FS, check if can work with HS as well */ if ((g_tdev[TDEV_R].speed == MSS_USB_DEVICE_FS) && (MSS_USBH_CIF_is_hs_mode())) { g_tdev[TDEV_R].speed = MSS_USB_DEVICE_HS; } if (0 != g_user_cb->usbh_tdev_attached) { g_user_cb->usbh_tdev_attached(g_tdev[tdev_idx].speed); } /* Configure CEP for the detected speed */ MSS_USBH_configure_control_pipe(TDEV_R); g_tdev[TDEV_R].state = MSS_USB_DEFAULT_STATE; g_host_state = HOST_ROOT_TARGET_ENUMERATING; } break; case HOST_ROOT_TARGET_ENUMERATING: enum_st = mss_usbh_get_enum_fsm_state(); if (ENUM_IDLE == enum_st) { mss_usbh_start_enum_fsm(); } else if (ENUM_SUCCESS == enum_st) { g_tdev[TDEV_R].state = MSS_USB_ADDRESS_STATE; mss_usbh_reset_enum_fsm(); g_host_state = HOST_ROOT_TARGET_ALLOCATE_CLASSD; } else if (ENUM_ERROR == enum_st) { mss_usbh_reset_enum_fsm(); g_tdev[TDEV_R].state = MSS_USB_ATTACHED_STATE; g_host_state = HOST_ROOT_TARGET_ERROR; } else { /* EnumFSM in progress, Do nothing */ } break; case HOST_ROOT_TARGET_ALLOCATE_CLASSD: g_rcd[TDEV_R].class_handle->usbh_class_allocate(g_tdev[TDEV_R].addr); g_host_state = HOST_ROOT_TARGET_SERVICING; if (0 != g_user_cb->usbh_tdev_class_driver_assigned) { g_user_cb->usbh_tdev_class_driver_assigned(); } break; case HOST_ROOT_TARGET_SERVICING: /* Class driver FSM is active now */ break; case HOST_ROOT_TARGET_ERROR: if (0 != g_user_cb->usbh_tdev_not_supported) { g_user_cb->usbh_tdev_not_supported(g_tdev_error_code); } g_host_state = HOST_IDLE; /* * Clear Enum-FSM * Clear Target_info for all targets. * Clear EP0 config * Give Visual Err Indication and remain in this state, * till Disconnect Interrupt occurs or USER wants to give a retry * command. */ break; default: /* Empty default */ break; } } /* * This function handles the enumeration process which includes, device reset, * speed detection, and standard USB request for retrieving Device and Config * Descriptor from the device. */ static void mss_usbh_enum_fsm ( void ) { uint8_t command_buf[USB_SETUP_PKT_LEN] = {0}; static uint32_t reset_milis = 0u; int8_t cd_idx = 0x04; uint8_t dummy[8]; /* * We do not do any assert checks here. * Before Calling this FSM, Calling function should make sure that This FSM * can be executed */ switch(g_enum_state) { case ENUM_IDLE: /* Free running Enum FSM hits here when doing nothing */ break; case ENUM_GET_DEF_DEV_DESC: MSS_USBH_construct_get_descr_command(command_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_DEVICE_DESCRIPTOR_TYPE, 0u, USB_SETUP_PKT_LEN); g_enum_state = ENUM_WAIT_GET_DEF_DEV_DESC; MSS_USBH_start_control_xfr(command_buf, (uint8_t*)&g_tdev_desc[tdev_idx].dev_desc, USB_STD_REQ_DATA_DIR_IN, USB_SETUP_PKT_LEN); break; case ENUM_WAIT_GET_DEF_DEV_DESC: if (g_cep_xfr_result) { if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { g_tdev[TDEV_R].tdev_maxpktsz0 = g_tdev_desc[TDEV_R].dev_desc.ds.bMaxPacketSize0; g_enum_state = ENUM_RESET_TDEV; } else { g_enum_state = ENUM_ERROR; } } break; case ENUM_RESET_TDEV: reset_milis = MSS_USBH_get_milis(); MSS_USBH_CIF_assert_bus_reset(); g_enum_state = ENUM_CLR_RESET_TDEV; break; case ENUM_CLR_RESET_TDEV: if ((MSS_USBH_get_milis() - reset_milis) == 20u) { MSS_USBH_CIF_clr_bus_reset(); } else if ((MSS_USBH_get_milis() - reset_milis) >= 40u) { /* Wait for 20ms to let the Target settle down */ g_enum_state = ENUM_SET_TDEV_ADDR; } break; case ENUM_SET_TDEV_ADDR: /* Configure CEP Since Maxpkt0 might have changed. */ MSS_USBH_configure_control_pipe(TDEV_R); memset(command_buf, 0, USB_SETUP_PKT_LEN*(sizeof(uint8_t))); command_buf[1] = USB_STD_REQ_SET_ADDRESS; command_buf[2] = 0x10U; /*New non-zero ADDR*/ reset_milis = MSS_USBH_get_milis(); g_enum_state = ENUM_WAIT_SET_TDEV_ADDR; MSS_USBH_start_control_xfr(command_buf, command_buf, /*Dummy Buf for zld req*/ USB_STD_REQ_DATA_DIR_OUT, 0u); break; case ENUM_WAIT_SET_TDEV_ADDR: if (g_cep_xfr_result) { if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { int8_t res; /* SetAddrDelay at least 2ms */ if ((MSS_USBH_get_milis() - reset_milis) >= 5u) { g_tdev[TDEV_R].addr = 0x10U; /* New non-zero ADDR */ MSS_USBH_CIF_tx_ep_set_target_func_addr(gh_tx_ep[MSS_USB_CEP].num, g_tdev[TDEV_R].addr); /* Validate DevDescriptor. Take exception for FS LS * devices */ res = validate_dev_desc((dev_desc_t*)&g_tdev_desc[tdev_idx].dev_desc); g_tdev_desc[tdev_idx].desc_err_code = res; if (0u == res) { g_enum_state = ENUM_GET_FUL_DEV_DESC; } else { g_enum_state = ENUM_ERROR; g_tdev_error_code = res; } } } else { g_tdev[TDEV_R].addr = 0x00u; g_enum_state = ENUM_ERROR; } } break; case ENUM_GET_FUL_DEV_DESC: MSS_USBH_construct_get_descr_command(command_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_DEVICE_DESCRIPTOR_TYPE, 0u, USB_STD_DEVICE_DESCR_LEN); g_enum_state = ENUM_WAIT_GET_FUL_DEV_DESC; MSS_USBH_start_control_xfr(command_buf, (uint8_t*)&g_tdev_desc[tdev_idx].dev_desc, USB_STD_REQ_DATA_DIR_IN, USB_STD_DEVICE_DESCR_LEN); break; case ENUM_WAIT_GET_FUL_DEV_DESC: if (g_cep_xfr_result) { if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { /* Support for PET device with VID = 0x1A0A PID = PID=0x0200*/ if ((g_tdev_desc[tdev_idx].dev_desc.ds.idVendor == 0x1A0AU) && (g_tdev_desc[tdev_idx].dev_desc.ds.idProduct == 0x0200U)) { g_enum_state = ENUM_PET_SET_CONFIG; } else { int8_t res; /* Validate DevDescriptor */ res = validate_dev_desc((dev_desc_t*)&g_tdev_desc[tdev_idx].dev_desc); g_tdev_desc[tdev_idx].desc_err_code = res; if (0u == res) { g_enum_state = ENUM_GET_DEF_CONFG_DESC; } else { g_enum_state = ENUM_ERROR; g_tdev_error_code = res; } } } else { g_enum_state = ENUM_ERROR; } } break; case ENUM_GET_DEF_CONFG_DESC: memset(command_buf, 0u, USB_SETUP_PKT_LEN*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(command_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0x0U, /*stringID*/ USB_STD_CONFIG_DESCR_LEN); g_enum_state = ENUM_WAIT_GET_DEF_CONFG_DESC; MSS_USBH_start_control_xfr(command_buf, (uint8_t*)&g_tdev_desc[tdev_idx].conf_desc, USB_STD_REQ_DATA_DIR_IN, USB_STD_CONFIG_DESCR_LEN); break; case ENUM_WAIT_GET_DEF_CONFG_DESC: if (g_cep_xfr_result) { if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { int8_t res; res = validate_def_conf_desc((def_conf_desc_t*)&g_tdev_desc[tdev_idx].conf_desc); g_tdev_desc[tdev_idx].desc_err_code = res; if (0u == res) { g_enum_state = ENUM_GET_FUL_CONFG_DESC; } else { g_enum_state = ENUM_ERROR; g_tdev_error_code = res; } } else { g_enum_state = ENUM_ERROR; } } break; case ENUM_GET_FUL_CONFG_DESC: /* We already read the Standard Config desc of size 9. Now read * additional MSC class specific descriptor data. reading first * 18 bytes is sufficient for supporting MSC class */ memset(command_buf, 0u, USB_SETUP_PKT_LEN*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(command_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0u, /*stringID*/ 18u); g_enum_state = ENUM_WAIT_GET_FUL_CONFG_DESC; MSS_USBH_start_control_xfr(command_buf, (uint8_t*)&g_tdev_desc[tdev_idx].conf_desc, USB_STD_REQ_DATA_DIR_IN, 18u); break; case ENUM_WAIT_GET_FUL_CONFG_DESC: if (g_cep_xfr_result) { if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { g_enum_state = ENUM_CHECK_TDEV_CLASS_SUPPORT; } else { g_enum_state = ENUM_ERROR; } } break; case ENUM_CHECK_TDEV_CLASS_SUPPORT: cd_idx = host_enum_check_class_support(TDEV_R); if (cd_idx < (int8_t)0u) { g_enum_state = ENUM_ERROR; g_tdev_error_code = cd_idx; } /* Max No of classDriver is 3 */ else if (cd_idx < 3u) { g_rcd[cd_idx].alloc_state = 1u; g_tdev[TDEV_R].class_handle = g_rcd[cd_idx].class_handle; g_enum_state = ENUM_SUCCESS; } break; case ENUM_PET_SET_CONFIG: memset(command_buf, 0u, USB_SETUP_PKT_LEN*(sizeof(uint8_t))); command_buf[1] = USB_STD_REQ_SET_CONFIG; command_buf[2] = 0x01u; /* ConfigNum for PET Device */ g_enum_state = ENUM_PET_WAIT_SET_CONFIG; MSS_USBH_start_control_xfr(command_buf, (uint8_t*)dummy, USB_STD_REQ_DATA_DIR_IN, 0u); break; case ENUM_PET_WAIT_SET_CONFIG: if (g_cep_xfr_result) { if (MSS_USB_EP_XFR_SUCCESS == g_cep_xfr_result) { g_enum_state = ENUM_CHECK_TDEV_CLASS_SUPPORT; } else { g_enum_state = ENUM_ERROR; } } break; case ENUM_SUCCESS: break; case ENUM_ERROR: default: ASSERT(0); /* Should never happen */ break; } } /* * This function is the FSM for the control transfer. Once the control transfer * is initiated, this function will monitor it's progress in all the stages and * record the status at the end. */ static void mss_usbh_control_xfr_fsm ( void ) { volatile mss_usb_ep_state_t cep_event_st = MSS_USB_EP_VALID; uint32_t rem_length = 0u; mss_usb_ep_t* cep_ptr = &gh_tx_ep[MSS_USB_CEP]; MSS_USB_CIF_cep_disable_irq(); /* gh_cep_cb_event is critical */ cep_event_st = (mss_usb_ep_state_t)gh_cep_cb_event; gh_cep_cb_event = 0u; MSS_USB_CIF_cep_enable_irq(); MSS_USB_CIF_set_index_reg(MSS_USB_CEP); switch (cep_ptr->state) { case MSS_USB_CEP_IDLE: /* do nothing. Free running CEP-FSM hits here when doing no transfers */ break; case MSS_USB_CEP_SETUP: if (cep_event_st) { if (MSS_USB_EP_TXN_SUCCESS == cep_event_st) { if (0u == cep_ptr->xfr_length) { /* zdl-request is sent. Get the status now */ cep_ptr->state = MSS_USB_CEP_STATUS_AFTER_OUT; MSS_USBH_CIF_cep_set_statuspktrdy_after_out(); } else { rem_length = cep_ptr->xfr_length - cep_ptr->xfr_count; if (rem_length > cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = rem_length; } if (USB_STD_REQ_DATA_DIR_IN == cep_ptr->cep_data_dir) { cep_ptr->state = MSS_USB_CEP_RX; MSS_USBH_CIF_cep_set_request_in_pkt(); /* One Packet at a time */ } else if (USB_STD_REQ_DATA_DIR_OUT == cep_ptr->cep_data_dir) { MSS_USBH_CIF_cep_write_pkt(cep_ptr); cep_ptr->state = MSS_USB_CEP_TX; MSS_USBH_CIF_cep_set_txpktrdy(); } else { ASSERT(0); /* DataDir not valid */ } } } else { cep_ptr->state = cep_event_st; } } break; case MSS_USB_CEP_RX: if (MSS_USB_EP_TXN_SUCCESS == cep_event_st) { MSS_USBH_CIF_cep_read_pkt(cep_ptr); if (cep_ptr->xfr_count == cep_ptr->xfr_length) { cep_ptr->state = MSS_USB_CEP_STATUS_AFTER_IN; MSS_USBH_CIF_cep_set_statuspktrdy_after_in(); } else { rem_length = cep_ptr->xfr_length - cep_ptr->xfr_count; if (rem_length > cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = rem_length; } cep_ptr->state = MSS_USB_CEP_RX; MSS_USBH_CIF_cep_set_request_in_pkt(); /*One Packet at a time*/ } } else { cep_ptr->state = cep_event_st; ASSERT(0);/* Flush fifo, if RxpktRdy is set.MUSB:21.2.2 */ } break; case MSS_USB_CEP_TX: if (MSS_USB_EP_TXN_SUCCESS == cep_event_st) { if (cep_ptr->xfr_count == cep_ptr->xfr_length) { cep_ptr->state = MSS_USB_CEP_STATUS_AFTER_OUT; MSS_USBH_CIF_cep_set_statuspktrdy_after_out(); } else { rem_length = cep_ptr->xfr_length - cep_ptr->xfr_count; if (rem_length > cep_ptr->max_pkt_size) { cep_ptr->txn_length = cep_ptr->max_pkt_size; } else { cep_ptr->txn_length = rem_length; } MSS_USBH_CIF_cep_write_pkt(cep_ptr); } } else { cep_ptr->state = cep_event_st; ASSERT(0); /* Error response received in INTR */ } /* TODO: Check if more data needs to Transmitted */ /* Initiate IN status phase. */ break; case MSS_USB_CEP_STATUS_AFTER_IN: if (MSS_USB_EP_TXN_SUCCESS == cep_event_st) { uint8_t this_tdev = cep_ptr->tdev_idx; cep_ptr->state = MSS_USB_EP_XFR_SUCCESS; if ((NULL == g_tdev[(cep_ptr->tdev_idx)].class_handle) || (1u == g_internal_cep_xfr)) { g_cep_xfr_result = MSS_USB_EP_XFR_SUCCESS; g_internal_cep_xfr = 0u; } else { if (0 != g_tdev[this_tdev].class_handle->usbh_class_cep_xfr_done) { g_tdev[this_tdev].class_handle-> usbh_class_cep_xfr_done(g_tdev[this_tdev].addr, cep_ptr->state, cep_ptr->xfr_count); } else { ASSERT(0);/* invalid pointer */ } } cep_ptr->state = MSS_USB_CEP_IDLE; } else { cep_ptr->state = cep_event_st; ASSERT(0); } break; case MSS_USB_CEP_STATUS_AFTER_OUT: if (MSS_USB_EP_TXN_SUCCESS == cep_event_st) { uint8_t this_tdev = cep_ptr->tdev_idx; MSS_USBH_CIF_cep_clr_statusRxpktrdy(); cep_ptr->state = MSS_USB_EP_XFR_SUCCESS; if ((0 == g_tdev[(cep_ptr->tdev_idx)].class_handle) || (1u == g_internal_cep_xfr)) { g_cep_xfr_result = MSS_USB_EP_XFR_SUCCESS; } else { if (0 != g_tdev[this_tdev].class_handle->usbh_class_cep_xfr_done) { g_tdev[this_tdev].class_handle-> usbh_class_cep_xfr_done(g_tdev[this_tdev].addr, cep_ptr->state, cep_ptr->xfr_count); } else { ASSERT(0); /* invalid pointer */ } } cep_ptr->state = MSS_USB_CEP_IDLE; } else { cep_ptr->state = cep_event_st; ASSERT(0); } break; case MSS_USB_EP_NAK_TOUT: case MSS_USB_EP_NO_RESPONSE: case MSS_USB_EP_STALL_RCVD: { uint8_t this_tdev = cep_ptr->tdev_idx; if ((0 == g_tdev[(cep_ptr->tdev_idx)].class_handle) || (1u == g_internal_cep_xfr)) { g_cep_xfr_result = cep_ptr->state; g_internal_cep_xfr = 0u; } else { if (0 != g_tdev[this_tdev].class_handle->usbh_class_cep_xfr_done) { g_tdev[this_tdev].class_handle-> usbh_class_cep_xfr_done(g_tdev[this_tdev].addr, cep_ptr->state, cep_ptr->xfr_count); } else { ASSERT(0); /* invalid pointer */ } cep_ptr->state = MSS_USB_CEP_IDLE; } } break; default: { ASSERT(0); /* Invalid CEP state */ break; } } } /* * This function is used to start the enumeration FSM */ static void mss_usbh_start_enum_fsm ( void ) { g_enum_state = ENUM_GET_DEF_DEV_DESC; } /* * This function is used to bring the enum FSM to it's initial IDLE state. */ static void mss_usbh_reset_enum_fsm ( void ) { g_enum_state = ENUM_IDLE; } /* * This function is used to find the current status of the enumeration FSM. The * state information is used to know if the enumeration was successful or not. */ static mss_usb_enum_state_t mss_usbh_get_enum_fsm_state ( void ) { return (g_enum_state); } /* * This Call-back function is executed on completion of current OUT transfer. */ static void mss_usbh_ep_tx_complete_cb ( uint8_t ep_num, uint8_t status ) { uint8_t this_tdev = 0u; uint8_t transfer_complete = 0u; mss_usb_ep_t* txep_ptr = &gh_tx_ep[ep_num]; /* retrieve tdev_idx which transmitted data. */ this_tdev = gh_tx_ep[ep_num].tdev_idx; if (MSS_USB_EP_ABORTED != txep_ptr->state) { txep_ptr->txn_count = txep_ptr->txn_length; txep_ptr->xfr_count += txep_ptr->txn_length; if (0u == status) { if (DMA_ENABLE == txep_ptr->dma_enable) { txep_ptr->state = MSS_USB_EP_XFR_SUCCESS; txep_ptr->xfr_count = MSS_USB_CIF_dma_read_addr(txep_ptr->dma_channel) - ((ptrdiff_t)txep_ptr->buf_addr); ASSERT(txep_ptr->xfr_count == txep_ptr->xfr_length); transfer_complete = 1u; } else { if (MSS_USB_XFR_BULK == txep_ptr->xfr_type) { if (txep_ptr->xfr_count < txep_ptr->xfr_length) { transfer_complete = 0u; } else if (txep_ptr->xfr_count == txep_ptr->xfr_length) { if (ADD_ZLP_TO_XFR == txep_ptr->add_zlp) { if (0u == txep_ptr->txn_count) { transfer_complete = 1u; } else { if (txep_ptr->txn_count == txep_ptr->max_pkt_size) { transfer_complete = 0u; } else if (txep_ptr->txn_count < txep_ptr->max_pkt_size) { transfer_complete = 1u; } } } else /* no zlp */ { transfer_complete = 1u; } } else { /* If xfr_count is more than xfr_lenght then something * has seriously gone bad.*/ ASSERT(0); } } } } else { txep_ptr->state = (mss_usb_ep_state_t)status; transfer_complete = 1u; } if (1u == transfer_complete) { if (0 != g_tdev[this_tdev].class_handle->usbh_class_tx_done) { /* call-back class driver */ if (0u == txep_ptr->xfr_count) { ASSERT(0); } else { g_tdev[this_tdev].class_handle->usbh_class_tx_done(g_tdev[this_tdev].addr, status, txep_ptr->xfr_count); } } else { ASSERT(0); /* Invalid function pointer */ } } else { txep_ptr->txn_count = 0u;/* reset txn_count for next txn */ ASSERT(txep_ptr->xfr_length >= txep_ptr->xfr_count); if ((txep_ptr->xfr_length - txep_ptr->xfr_count) >= txep_ptr->max_pkt_size) { txep_ptr->txn_length = txep_ptr->max_pkt_size; } else { txep_ptr->txn_length = (txep_ptr->xfr_length - txep_ptr->xfr_count); } while (MSS_USB_CIF_is_txepfifo_notempty(txep_ptr->num)) { ; } if ((txep_ptr->max_pkt_size <= txep_ptr->fifo_size) && (txep_ptr->txn_length <= txep_ptr->fifo_size)) { txep_ptr->state = MSS_USB_EP_VALID; MSS_USB_CIF_ep_write_pkt(txep_ptr->num, (txep_ptr->buf_addr + txep_ptr->xfr_count), txep_ptr->dma_enable, txep_ptr->dma_channel, txep_ptr->xfr_type, txep_ptr->xfr_length, txep_ptr->txn_length); } else { ASSERT(0); } } } else { /* The Transmit endpoint generates an endpoint interrupt when previously * initiated TX transfer is aborted.Class driver doesn't need to know this. * Also this driver doesn't need to do anything in this case.*/ } } /* * This Call-back function is executed on completion of current IN transfer. */ static void mss_usbh_ep_rx_cb ( uint8_t ep_num, uint8_t status ) { uint8_t this_tdev = 0u; uint8_t transfer_complete = 0u; uint32_t received_count = 0u; mss_usb_ep_t* rxep_ptr = &gh_rx_ep[ep_num]; /* Retrieve tdev_idx which received data. */ this_tdev = gh_rx_ep[ep_num].tdev_idx; if (status & (RX_EP_OVER_RUN_ERROR | RX_EP_STALL_ERROR | RX_EP_DATA_ERROR | RX_EP_PID_ERROR | RX_EP_ISO_INCOMP_ERROR)) { transfer_complete = 1u; } else { if (MSS_USB_CIF_rx_ep_is_rxpktrdy((mss_usb_ep_num_t)ep_num)) { received_count = (uint32_t)MSS_USB_CIF_rx_ep_read_count((mss_usb_ep_num_t)ep_num); if (DMA_ENABLE == rxep_ptr->dma_enable) { if (MSS_USB_DMA_MODE1 == (MSS_USB_CIF_rx_ep_get_dma_mode((mss_usb_ep_num_t)ep_num))) { uint32_t increamented_addr; /* * This means we are in BULK transfer with DMA mode1. * all the rxmaxP size pkts are received and last short pkt * need to be read without DMA or by switching to mode 0. * After switching mode to 0, this ISR handler is invoked * again. Data packet will be read then. */ /* Read 'short packet' without DMA */ MSS_USB_CIF_dma_stop_xfr(rxep_ptr->dma_channel); MSS_USB_CIF_rx_ep_clr_autoclr((mss_usb_ep_num_t)ep_num); increamented_addr = MSS_USB_CIF_dma_read_addr(rxep_ptr->dma_channel); /* Count number of bytes read so far,since DMA was operating * in m1 with Autoclr.*/ rxep_ptr->xfr_count = (increamented_addr - ((ptrdiff_t)(rxep_ptr->buf_addr))); if (received_count) { MSS_USB_CIF_read_rx_fifo((mss_usb_ep_num_t)ep_num, (rxep_ptr->buf_addr+rxep_ptr->xfr_count), received_count); rxep_ptr->xfr_count += received_count; MSS_USB_CIF_rx_ep_clr_rxpktrdy((mss_usb_ep_num_t)ep_num); } transfer_complete = 1u; } else { MSS_USB_CIF_dma_write_count(rxep_ptr->dma_channel, received_count); MSS_USB_CIF_dma_start_xfr(rxep_ptr->dma_channel); transfer_complete = 2u; /*Upper layer cb will be called from DMA ISR*/ } } else /* dma disable */ { if (received_count) { MSS_USB_CIF_read_rx_fifo((mss_usb_ep_num_t)ep_num, (rxep_ptr->buf_addr+rxep_ptr->xfr_count), received_count); rxep_ptr->txn_count = received_count; rxep_ptr->xfr_count += received_count; MSS_USB_CIF_rx_ep_clr_rxpktrdy((mss_usb_ep_num_t)ep_num); } if (rxep_ptr->xfr_count == rxep_ptr->xfr_length) { transfer_complete = 1u; } else if (rxep_ptr->xfr_count < rxep_ptr->xfr_length) { /* Reset txn_count for next txn */ rxep_ptr->txn_count = 0u; if ((rxep_ptr->xfr_length - rxep_ptr->xfr_count) > rxep_ptr->max_pkt_size) { rxep_ptr->txn_length = rxep_ptr->max_pkt_size; } else { rxep_ptr->txn_length = (rxep_ptr->xfr_length - rxep_ptr->xfr_count); } MSS_USBH_CIF_rx_ep_set_reqpkt((mss_usb_ep_num_t)ep_num); } else { ASSERT(0); } } } } if (1u == transfer_complete) { rxep_ptr->state = (mss_usb_ep_state_t)status; if (0 != g_tdev[this_tdev].class_handle->usbh_class_rx_done) { /* call-back class driver */ /* count = 0 since there was error */ g_tdev[this_tdev].class_handle->usbh_class_rx_done(g_tdev[this_tdev].addr, status, rxep_ptr->xfr_count); } else { ASSERT(0); /* Invalid pointer */ } } } /* * This Call-back function is executed on completion of current CONTROL transfer. */ static void mss_usbh_cep_cb ( uint8_t status ) { gh_cep_cb_event = status; } /* * This Call-back function is executed on receiving SOF interrupt in HOST mode */ static void mss_usbh_sof_cb ( uint32_t frame_number ) { } /* * This Call-back function is executed on detecting the device attach event */ static void mss_usbh_connect_cb ( mss_usb_device_speed_t target_speed, mss_usb_vbus_level_t vbus_level ) { g_tdev[TDEV_R].speed = target_speed; gh_tdev_connect_event = 1u; } /* * This Call-back function is executed on detecting the device detach event */ static void mss_usbh_disconnect_cb ( void ) { gh_tdev_discon_event = 1u; } /* * This Call-back function is executed on detecting a Vbus level error event */ static void mss_usbh_vbus_err_cb ( mss_usb_vbus_level_t vbus_level ) { } /* * This Call-back function is executed on detecting the babble error event */ static void mss_usbh_babble_err_cb ( void ) { /* Not supported yet */ } /* * This Call-back function is executed on detecting the session request event * when the attached device is also a OTG device. */ static void mss_usbh_session_request_cb ( void ) { /* Not supported yet */ } static void mss_usbh_dma_handler_cb ( mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val ) { mss_usb_ep_t* ep_ptr = 0; uint8_t this_tdev = 0u; if (DMA_XFR_ERROR == status) { ASSERT(0); } else { if (MSS_USB_DMA_READ == dma_dir) /*TX EP*/ { ep_ptr = &gh_tx_ep[ep_num]; /* Retrieve tdev_idx which received data.*/ this_tdev = gh_tx_ep[ep_num].tdev_idx; /* EP interrupt won't happen when short packet is not received */ if ((NO_ZLP_TO_XFR == ep_ptr->add_zlp) && (ep_ptr->xfr_length) && (!(ep_ptr->xfr_length % ep_ptr->max_pkt_size))) { /* Wait till last TxMaxPkt size packet is sent.*/ while (MSS_USB_CIF_tx_ep_is_txpktrdy(ep_num)) { ; } ep_ptr->xfr_count = dma_addr_val - (ptrdiff_t)ep_ptr->buf_addr; ep_ptr->state = MSS_USB_EP_XFR_SUCCESS; if (0 != g_tdev[this_tdev].class_handle->usbh_class_tx_done) { /* Call-back class driver */ g_tdev[this_tdev].class_handle->usbh_class_tx_done(g_tdev[this_tdev].addr, status, ep_ptr->xfr_count); } } else { MSS_USB_CIF_tx_ep_set_txpktrdy(ep_num); } } /* RX EP */ else if (MSS_USB_DMA_WRITE == dma_dir) { ep_ptr = &gh_rx_ep[ep_num]; /* Retrieve tdev_idx which transmitted data.*/ this_tdev = gh_rx_ep[ep_num].tdev_idx; if ((NO_ZLP_TO_XFR == ep_ptr->add_zlp) && (ep_ptr->xfr_length) && (!(ep_ptr->xfr_length % ep_ptr->max_pkt_size))) { MSS_USB_CIF_dma_stop_xfr(ep_ptr->dma_channel); MSS_USBH_CIF_rx_ep_clr_reqpkt((mss_usb_ep_num_t)ep_num); MSS_USB_CIF_rx_ep_clr_autoclr((mss_usb_ep_num_t)ep_num); ep_ptr->xfr_count = dma_addr_val - (ptrdiff_t)ep_ptr->buf_addr; ep_ptr->state = MSS_USB_EP_XFR_SUCCESS; if (MSS_USB_DMA_MODE0 == (MSS_USB_CIF_rx_ep_get_dma_mode(ep_num))) { MSS_USB_CIF_rx_ep_clr_rxpktrdy(ep_num); } if (0 != g_tdev[this_tdev].class_handle->usbh_class_rx_done) { /* Call-back class driver */ g_tdev[this_tdev].class_handle-> usbh_class_rx_done(g_tdev[this_tdev].addr, status, ep_ptr->xfr_count); } } } } } /* * This function checks errors in the received device descriptor. */ static int8_t validate_dev_desc ( dev_desc_t* p_desc ) { int8_t result = 0; if (p_desc->bLength != USB_STD_DEVICE_DESCR_LEN) { result = DEV_DESC_WRONG_LENGTH; } if (p_desc->bDescriptorType != USB_DEVICE_DESCRIPTOR_TYPE) { result = DEV_DESC_WRONG_DESC_TYPE; } if (!((p_desc->bcdUSB != USB_BCD_VERSION_2_0) || (p_desc->bcdUSB != USB_BCD_VERSION_2_1) || (p_desc->bcdUSB != USB_BCD_VERSION_1_1) || (p_desc->bcdUSB != USB_BCD_VERSION_1_0))) { result = DEV_DESC_WRONG_USBBCD; } if (!((p_desc->bMaxPacketSize0 != 8u) || (p_desc->bMaxPacketSize0 != 16u) || (p_desc->bMaxPacketSize0 != 32u) || (p_desc->bMaxPacketSize0 != 64u))) { result = DEV_DESC_WRONG_MAXPKTSZ0; } if ((MSS_USB_DEVICE_HS == g_tdev[TDEV_R].speed)) { if ((p_desc->bcdUSB != USB_BCD_VERSION_2_0) && (p_desc->bcdUSB != USB_BCD_VERSION_2_1)) { result = DEV_DESC_HS_USBBCD_NOT200; } if (p_desc->bMaxPacketSize0 != 64u) { result = DEV_DESC_HS_MAXPKTSZ0_NOT64; } } if ((MSS_USB_DEVICE_LS == g_tdev[TDEV_R].speed)) { if (p_desc->bMaxPacketSize0 != 8u) { result = DEV_DESC_LS_MAXPKTSZ0_NOT8; } } if ((MSS_USB_DEVICE_FS == g_tdev[TDEV_R].speed)) { result = FS_DEV_NOT_SUPPORTED; } /* Need to comment the below section for keyboard and mouse are low speed * device */ #if 0 if ((MSS_USB_DEVICE_LS == g_tdev[TDEV_R].speed)) { result = LS_DEV_NOT_SUPPORTED; } #endif /*0 return value indicates success*/ return (result); } /* * This function checks errors in the received configuration descriptor (9bytes) */ static int8_t validate_def_conf_desc ( def_conf_desc_t* p_desc ) { int8_t result = 0u; if (p_desc->bLength != USB_STD_CONFIG_DESCR_LEN) { result = CONF_DESC_WRONG_LENGTH; } if (p_desc->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) { result = CONF_DESC_WRONG_DESC_TYPE; } if (p_desc->bMaxPower > USB_MAX_BUS_POWER) { result = CONF_DESC_POWER_LIM_EXCEED; } /*0 return value indicates success*/ return (result); } /* * This function executes the sequence of actions when device is disconnected. */ static void mss_usbh_handle_discon_event ( void ) { gh_tdev_discon_event = 0u; tdev_idx = TDEV_R; if (0 != g_user_cb->usbh_tdev_dettached) { g_user_cb->usbh_tdev_dettached(); } if (1u == g_rcd[TDEV_R].alloc_state) { g_rcd[TDEV_R].class_handle->usbh_class_release(g_tdev[TDEV_R].addr); } g_tdev[TDEV_R].addr = USB_DEFAULT_TARGET_ADDR; g_tdev[TDEV_R].speed = MSS_USB_DEVICE_HS; g_tdev[TDEV_R].state = MSS_USB_NOT_ATTACHED_STATE; g_tdev[TDEV_R].hub_addr = 0u; g_tdev[TDEV_R].hub_port = 0u; g_tdev[TDEV_R].hub_mtt = 0u; g_tdev[TDEV_R].tdev_maxpktsz0 = CEP_MAX_PKT_SIZE; g_tdev[TDEV_R].class_handle = 0u; g_tdev_error_code = 0; memset(&g_tdev_desc[TDEV_R], 0u, sizeof(tdev_desc_t)); /* Un-register Class driver */ g_rcd[TDEV_R].alloc_state = 0u; mss_usbh_reset_enum_fsm(); MSS_USB_CIF_enable_usbirq(CONNECT_IRQ_MASK | DISCONNECT_IRQ_MASK); MSS_USBH_configure_control_pipe(USB_DEFAULT_TARGET_ADDR); MSS_USBH_CIF_tx_ep_set_target_func_addr(MSS_USB_CEP,0u); MSS_USBH_CIF_cep_set_type0_reg((mss_usb_device_speed_t)0u); } static int8_t host_enum_check_class_support ( tdev_id_t tid ) { uint8_t i = 0u; /* Max number of registered Class drivers supported is 1 */ for (i = 0u;i < 1u;i++) { /* Value 9 in interface descriptor's bInterfaceClass field indicates * HUB Class device */ if (0x09u == g_tdev_desc[tid].conf_desc.cs.upended_desc[5]) { return (HUB_CLASS_NOT_SUPPORTED); } /* Comparing assigned class driver with the interface descriptor's * bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol * fields*/ if (((uint8_t)(g_rcd[i].class_handle->class_id>>16u) == g_tdev_desc[tid].conf_desc.cs.upended_desc[5]) && ((uint8_t)(g_rcd[i].class_handle->class_id>>8u) == g_tdev_desc[tid].conf_desc.cs.upended_desc[6]) && ((uint8_t)(g_rcd[i].class_handle->class_id) == g_tdev_desc[tid].conf_desc.cs.upended_desc[7])) { /* Class driver is matched and available. */ if (g_rcd[i].alloc_state == 0u) { /* Allocation successful */ return (i); } else { /* Match found but Driver is already assigned */ return (CLASS_DRIVER_NOT_FREE); } } } /* No matching class driver found. */ return (CLASS_DRIVER_NOT_MATCHED); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif mss_usb_host.h000066400000000000000000002263241432224323300376200ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Microchip PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBH driver * * USBH driver public API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS USB Host driver (USBH) ============================================================================== Introduction ============================================================================== The USB Host Driver (USBH) is part of the USB-LL layer of the MSS USB driver stack. The USBH driver implements the core functionality of the USB host mode operations. The USBH driver is responsible for the following functionalities. - Device attach and detach handling - Enumeration and USB Standard requests - Device Suspend, Resume and Reset handling - USB transfers management - USBH-Class call-back interface - Application call-back interface ============================================================================== Theory of Operation ============================================================================== The following steps are involved in the operation of the USBH driver: - Configuration - Initialization - USBH-Class Interface - Application Interface - Data transfer The USBH driver operation depends on user configuration provided in mss_usb_config.h. -------------------------------- Configuration -------------------------------- The following parameter must be defined in the mss_usb_config.h file to operate the MSS USB hardware block in USB Host mode. MSS_USB_HOST_MODE Configures the MSS USB Driver Stack to operate in USB host mode. -------------------------------- Initialization -------------------------------- The USBH driver must be initialized by calling the MSS_USBH_init() initialization function with a parameter to provide the application call-back interface. Once initialized the USBH driver is ready to detect the attach event on the USB port. The application call-back interface is used to provide information about the events on the USB bus to the application. The MSS_USBH_task() is the main task of the USBH driver which implements the state machines for monitoring the USB bus activities. This function must be called repeatedly by the application to allow USBH driver to run it's state machines. A timer/scheduler can be used to call this function at regular intervals or it can be called from the main continuous foreground loop of the application. The function MSS_USBH_1ms_tick() must be called to provide a 1milisecond time tick to the USBH driver. This time tick is used by the USBH driver to track the enumeration process and other housekeeping purposes. The MSS_USBH_get_milis() function is provided to get the number of milliseconds lapsed from the system reset. The MSS_USBH_test_mode() function is provided to force the MSS USB in test modes as required by the USB compliance test specification. This function has no use in normal operations with a attached USB device. -------------------------------- USBH-Class Call-back Interface -------------------------------- This driver encapsulates the generic USB protocol functionality from the USB class functionality. This driver needs the USBH-Class driver to implement a set of call-back functions to pass on the control to the USBH-Class driver for handling the USB class specific functionality. This driver provides a data type mss_usbh_class_cb_t which must be implemented by the USBH-Class driver. This data type is the collection of call-back functions which must be implemented by the USBH-Class driver. Implementing all the elements of this structure may not be necessary for a specific USB class. The USBH-Class driver must define a structure of type mss_usbh_class_cb_t and implement its required elements. The function MSS_USBH_register_class_driver() must be used to inform the USBH driver about this call-back interface and the supported USB Class information The table below lists the prototypes of the call-back functions which are part of the mss_usbh_class_cb_t type and the event in which they are called. | Call-back Element | Event | |------------------------|---------------------------------------------------| | usbh_class_allocate | Called when a match is found between the class | | | sub-class code and protocol code of the attached | | | device and the corresponding parameters provided | | | by the USBH-Class driver in the class_id parameter| | usbh_class_release | Called when the device for which this USBH-Class | | | driver is assigned is detached | | usbh_class_cep_xfr_done| Called when a transfer started by this USBH-Class | | | driver is complete | | usbh_class_tx_done | Called when a transfer started on the OUT pipe by | | | this USBH-Class driver is complete | | usbh_class_rx_done | Called when a transfer started on the IN pipe by | | | this USBH-Class driver is complete | | usbh_class_sof | The function pointed by the usbh_class_sof element| | | will be called when a new (micro) frame starts | -------------------------------- Application Call-back Interface -------------------------------- The USBH driver uses interrupts to respond to the events on MSS USB. The USBH driver handles the enumeration of the attached device internally. The enumeration process can take long time (hundreds of milliseconds) to complete. The USBH driver uses application call-back interface to inform the application about the events on the USB bus as they happen. The application may implement these call-back functions to take application specific action on each event or to provide error/status messages to the user. The table below lists the prototypes of the call-back functions which are part of the mss_usbh_user_cb_t type and the event in which they are called. | Element | Call-back Event | |---------------------------------|------------------------------------------| | usbh_tdev_attached | Called when a device-attach event is | | | detected by the USBH driver. At this | | | point the device is not enumerated. | | usbh_tdev_dettached | Called when a device-detach event is | | | detected by the USBH driver | | usbh_tdev_oc_error | Called when an over-current condition is | | | detected by the USBH driver | | usbh_tdev_enumerated | Called when the attached device is | | | successfully enumerated | | usbh_tdev_class_driver_assigned | Called when a matching class driver is | | | assigned to the attached device | | usbh_tdev_not_supported | Called when a device which is not | | | supported by the USBH driver is detected | | usbh_tdev_permanent_error | Called if there was error during data | | | transfer operations with the attached | | | device | -------------------------------- Data transfer -------------------------------- The USB host uses pipe, a representation of logical connection from endpoint on MSS USB to the endpoint on the target device. The transmit pipe or the receive pipe must first be configured before starting the data transfer on it. The functions MSS_USBH_configure_in_pipe() and MSS_USBH_configure_out_pipe() must be used to configure an IN(data moving from device to host) and an OUT(data moving from host to device) pipe respectively. The application must use MSS_USBH_write_out_pipe() function to start data transmission on a OUT pipe. This function prepares the MSS USB to transmit data to the device. However, actual transmission happens depending on the transfer type and the selected interval. This function is non-blocking. The USBH-Class driver will be informed about data transmission completion or transmission errors by a call to its call-back function. Please refer USBH-Class Interface section above for more details. To receive data from attached USB device, application must use MSS_USBH_read_in_pipe() function. This function prepares the MSS USB to receive data from the attached device. However, actual data transfer happens depending on the transfer type and the selected interval. This function is non-blocking. On receiving data or in case of errors during this operation the USBH-Class driver will be informed about it by calling a call-back function. Please refer the USBH-Class Interface section above for more details. This driver supports multi-packet Bulk transfer (both IN and OUT), to make sure that it is able to use the full bandwidth offered by USB Bulk transfers. When a transfer size of more than wMaxPktSize is provided to this driver using MSS_USBH_write_out_pipe() function or MSS_USBH_read_in_pipe() function, this driver handles this multi-packet transfer internally by dividing it into multiple Bulk transfers of wMaxPktSize each. This way no application intervention is required till the total multi-packet Bulk transfer is complete. The USBH driver supports Bulk transfers using the DMA inside MSS USB or without using the internal DMA. It is advised that the USBH driver is configured to use the internal DMA in order to free up the application from transferring data to/from MSS USB hardware block. However, the internal DMA can access only aligned address. Care must be taken that the buffer address provided to the USBH driver must be modulo-4. This is not a requirement when the MSS USB driver is configured not to use internal DMA. All the control transfers happen on the control pipe. The control pipe is shared by the USBH driver and the USBH-Class driver. When the USBH-Class driver needs to perform control transfer on the attached device, it must first configure the control pipe using the MSS_USBH_configure_control_pipe() function. The MSS_USBH_start_control_xfr() function can be used to start the control transfer After the control pope is configured. The data direction is determined by a parameter provided with this function. The USBH-Class driver will be informed about the data transfer completion or the error status by calling a call-back function. Please refer the USBH-Class Interface section above for more details. The control transfer can be started by a USBH-Class driver only when the control pipe is free.The MSS_USBH_get_cep_state() function can be used to know the current state of the control pipe. At the start of the control transfer the USBH driver must send a setup-packet to the attached device in the setup phase. The function MSS_USBH_construct_get_descr_command() can be used to construct the setup packet as per the USB specification for the transfer to be performed. This function formats the setup packet depending on the parameters provided with this function. The application may choose to keep the MSS USB in suspend state to conserve power to the USB device, and the MSS USB, In this state the MSS USB does not send any frames on the bus and there will be no bus activity. This will also ensure that the attached device enters suspend state as specified in the USB2.0 specification. The USBH driver provides the MSS_USBH_suspend() function to suspend the MSS USB. The MSS_USBH_resume() function must be used to resume the normal operations. The table below provides the list of all the functions provided by USBH driver. | function | Description | |------------------------------|---------------------------------------------| | MSS_USBH_init() | Initialize the MSS USB to operate in the | | | host mode | | | | | MSS_USBH_task() | Main task of the USBH driver where the state| | | machines are implemented | | | | | MSS_USBH_register_class_ | Used to register the class driver handle | | driver() | with the USBH driver | | | | | MSS_USBH_configure_control_ | Configures the control pipe for control | | pipe() | transfers with the attached device | | | | | MSS_USBH_configure_in_pipe() | Configures the IN pipe for the USB IN | | | transfers with the attached device | | | | | MSS_USBH_configure_out_pipe()| Configures the OUT pipe for the USB OUT | | | transfers with the attached device | | | | | MSS_USBH_write_out_pipe() | Writes data on to the attached device using | | | the OUT pipe | | | | | MSS_USBH_read_in_pipe() | Reads data from the attached device using | | | the IN pipe | | | | | MSS_USBH_get_tdev_state() | Used to find out the current state of the | | | attached device | | | | | MSS_USBH_suspend() | Suspends the MSS USB core. No frames are | | | transferred | | | | | MSS_USBH_resume() | Resumes the previously suspended MSS USB | | | | | MSS_USBH_get_std_dev_descr() | Reads the device descriptor from the | | | attached device | | | | | MSS_USBH_1ms_tick() | Time stamping and housekeeping function | | | | | MSS_USBH_get_milis() | Used to know the number of milliseconds | | | lapsed after reset | | | | | MSS_USBH_construct_get_descr | Formats the provided parameters into a USB | | _command() | standard setup packet for GET_DESCRIPTOR | | | command | | | | | MSS_USBH_start_control_xfr() | Starts a control transfer on previously | | | configured control pipe | | | | | MSS_USBH_get_cep_state() | Provides the current state of the control | | | pipe | | | | | MSS_USBH_test_mode() | Initiates compliance test mode as specified | | | by the parameter. | *//*=========================================================================*/ #ifndef __MSS_USB_HOST_H_ #define __MSS_USB_HOST_H_ #include "mss_usb_common_cif.h" #include "mss_usb_common_reg_io.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /*-------------------------------------------------------------------------*//** Constant values exported by USBH driver */ /*-------------------------------------------------------------------------*//** The following constants are used to identify the exact reason due to which the USBH driver is not supporting the attached device. One of these values is passed as a parameter to the call-back function usbh_tdev_not_supported when USBH driver detects respective condition. */ /* Devices operating at the USB full speed are not supported. */ #define FS_DEV_NOT_SUPPORTED -15 /* Devices operating at the USB low speed are not supported. */ #define LS_DEV_NOT_SUPPORTED -14 /* Device belonging to the USB HUB class is detected. The Hub class is not supported by the USBH driver. */ #define HUB_CLASS_NOT_SUPPORTED -13 /* Attached device class description does not match the class description supported by the registered class driver. */ #define CLASS_DRIVER_NOT_MATCHED -12 /* The registered class driver is already in assigned state when new device attachment is detected. */ #define CLASS_DRIVER_NOT_FREE -11 /* The power requirement for the attached device, as described in the bMaxPower field of configuration descriptor, can not be supported by the USBH driver. */ #define CONF_DESC_POWER_LIM_EXCEED -10 /* The value received in bDescriptorType field in configuration descriptor is invalid. */ #define CONF_DESC_WRONG_DESC_TYPE -9 /* The value received in bLength field of the configuration descriptor does not match the standard value (9) as specified in the USB2.0 specification. */ #define CONF_DESC_WRONG_LENGTH -8 /* The value received in bMaxPacketSize0 field of the device descriptor is not 8 for a LS device. */ #define DEV_DESC_LS_MAXPKTSZ0_NOT8 -7 /* The value received in bMaxPacketSize0 field of the device descriptor is not 64 for a HS device. */ #define DEV_DESC_HS_MAXPKTSZ0_NOT64 -6 /* The value received in bcdDevice field of the device descriptor for a HS device does not indicate USB2.0 */ #define DEV_DESC_HS_USBBCD_NOT200 -5 /* The value received in the bMaxPacketSize0 field of the device descriptor is invalid. For LS device this value must be 8. For HS device this value must be 64. For FS device this value must be 8, 16, 32, or 64. */ #define DEV_DESC_WRONG_MAXPKTSZ0 -4 /* The value received in the bcdDevice field of the device descriptor is invalid. For HS device this value must indicate USB2.0. */ #define DEV_DESC_WRONG_USBBCD -3 /* The value received in the bDescriptorType field in device descriptor is invalid. */ #define DEV_DESC_WRONG_DESC_TYPE -2 /* The value received in the bLength field of the device descriptor does not match the standard value (18). */ #define DEV_DESC_WRONG_LENGTH -1 /* The following constants are used as the return values for the call-back functions, implemented by the USBH-Class driver as part of mss_usbh_class_cb_t type, which are called by the USBH driver. The USBH driver uses these values to infer whether or not the call-back function was successfully executed. The current control transfer is stalled if the return value is USB_FAIL. */ #define USB_FAIL 0u #define USB_SUCCESS 1u /*-------------------------------------------------------------------------*//** Data structures exported by USBH driver */ /*-------------------------------------------------------------------------*//** The mss_usbh_class_cb_t provides the prototype of the structure that must be implemented by the USBH-Class driver to provide the call-back functions which will be called by the USBH driver to communicate events on the target device. class_id The class_id parameter is the place-holder for identifying the USBH-Class driver which is implementing this call-back interface. This parameter is used by the USBH driver to identify and assign the class driver to the attached device.The MSS_USBH_register_class_driver() function must be used to register a class driver with the the USBH driver. This parameter must be of the form: | Class id bit | Description | |-------------- |------------------------------------------------------------| | D7 - D0 | USB Std Protocol code | | D15 - D8 | USB Std sub-class code | | D23 - D16 | USB Std class code | | D31 - D24 | 0x00 | usbh_class_allocate The function pointed by the usbh_class_allocate element will be called when a match is found between the class code, sub-class code and protocol code of the attached device and the corresponding parameters provided by the USBH-Class driver in class_id parameter. The tdev_addr parameter provides the non-zero device address assigned to the attached device by the USBH driver. usbh_class_release The function pointed by the usbh_class_release element will be called when the device for which this USBH-Class driver is assigned is detached. The tdev_addr parameter provides the non-zero device address assigned to the attached device by the USBH driver. usbh_class_cep_xfr_done The function pointed by the usbh_class_cep_xfr_done element will be called when a control transfer started by this USBH-Class driver is complete. The tdev_addr parameter provides the non-zero device address assigned to the attached device by the USBH driver. The status parameter indicates whether or not the current control transfer was completed successfully. The count parameter provides the number of bytes transferred in the current control transfer. The status parameter provides the error status of current control transfer. A non-zero value indicates that there was an error. usbh_class_tx_done The function pointed by the usbh_class_tx_done element will be called when a transfer started on OUT pipe by this USBH-Class driver is complete. The tdev_addr parameter provides the non-zero device address assigned to the attached device by USBH driver. The status parameter indicates whether or not the current transfer was completed successfully. The count parameter provides the number of bytes transferred in the current control transfer. The status parameter provides the error status of the current control transfer. A non-zero value indicates that there was an error. usbh_class_rx_done The function pointed by the usbh_class_rx_done element will be called when a transfer started on the IN pipe by this USBH-Class driver is complete. The tdev_addr parameter provides the non-zero device address assigned to the attached device by the USBH driver. The status parameter indicates whether or not the current transfer was completed successfully. The count parameter provides the number of bytes transferred in the current control transfer. The status parameter provides the error status of current control transfer. A non-zero value indicates that there was an error. usbh_class_sof The function pointed by the usbh_class_sof element will be called when a new micro frame starts. The frame_number provides the number of the current micro frame. */ typedef struct mss_usbh_class_cb { uint32_t class_id; uint8_t (*usbh_class_allocate)(uint8_t tdev_addr); uint8_t (*usbh_class_release)(uint8_t tdev_addr); uint8_t (*usbh_class_cep_xfr_done)(uint8_t tdev_addr, uint8_t status, uint32_t count); uint8_t (*usbh_class_tx_done)(uint8_t tdev_addr, uint8_t status, uint32_t count); uint8_t (*usbh_class_rx_done)(uint8_t tdev_addr, uint8_t status, uint32_t count); uint8_t (*usbh_class_sof)(uint32_t frame_number); }mss_usbh_class_cb_t; /*-------------------------------------------------------------------------*//** The mss_usbh_tdev_info_t type provides the prototype for the detailed information of the attached device. Some of the parameters are only applicable when multi-point support is enabled on MSS USB. Multi-point support is currently not enabled in the USBH driver. addr The addr parameter provides the device address assigned to the attached device by the USBH driver. speed The speed parameter indicates the USB speed of operation at which the USBH driver is communicating with the attached device. state The state parameter provides the current state of the attached device. E.g. address, Configured etc. hub_addr The hub_addr parameter provides the address of the hub to which the device is attached. This parameter is meaningful only when Multi-Point support is enabled. Multi-point support is currently not enabled in the USBH driver. hub_port The hub_port parameter provides the port number of the hub to which the device is attached. This parameter is meaningful only when Multi-Point support is enabled. Multi-point support is currently not enabled in the USBH driver. hub_mtt The hub_mtt parameter indicates whether or not the hub to which the device is attached supports multiple transaction translators. This parameter is meaningful only when Multi-Point support is enabled. Multi-point support is currently not enabled in the USBH driver. maxpktsz0 The maxpktsz0 parameter provides the maximum packet size of the control endpoint on the attached device. state The state parameter provides the current state of the attached device. E.g. address, Configured etc. class_handle The class_handle parameter is the class handle registered with the USBH driver using MSS_USBH_register_class_driver() function. This handle is used by the USBH driver to call the call-back functions implemented by the USBH-Class driver. */ typedef struct mss_usbh_target_info { uint8_t addr; mss_usb_device_speed_t speed; mss_usb_state_t state; uint8_t hub_addr; uint8_t hub_port; uint8_t hub_mtt; uint16_t tdev_maxpktsz0; mss_usbh_class_cb_t* class_handle; } mss_usbh_tdev_info_t; /*-------------------------------------------------------------------------*//** The mss_usbh_user_cb_t provides the prototype of the structure that must be implemented by the application to provide the call-back functions which will be called by the USBH driver to communicate events on the target device. These call-back functions can be used by the application to know the USBH driver state and information about the attached device from the USBH driver. These events are not specific to any USB class. usbh_tdev_attached The function pointed by the usbh_tdev_attached element will be called when a device attach even is detected by the USBH driver. At this point the device is not enumerated. The speed parameter indicates the USB speed of operation at which the USBH driver is going to communicate with the attached device. usbh_tdev_dettached The function pointed by the usbh_tdev_dettached element will be called when a device detach even is detected by the USBH driver. usbh_tdev_oc_error The function pointed by the usbh_tdev_oc_error element will be called when an over-current condition is detected by the USBH driver. usbh_tdev_enumerated The function pointed by the usbh_tdev_enumerated element will be called when the attached device is successfully enumerated. At this point the device descriptor is successfully read from the attached device. No class specific information is read from the device yet. The tdev_info parameter gives the information about the attached device. usbh_tdev_class_driver_assigned The function pointed by the usbh_tdev_class_driver_assigned element will be called when a matching class driver is assigned to the attached device. The class driver must be previously registered with the USBH driver using MSS_USBH_register_class_driver() function. usbh_tdev_not_supported The function pointed by the usbh_tdev_not_supported element will be called when a device which is not supported by the USBH driver is attached. The error_code parameter provides the exact reason why the device is not supported. E.g. devices belonging to Hub class are not supported. usbh_tdev_ permanent_error The function pointed by the usbh_tdev_permanent_error element will be called if there is error during data transfer operations with the attached device persists after retries. On detecting an error in data transfer with the attached device, the USBH driver retries for maximum three times. */ typedef struct mss_usbh_user_cb { void (*usbh_tdev_attached)(mss_usb_device_speed_t speed); void (*usbh_tdev_dettached)(void); void (*usbh_tdev_oc_error)(void); void (*usbh_tdev_enumerated)(mss_usbh_tdev_info_t tdev_info); void (*usbh_tdev_class_driver_assigned) (void); void (*usbh_tdev_not_supported)(int8_t error_code); void (*usbh_tdev_permanent_error)(void); } mss_usbh_user_cb_t; /*-------------------------------------------------------------------------*//** Data structures internally used by USBH driver */ /*-------------------------------------------------------------------------*//** The dev_desc_t provides the prototype of the structure for the standard USB device descriptor. All the parameters of this structure are as per the standard setup packet defined in the USB2.0 specification. bLength The bLength parameter indicates the length of the device descriptor in bytes. The meaning of this parameter is exactly as defined by the USB2.0 specification. bDescriptorType The bDescriptorType parameter indicates the standard descriptor type of this descriptor. The meaning of this parameter is exactly as defined by the USB2.0 specification. bcdUSB The bcdUSB parameter indicates the USB standard (BCD format) supported by the device. The meaning of this parameter is exactly as defined by the USB2.0 specification. bDeviceClass The bDeviceClass parameter indicates the standard USB class supported by the device. The meaning of this parameter is exactly as defined by the USB2.0 specification. bDeviceSubClass The bDeviceSubClass parameter indicates the standard USB sub-class supported by the device. The meaning of this parameter is exactly as defined by the USB2.0 specification. bDeviceProtocol The bDeviceProtocol parameter indicates the standard USB data transfer protocol supported by the device. The meaning of this parameter is exactly as defined by the USB2.0 specification. bMaxPacketSize0 The bMaxPacketSize0 parameter indicates the Maximum packet size of the Endpoint0 on the device. The meaning of this parameter is exactly as defined by the USB2.0 specification. idVendor The idVendor parameter indicates Vendor ID of the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. idProduct The idProduct parameter indicates Product ID of the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. bcdDevice The bcdDevice parameter indicates release number (BCD format) of the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. iManufacturer The iManufacturer parameter indicates the index of the string descriptor describing the manufacture name of the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. iProduct The iProduct parameter indicates index of string descriptor describing the product name of the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. iSerialNumber The iSerialNumber parameter indicates the index of the string descriptor describing the serial number of the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. bNumConfigurations The bNumConfigurations parameter indicates number of configurations supported by the connected device. The meaning of this parameter is exactly as defined by the USB2.0 specification. reserved The reserved parameter does not have a specific meaning. It is provided to make the structure word aligned. */ typedef struct { uint8_t bLength; uint8_t bDescriptorType; uint16_t bcdUSB; uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocol; uint8_t bMaxPacketSize0; uint16_t idVendor; uint16_t idProduct; uint16_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; uint16_t reserved; /*Word alignment*/ }dev_desc_t; /*-------------------------------------------------------------------------*//** The def_conf_desc_t provides the prototype of the structure for the standard USB configuration descriptor. All the parameters of this structure are as per the standard setup packet defined in the USB2.0 specification. bLength The bLength parameter indicates the length of the configuration descriptor in bytes. The meaning of this parameter is exactly as defined by the USB2.0 specification. bDescriptorType The bDescriptorType parameter indicates the standard descriptor type of this descriptor. The meaning of this parameter is exactly as defined by the USB2.0 specification. bTotalLength The bTotalLength parameter indicates the total length (in bytes) of the configuration descriptor including the class specific subordinate descriptors. The meaning of this parameter is exactly as defined by the USB2.0 specification. bNumInterface The bNumInterfaces parameter indicates the number of interfaces supported by this configuration. The meaning of this parameter is exactly as defined by the USB2.0 specification. bConfigurationValue The bConfigurationValue parameter indicates the value to be use as an argument to SET_CONFIGURATION request to select this configuration. The meaning of this parameter is exactly as defined by the USB2.0 specification. iConfiguration The iConfiguration parameter indicates the index of the string descriptor describing this configuration. The meaning of this parameter is exactly as defined by the USB2.0 specification. bmAttributes The bmAttributes parameter provides configuration characteristics of this configuration. The meaning of this parameter is exactly as defined by the USB2.0 specification. bMaxPower The bMaxPower parameter indicates the Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. The meaning of this parameter is exactly as defined by the USB2.0 specification. upended_desc The upended_desc parameter can be used to store the class specific subordinate descriptor information. This might be useful to retrieve some basic information about the selected configuration. */ typedef struct { uint8_t bLength; uint8_t bDescriptorType; uint16_t wTotalLength; uint8_t bNumInterfaces; uint8_t bConfigurationValue; uint8_t iConfiguration; uint8_t bmAttributes; uint8_t bMaxPower; uint8_t upended_desc[11]; }def_conf_desc_t; /*---------------------------USBH Public APIs---------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_USBH_init() function initializes the MSS USB driver in the USB host mode. This function initializes the internal data structures and readies the MSS USB hardware block to detect the device attachment event. This function also configures the control endpoint to keep it ready for communicating with the detected device on the USB port. The parameter app_cb provided with this function must be implemented by the application. This driver uses the app_cb to inform the application about the events on the USB bus by calling the appropriate callback element. The MSS_USBH_init() function must be called before any other function to initialize the USBH driver in the USB host mode. @param app_cb The app_cb parameter provides the pointer to the structure of type mss_usbh_user_cb_t. This structure is used to call the user call-back functions by the USBH driver. These call-back functions can be used to provide error/status messages to the user for the application specific handling of the events. @return This function does not return any value. Example: @code mss_usbh_user_cb_t MSS_USBH_user_cb = { USB_DEV_attached, USB_DEV_dettached, USB_DEV_oc_error, USB_DEV_enumerated, USB_DEV_class_driver_assigned, USB_DEV_not_supported, USB_DEV_permanent_erro }; MSS_USBH_init(&MSS_USBH_user_cb); MSS_USBH_register_class_driver(MSS_USBH_HID_get_handle()); @endcode */ void MSS_USBH_init ( mss_usbh_user_cb_t* app_cb ); /*-------------------------------------------------------------------------*//** The MSS_USBH_task() function is the main task of the USBH driver. This function must be called repeatedly by the application to allow the USBH driver to perform the housekeeping tasks. A timer/scheduler can be used to call this function at regular intervals or it can be called from the main continuous foreground loop of the application. @param This function does not take any parameters. @return This function does not return any value. Example: @code void Host_controller_task ( void ) { MSS_USBH_task(); MSS_USBH_HID_task(); switch (c_state) { case CONTROLLER_IDLE: if(USBH_MSD_DEVICE_READY == MSS_USBH_MSC_get_state()) { c_state = CONTROLLER_INQUIRY; } break; . default: break; } } @endcode */ void MSS_USBH_task ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_register_class_driver() function must be used by the application to register a USBH-Class driver with the USBH driver. The application must first get the handle from the USBH-Class driver before assigning it to the USBH driver. Refer the USBH-Class section to know how to get a handle from the USBH-Class driver. This handle is used by the USBH driver to communicate with the USBH-Class driver. @param class_handle The class_handle parameter specifies the class driver handle to be registered with the USBH driver. @return This function returns zero when execution was successful. Example: @code mss_usbh_user_cb_t MSS_USBH_user_cb = { USB_DEV_attached, USB_DEV_dettached, USB_DEV_oc_error, USB_DEV_enumerated, USB_DEV_class_driver_assigned, USB_DEV_not_supported, USB_DEV_permanent_erro }; MSS_USBH_init(&MSS_USBH_user_cb); MSS_USBH_register_class_driver(MSS_USBH_HID_get_handle()); @endcode */ int8_t MSS_USBH_register_class_driver ( void* class_handle ); /*-------------------------------------------------------------------------*//** The MSS_USBH_configure_control_pipe() function is used to configure the control pipe for the control transactions with attached device with the address provided in target_addr parameter. This function also enables the control pipe interrupt. This function must be called before any other function for the control pipe. @param target_addr The target_addr parameter is address of the attached device with which the MSS USB needs to communicate. @return This function returns zero when execution was successful. Example: @code typedef enum { TDEV_R, TDEV_RHP1, TDEV_RHP2 } tdev_id_t; MSS_USBH_configure_control_pipe(TDEV_R); @endcode */ int8_t MSS_USBH_configure_control_pipe ( uint8_t target_addr ); /*-------------------------------------------------------------------------*//** The MSS_USBH_configure_in_pipe() function is used to configure the IN pipe for the IN transactions with the attached device with the address provided in the target_addr parameter. This function also enables the IN pipe interrupt. This function must be called before any other function for the IN pipe. @param target_addr The target_addr parameter is the address of the attached device with which MSS USB needs to communicate. @param inpipe_num The inpipe_num parameter indicates the IN pipe number (endpoint) on MSS USB which must be used for IN transfers with the attached device. @param target_ep The target_ep parameter indicates the IN endpoint number on the attached device with which MSS USB needs to communicate. @param fifo_addr The fifo_addr parameter is the address of the FIFO in the MSS USB internal RAM. The valid FIFO address values are from 0x00 to 0xFFF8. The FIFO Address must be a multiple of 8. If the value provided is not a multiple of 8, then the immediate lower value which is a multiple of 8 is taken as the FIFO address. E.g. If the provided value is 0x09, the actual value taken by the driver is 0x08. If the provided value is less than 0x08 then the FIFO address is taken as 0x00. @param fifo_size The fifo_size parameter provides the endpoint FIFO size in the USB core internal RAM. The valid FIFO size values are 8, 16, 32, 64, 128, 512, 1024, 2048, 4096. The MSS USB assigns 8 byte FIFO by default if the FIFO size is not configured. @param max_pkt_size The max_pkt_size parameter provides the maximum packet size of the USB transfer. This value must be equal to the maximum packet size as mentioned in the endpoint descriptor which is used during enumeration process. Note: This value must be less than or equal to the FIFO size value. @param num_usb_pkt The num_usb_pkt parameter has different meanings for different types of transfers. Low bandwidth ISO/interrupt transfers - This parameter must always be 1u. This parameter represents the number of packets transferred in one (micro) frame. High bandwidth ISO transfers - This parameter represents the number of packets transferred in one (Micro) frame. In this case, this parameter can have a value of 1 2 or 3. High bandwidth ISO transfers are not yet implemented. Bulk transfers. - For Bulk transfer this value must always be 1u. This parameter is be used with the auto-amalgamation/auto-split feature where it indicates number of bulk packets to be auto-amalgamated/auto-split in bulk transfer. The auto-amalgamation/auto-split feature is implemented but not yet tested. @param dma_enable The dma_enable parameter specifies whether or not the internal DMA must be used for the data transfer from the provided buffer to the USB FIFO. @param dma_channel The dma_channel parameter specifies the internal DMA channel to be used for the data transfers. DMA channel will be associated with selected endpoint. A unique DMA channel must be selected to transfer data on individual endpoints. This parameter is ignored when dma_enable parameter indicates that the DMA must not be used. @param xfr_type The xfr_type parameter specifies the type of transfer to be performed on the specified endpoint. All other types of transfers (Interrupt, Isochronous, and Bulk) can be selected except the control transfer. @param add_zlp The add_zlp parameter indicates whether to expect a zero length packet (ZLP) if the transfer size is exact a multiple of wMaxPacketSize. This parameter is only applicable for bulk transfers. For all other transfer types this parameter is ignored. @param interval The interval parameter for interrupt and isochronous transfers defines the polling interval for the currently-selected IN pipe. For bulk transfers, this parameter indicates the number of frames/microframes after which the IN pipe must timeout on receiving a stream of NAK responses. The valid values for this parameter are as mentioned in the table below. | Transfer Type | Speed | Valid values | |------------------|------------|--------------------------------------------| | Interrupt | LS or FS | 1 - 255 | | Interrupt | HS | 1,2,4,8,16,32,64...32768 microframes | | | | | | Isochronous | FS or HS | 1,2,4,8,16,32,64...32768 frames/microframes| | | | | | Bulk | HS | 0,2,4,8,16,32,64...32768 microframes | | | | Note:Value 0 disables the NAK Timeout | | | | detection on Bulk endpoint | @return This function returns zero when execution was successful. Example: @code case USBH_MSC_CONFIG_BULK_ENDPOINTS: MSS_USBH_configure_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, USBH_MSC_BULK_TX_PIPE_FIFOADDR, USBH_MSC_BULK_TX_PIPE_FIFOSZ, g_tdev_out_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL_NA, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR, 32768u); MSS_USBH_configure_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, USBH_MSC_BULK_RX_PIPE_FIFOADDR, USBH_MSC_BULK_RX_PIPE_FIFOSZ, g_tdev_in_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL_NA, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR, 32768u); g_msc_state = USBH_MSC_TEST_UNIT_READY_CPHASE; break; @endcode */ int8_t MSS_USBH_configure_in_pipe ( uint8_t target_addr, uint8_t inpipe_num, uint8_t target_ep, uint16_t fifo_addr, uint16_t fifo_size, uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp, uint32_t interval ); /*-------------------------------------------------------------------------*//** The MSS_USBH_configure_out_pipe() function is used to configure the OUT pipe for the OUT transactions with attached device with the address provided in the target_addr parameter. This function also enables the OUT pipe interrupt. This function must be called before any other function for the OUT pipe. @param target_addr The target_addr parameter is the address of the attached device with which MSS USB needs to communicate. @param outpipe_num The outpipe_num parameter indicates the OUT pipe number (endpoint) on MSS USB which must be used for OUT transfers with the attached device. @param target_ep The target_ep parameter indicates the OUT endpoint number on the attached device with which MSS USB needs to communicate. @param fifo_addr The fifo_addr parameter is the address of the FIFO in the MSS USB internal ram. The valid FIFO address values are from 0x00 to 0xFFF8. The FIFO address must be a multiple of 8. If the value provided is not a multiple of 8, then the immediate lower value which is a multiple of 8 is taken as the FIFO address. E.g. If the provided value is 0x09, the actual value taken by the driver is 0x08. If the provided value is less than 0x08 then the FIFO address is taken as 0x00. @param fifo_size The fifo_size parameter provides the endpoint FIFO size in the USB core internal RAM. The valid FIFO size values are 8, 16, 32, 64, 128, 512, 1024, 2048, 4096. The MSS USB assigns 8 byte FIFO by default if the FIFO size is not configured. @param max_pkt_size The max_pkt_size parameter provides the maximum packet size of the USB transfer. This value must be equal to the maximum packet size as mentioned in the endpoint descriptor which is used during enumeration process. Note: This value must be less than or equal to the FIFO size value. @param num_usb_pkt The num_usb_pkt parameter has different meanings for different types of transfers. Low bandwidth ISO/interrupt transfers - This parameter must always be '1u'. This parameter represents the number of packets transferred in one (micro) frame. High bandwidth ISO transfers - This parameter represents the number of packets transferred in one (Micro) frame. In this case, this parameter can have a value of 1 2 or 3. High bandwidth ISO transfers are not yet implemented. Bulk transfers. - For Bulk transfer this value must always be '1u'. This parameter will be used with the auto-amalgamation/auto-split feature where it indicates the number of bulk packets to be auto-amalgamated/auto-split in bulk transfer. The auto-amalgamation/auto-split feature is implemented but not yet tested. @param dma_enable The dma_enable parameter specifies whether or not the internal DMA must be used for the data transfer from the provided buffer to the USB FIFO. @param dma_channel The dma_channel parameter specifies the internal DMA channel to be used for the data transfers. The DMA channel will be associated with the specified endpoint. A unique DMA channel must be selected to transfer data on individual endpoints. This parameter is ignored when the dma_enable parameter indicates that the DMA must not be used. @param xfr_type The xfr_type parameter specifies the type of transfer to be performed on the specified endpoint. All other types of transfers (Interrupt, Isochronous, and Bulk) can be selected except control transfer. @param add_zlp The add_zlp parameter indicates whether to send a zero length packet (ZLP) if the transfer size is a exact multiple of wMaxPacketSize. This parameter is only applicable for Bulk transfers. For all other transfer types this parameter is ignored. @param interval The interval parameter for interrupt and isochronous transfers, defines the polling interval for the currently-selected OUT pipe. For the bulk transfers, this parameter indicates the number of frames/microframes after which the OUT Pipe must time out on receiving a stream of NAK responses. The valid values for this parameter are as mentioned in the table below. | Transfer Type | Speed | Valid values | |------------------|-----------|---------------------------------------------| | Interrupt | LS or FS | 1 - 255 | | Interrupt | HS | 1,2,4,8,16,32,64...32768 microframes | | | | | | Isochronous | FS or HS | 1,2,4,8,16,32,64...32768 frames/microframes | | | | | | Bulk | HS | 0,2,4,8,16,32,64...32768 microframes | | | | Note:Value 0 disables the NAK Timeout | | | | detection on Bulk endpoint | @return This function returns zero when execution was successful. Example: @code case USBH_MSC_CONFIG_BULK_ENDPOINTS: MSS_USBH_configure_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, USBH_MSC_BULK_TX_PIPE_FIFOADDR, USBH_MSC_BULK_TX_PIPE_FIFOSZ, g_tdev_out_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL_NA, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR, 32768u); MSS_USBH_configure_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, USBH_MSC_BULK_RX_PIPE_FIFOADDR, USBH_MSC_BULK_RX_PIPE_FIFOSZ, g_tdev_in_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL_NA, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR, 32768u); g_msc_state = USBH_MSC_TEST_UNIT_READY_CPHASE; break; @endcode */ int8_t MSS_USBH_configure_out_pipe ( uint8_t target_addr, uint8_t outpipe_num, uint8_t target_ep, uint16_t fifo_addr, uint16_t fifo_size, uint16_t max_pkt_size, uint8_t num_usb_pkt, uint8_t dma_enable, mss_usb_dma_channel_t dma_channel, mss_usb_xfr_type_t xfr_type, uint32_t add_zlp, uint32_t interval ); /*-------------------------------------------------------------------------*//** The MSS_USBH_write_out_pipe() function writes the data provided by the user into the previously configured out pipe FIFO. The data is ready to be transferred after calling this function. The Data will be transferred by the MSS USB according to the transfer type and interval parameter set for this OUT pipe using MSS_USBH_configure_out_pipe() function. This function is non-blocking.A call-back function will be called to indicate the status of this transfer after the status phase of the current OUT transaction is complete. @param target_addr The target_addr parameter is the address of the attached device with which the MSS USB needs to communicate. @param outpipe_num The outpipe_num parameter indicates the OUT pipe number (endpoint) on the MSS USB which must be used for the OUT transfers with the attached device. @param target_ep The target_ep parameter indicates the OUT endpoint number on the attached device with which MSS USB needs to communicate. @param max_pkt_size The max_pkt_size parameter provides the maximum packet size of the USB transfer. This value must be equal to the maximum packet size as mentioned in the endpoint descriptor which is used during enumeration process. @param buf The buf parameter is the address of the buffer provided by the user from which the data is copied to the selected pipe buffer. @param length The length parameter specifies the length of the data buffer in bytes. @return This function does not return a value. Example: @code case USBH_MSC_TEST_UNIT_READY_CPHASE: MSS_USBH_MSC_construct_cbw_cb6byte(USB_MSC_SCSI_TEST_UNIT_READY, 0u, &g_bot_cbw); MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, (uint8_t*)&g_bot_cbw, 31u); g_msc_state = USBH_MSC_TEST_UNIT_READY_SPHASE; break; @endcode */ int8_t MSS_USBH_write_out_pipe ( uint8_t target_addr, uint8_t outpipe_num, uint8_t tdev_ep_num, uint16_t maxpktsz, uint8_t* buf, uint32_t length ); /*-------------------------------------------------------------------------*//** The MSS_USBH_read_in_pipe() function writes the data provided by the user into the previously configured out pipe FIFO. The data is ready to be transferred after calling this function. The data will be transferred by the MSS USB according to the transfer type and the interval parameter set for this OUT pipe using theMSS_USBH_configure_in_pipe() function. This function is non-blocking. A call-back function will be called to indicate the status of this transfer after the status phase of the current IN transaction is complete. @param target_addr The target_addr parameter is the address of the attached device with which the MSS USB needs to communicate. @param outpipe_num The outpipe_num parameter indicates the OUT pipe number (endpoint) on MSS USB which must be used for the OUT transfers with the attached device. @param target_ep The target_ep parameter indicates the OUT endpoint number on the attached device with which the MSS USB needs to communicate. @param max_pkt_size The max_pkt_size parameter provides the maximum packet size of the USB transfer. This value must be equal to the maximum packet size as mentioned in the endpoint descriptor which is used during enumeration process. @param buf The buf parameter is the address of the buffer provided by the user from which the data is copied to the selected pipe buffer. @param length The length parameter specifies the length of the data buffer in bytes. @return This function does not return a value. Example: @code case USBH_MSC_TEST_UNIT_READY_SPHASE: if(g_usbh_msc_tx_event) { g_usbh_msc_tx_event = 0; g_msc_state = USBH_MSC_TEST_UNIT_READY_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, (uint8_t*)&g_bot_csw, 13u); } break; @endcode */ int8_t MSS_USBH_read_in_pipe ( uint8_t target_addr, uint8_t inpipe_num, uint8_t tdev_ep_num, uint16_t tdev_ep_maxpktsz, uint8_t* buf, uint32_t length ); /*-------------------------------------------------------------------------*//** The MSS_USBH_get_tdev_state() function can be used to find out the current state of the attached device. E.g. ADDRESS, CONFIGURED etc. (as defined by USB2.0). @param target_addr The target_addr parameter is the address of the attached device with which the MSS USB needs to communicate. @return This function returns a value of type mss_usb_state_t indicating the current state of the attached device. Example: @code static mss_usb_state_t msd_tdev_state = MSS_USB_NOT_ATTACHED_STATE; msd_tdev_state = MSS_USBH_get_tdev_state(g_msd_tdev_addr); @endcode */ mss_usb_state_t MSS_USBH_get_tdev_state ( uint8_t target_addr ); /*-------------------------------------------------------------------------*//** The MSS_USBH_suspend() function can be used to suspend the MSS USB. The MSS USB will complete the current transaction then stop the transaction scheduler and frame counter. No further transactions will be started and no SOF packets will be generated. @param This function does not take any parameters. @return This function does not return any value. Example: @code @endcode */ void MSS_USBH_suspend ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_resume() function can be used to resume the previously suspended MSS USB. If the MSS USB was in suspend mode then it will start the transaction scheduler and frame counter after calling this function. @param This function does not take any parameters. @return This function does not return any value. Example: @code @endcode */ void MSS_USBH_resume ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_1ms_tick() function must be used to provide the 1ms time tick to the USBH driver. This time reference is used by the USBH driver to keep track of different time delays required during enumeration process. This way the application need not wait for the enumeration to complete which may take long time. @param This function does not take any parameters. @return This function does not return any value. Example: @code void SysTick_Handler(void) { MSS_USBH_task(); MSS_USBH_HID_task(); MSS_USBH_1ms_tick(); } @endcode */ void MSS_USBH_1ms_tick ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_get_milis() function is used to find out the number of milliseconds elapsed from the time when last reset occurred. @param This function does not take any parameters. @return This function returns a 32-bit unsigned integer value. This value indicates the number of milliseconds elapsed from the time when the last reset occurred. This integer value will overflow after approximately 49Hrs after reset. Example: @code case USBH_MSC_WAIT_SET_CONFIG: if(g_usbh_msc_cep_event) { g_usbh_msc_cep_event = 0; wait_mili = MSS_USBH_get_milis(); g_msc_state = USBH_MSC_WAIT_DEV_SETTLE; } break; case USBH_MSC_WAIT_DEV_SETTLE: if((MSS_USBH_get_milis() - wait_mili) > 60) { g_msc_state = USBH_MSC_GET_MAX_LUN; } break; @endcode */ uint32_t MSS_USBH_get_milis ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_construct_get_descr_command() function is be used to construct the setup packet which is to be sent on the USB bus. This function formats the provided parameters into a USB standard format GET_DESCRIPTOR request and stores it in the location provided by the buf parameter. @param buf The buf parameter is the address of the buffer where the formatted GET_DESCRIPTOR request is stored. @param xfr_dir The xfr_dir parameter indicates the direction of the data transfer on the USB bus. The value USB_STD_REQ_DATA_DIR_IN indicates that the direction of the data transfer is from the USB device to USB host (USB IN transaction). The value USB_STD_REQ_DATA_DIR_OUT indicates that the direction of the data transfer is from the USB host to the USB device (USB OUT transaction). @param req_type The req_type parameter indicates the request type. The request type can be one of the following: standard request, class request or vendor request. @param recip_type The recip_type parameter indicates the recipient type on the USB device. The request recipient on the attached device can be one of the following: device, endpoint or interface. @param request The request parameter indicates the request that needs to be sent to the attached device. @param desc_type The desc_type parameter indicates the descriptor type that needs to be requested from the attached device. @param strng_idx The strng_idx parameter indicates the index of the string descriptor when the desc_type parameter indicates STRING TYPE. @param length The length parameter indicates the number of bytes to be received from attached device as part of the requested descriptor. @return This function does not return any value. Example: @code MSS_USBH_configure_control_pipe(g_msd_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 32u); g_msc_state = USBH_MSC_WAIT_GET_CLASS_DESCR; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_msd_conf_desc, USB_STD_REQ_DATA_DIR_IN, 32u); @endcode */ void MSS_USBH_construct_get_descr_command ( uint8_t* buf, uint8_t xfr_dir, uint8_t req_type, uint8_t recip_type, uint8_t request, uint8_t desc_type, uint8_t strng_idx, uint16_t length ); /*-------------------------------------------------------------------------*//** The MSS_USBH_start_control_xfr() function must be used to start a control transfer with the attached USB device. This is a non-blocking function. This function prepares the control pipe for the control transfer. A call-back function will be called to indicate the status of the transfer after the status phase of the control transfer is complete. @param cbuf_addr The cbuf_addf parameter is the address of the buffer where the USB request setup packet is available. @param dbuf_addr The dbuf_addf parameter is the address of the buffer for the data phase of the control transfer. The USBD driver will put the data received from attached device in this buffer for the USB IN transfers. The data from this buffer will be sent to the attached device for the USB OUT transfers. @param data_dir The data_dir parameter indicates the direction of the data flow in the data phase of the control transfer. The value USB_STD_REQ_DATA_DIR_IN indicates that the direction of the data transfer is from the USB device to the USB host (USB IN transaction). The value USB_STD_REQ_DATA_DIR_OUT indicates that the direction of the data transfer is from the USB host to the USB device (USB OUT transaction). @param data_len The data_len parameter indicates the number of bytes to be transferred during the data phase of the control transfer. @return This function returns zero when execution was successful. Example: @code MSS_USBH_configure_control_pipe(g_msd_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 32u); g_msc_state = USBH_MSC_WAIT_GET_CLASS_DESCR; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_msd_conf_desc, USB_STD_REQ_DATA_DIR_IN, 32u); @endcode */ uint8_t MSS_USBH_start_control_xfr ( uint8_t* cbuf_addr, uint8_t* dbuf_addr, uint8_t data_dir, uint32_t data_len ); /*-------------------------------------------------------------------------*//** The MSS_USBH_get_cep_state() function can be used to find out the current state of the control pipe. A new control transfer can be started when the control pipe is in the MSS_USB_CEP_IDLE state. @param This function does not take any parameters. @return This function returns a value of type mss_usb_ep_state_t indicating the current state of the control pipe. Example: @code mss_usb_ep_state_t cep_st; cep_st = MSS_USBH_get_cep_state(); if(MSS_USB_CEP_IDLE == cep_st) { MSS_USBH_configure_control_pipe(g_msd_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 32u); g_msc_state = USBH_MSC_WAIT_GET_CLASS_DESCR; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_msd_conf_desc, USB_STD_REQ_DATA_DIR_IN, 32u); } @endcode */ mss_usb_ep_state_t MSS_USBH_get_cep_state ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_test_mode() function can be used to initiate one of the compliance test modes in the MSS USB. This function is useful only for compliance test procedures. The MSS USB goes into the specified test mode once this function is executed. A hard reset is required to resume normal operations. @param test_case The test_case parameter indicates the compliance test that need to be executed.The compliance tests could be one of the following: Test-J (USB_TEST_MODE_SELECTOR_TEST_J), Test-K (USB_TEST_MODE_SELECTOR_TEST_K), SE0-NAK (USB_TEST_MODE_SELECTOR_TEST_SE0NAK), Test-Packet (USB_TEST_MODE_SELECTOR_TEST_PACKET) @return This function does not return any value. Example: @code case '1': MSS_USBH_test_mode(USB_TEST_MODE_SELECTOR_TEST_PACKET); MSS_UART_polled_tx_string(&g_mss_uart1, (uint8_t *)"\n\n\r Test-Packet started..."); break; case '2': MSS_USBH_test_mode(USB_TEST_MODE_SELECTOR_TEST_J); MSS_UART_polled_tx_string(&g_mss_uart1, (uint8_t *)"\n\n\r Test-J started..."); break; case '3': MSS_USBH_test_mode(USB_TEST_MODE_SELECTOR_TEST_K); MSS_UART_polled_tx_string(&g_mss_uart1, (uint8_t *)"\n\n\r Test-K started..."); break; case '4': MSS_USBH_test_mode(USB_TEST_MODE_SELECTOR_TEST_SE0NAK); MSS_UART_polled_tx_string(&g_mss_uart1, (uint8_t *)"\n\n\r Test-SE0-NAK started..."); break; case '5': MSS_USBH_test_mode(USB_TEST_MODE_SELECTOR_TEST_FORCE_ENA); MSS_UART_polled_tx_string(&g_mss_uart1, (uint8_t *)"\n\n\r Test-Force-Host started..."); break; default: invalid_selection_menu(); break; @endcode */ void MSS_USBH_test_mode ( uint8_t test_case ); /*-------------------------------------------------------------------------*//** The MSS_USBH_get_std_dev_descr() function can be used to get the 8 byte USB standard device descriptor from the attached device. This function is provided specifically for the Standard Descriptor test case of USB-IF compliance procedure. This function might not be useful In general scenarios. @param buffer The buffer parameter is the pointer to the buffer where the USB standard device descriptor received from the attached device will be stored. @return This function returns zero on successful execution. Example: @code mss_usb_ep_state_t cep_st; cep_st = MSS_USBH_get_cep_state(); if(MSS_USB_CEP_IDLE == cep_st) { MSS_USBH_configure_control_pipe(g_msd_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 32u); g_msc_state = USBH_MSC_WAIT_GET_CLASS_DESCR; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_msd_conf_desc, USB_STD_REQ_DATA_DIR_IN, 32u); } @endcode */ int8_t MSS_USBH_get_std_dev_descr ( uint8_t* buffer ); void MSS_USBH_abort_in_pipe ( mss_usb_ep_num_t inpipe_num ); void MSS_USBH_abort_out_pipe ( mss_usb_ep_num_t outpipe_num ); #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif #endif /* __MSS_USB_HOST_H_ */ mss_usb_host_cif.c000066400000000000000000000266271432224323300404400ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USBH-CIF driver * * USBH-CIF driver implementation: * This file implements MSS USB core initialization in host mode and * implements core interface function for the logical layer to control the * MSS USB core in USB Host mode. * * SVN $Revision$ * SVN $Date$ */ #include "mss_assert.h" #include "mss_plic.h" #include "mss_usb_host_cif.h" #include "mss_usb_common_cif.h" #include "mss_usb_common_reg_io.h" #include "mss_usb_core_regs.h" #include "mss_usb_host_reg_io.h" #include "mss_usb_std_def.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED extern mss_usbh_cb_t g_mss_usbh_cb; /***************************************************************************//** * */ void MSS_USBH_CIF_init ( void ) { MSS_USB_CIF_enable_hs_mode(); MSS_USB_CIF_clr_usb_irq_reg(); PLIC_EnableIRQ(PLIC_USB_DMA_INT_OFFSET); MSS_USB_CIF_rx_ep_disable_irq_all(); MSS_USB_CIF_tx_ep_disable_irq_all(); PLIC_EnableIRQ(USB_MC_PLIC); /* This was added during Compliance testing */ USB->C_T_HSBT = 0x01u; MSS_USB_CIF_enable_usbirq(CONNECT_IRQ_MASK | DISCONNECT_IRQ_MASK); MSS_USB_CIF_start_session(); } /***************************************************************************//** * */ void MSS_USBH_CIF_cep_configure ( mss_usb_ep_t* cep ) { /* Control transfers will be handled without DMA */ MSS_USBH_CIF_cep_clr_csr_reg(); /* TODO:Ping should be decided based on TDev Speed. */ if (cep->disable_ping) { MSS_USBH_CIF_cep_disable_ping(); } else { MSS_USBH_CIF_cep_enable_ping(); } ASSERT(cep->interval <= 32768u); /* Value 0 or 1 disables the NAKTIMEOUT functionality.*/ if (cep->interval <= 32768u) { /*Value must be true and power of 2*/ ASSERT(((cep->interval != 0U) && (!(cep->interval & (cep->interval- 1))))); /*2 pow (m-1)*/ MSS_USBH_CIF_cep_set_naklimit((MSS_USBH_CIF_ctz(cep->interval) + 1u)); } /* Not flushing FIFO..since Tx/Rxpktrdy bit is not set. */ MSS_USB_CIF_cep_enable_irq(); } /******************************************************************************* * Configures the registers related to TX EP for data transfer operations as * per the parameters provided by the upper layer. */ void MSS_USBH_CIF_tx_ep_configure ( mss_usb_ep_t* host_ep ) { MSS_USB_CIF_tx_ep_clr_csrreg(host_ep->num); /* Perform host mode configurations here */ /* TODO: Add AutoSet DMA etc */ MSS_USBH_CIF_tx_ep_clr_retry_err(host_ep->num); MSS_USBH_CIF_tx_ep_clr_naktimeout_err(host_ep->num); MSS_USBH_CIF_tx_ep_clr_rxstall_err(host_ep->num); MSS_USBH_CIF_tx_ep_clr_data_tog_we(host_ep->num); MSS_USBH_CIF_tx_ep_clr_force_data_tog(host_ep->num); if (DMA_ENABLE == host_ep->dma_enable) { MSS_USB_CIF_tx_ep_set_autoset(host_ep->num); } else { MSS_USB_CIF_tx_ep_clr_autoset(host_ep->num); } /* Do the common configuration for TX EP */ MSS_USB_CIF_tx_ep_configure(host_ep); } /******************************************************************************* * Configures the registers related to RX EP for data transfer operations as * per the parameters provided by the upper layer. */ void MSS_USBH_CIF_rx_ep_configure ( mss_usb_ep_t* host_ep ) { MSS_USB_CIF_rx_ep_clr_csrreg(host_ep->num); /* Perform host mode configurations here */ /* TODO: Add AutoSet DMA etc */ MSS_USBH_CIF_rx_ep_clr_retry_err(host_ep->num); MSS_USBH_CIF_rx_ep_clr_naktimeout_err(host_ep->num); MSS_USBH_CIF_rx_ep_clr_rxstall_err(host_ep->num); MSS_USBH_CIF_rx_ep_clr_data_tog_we(host_ep->num); MSS_USBH_CIF_rx_ep_clr_data_tog(host_ep->num); if (DMA_ENABLE == host_ep->dma_enable) { MSS_USBH_CIF_rx_ep_set_autoreq(host_ep->num); } else { MSS_USBH_CIF_rx_ep_clr_autoreq(host_ep->num); } /* Do the common configuration for RX EP */ MSS_USB_CIF_rx_ep_configure(host_ep); } /***************************************************************************//** * */ void MSS_USBH_CIF_bus_suspend ( uint32_t enable_suspendm ) { if (SUSPENDM_DISABLE == enable_suspendm) { MSS_USBH_CIF_disable_suspendm_out(); } else { MSS_USBH_CIF_enable_suspendm_out(); } MSS_USBH_CIF_assert_suspend_bus(); } /***************************************************************************//** * */ void MSS_USBH_CIF_bus_resume ( void ) { MSS_USBH_CIF_clr_suspend_bus(); MSS_USBH_CIF_assert_bus_resume(); /* TODO:This delay should be 20ms */ MSS_USBH_CIF_clr_bus_resume(); } /***************************************************************************//** * */ mss_usb_vbus_level_t MSS_USBH_CIF_read_vbus_level ( void ) { return (MSS_USB_CIF_get_vbus_level()); } /***************************************************************************//** * */ uint32_t MSS_USBH_CIF_tx_ep_mp_configure ( uint8_t outpipe_num, uint8_t tdev_ep_num, uint8_t tdev_addr, uint8_t tdev_hub_addr, uint8_t tdev_hub_port, uint8_t tdev_hub_mtt, mss_usb_device_speed_t tdev_speed, uint32_t tdev_interval, mss_usb_xfr_type_t tdev_xfr_type ) { MSS_USBH_CIF_tx_ep_clr_txtypereg((mss_usb_ep_num_t)outpipe_num); /* * Since the core has Multipoint option enabled, following settings need to * be done even though there is single device connected */ MSS_USBH_CIF_tx_ep_set_target_func_addr((mss_usb_ep_num_t)outpipe_num, tdev_addr); #if 0 /* Hub and multiple devices are not supported yet */ MSS_USBH_CIF_tx_ep_set_target_hub_addr(outpipe_num, tdev_hub_addr, tdev_hub_mtt); MSS_USBH_CIF_tx_ep_set_target_hub_port(outpipe_num, tdev_hub_port); #endif if ((MSS_USB_XFR_INTERRUPT == tdev_xfr_type) && (MSS_USB_DEVICE_HS != tdev_speed)) { MSS_USBH_CIF_tx_ep_set_target_interval((mss_usb_ep_num_t)outpipe_num, tdev_interval); } else { /*2 pow (m-1)*/ MSS_USBH_CIF_tx_ep_set_target_interval((mss_usb_ep_num_t)outpipe_num, ((MSS_USBH_CIF_ctz(tdev_interval)) + 1u)); } MSS_USBH_CIF_tx_ep_set_target_ep_no((mss_usb_ep_num_t)outpipe_num, tdev_ep_num); MSS_USBH_CIF_tx_ep_set_target_protocol((mss_usb_ep_num_t)outpipe_num, tdev_xfr_type); MSS_USBH_CIF_tx_ep_set_target_speed((mss_usb_ep_num_t)outpipe_num, tdev_speed); return (0); } /***************************************************************************//** * */ uint32_t MSS_USBH_CIF_rx_ep_mp_configure ( uint8_t inpipe_num, uint8_t tdev_ep_num, uint8_t tdev_addr, uint8_t tdev_hub_addr, uint8_t tdev_hub_port, uint8_t tdev_hub_mtt, mss_usb_device_speed_t tdev_speed, uint32_t tdev_interval, mss_usb_xfr_type_t tdev_xfr_type ) { MSS_USBH_CIF_rx_ep_clr_rxtypereg((mss_usb_ep_num_t)inpipe_num); /* * Since the core has Multipoint option enabled, following settings need to * be done even though there is single device connected */ MSS_USBH_CIF_rx_ep_set_target_func_addr((mss_usb_ep_num_t)inpipe_num, tdev_addr); #if 0 /* Hub and multiple devices are not supported yet */ MSS_USBH_CIF_rx_ep_set_target_hub_addr((mss_usb_ep_num_t)inpipe_num, tdev_hub_addr, tdev_hub_mtt); MSS_USBH_CIF_rx_ep_set_target_hub_port((mss_usb_ep_num_t)inpipe_num, tdev_hub_port); #endif if((MSS_USB_XFR_INTERRUPT == tdev_xfr_type) && (MSS_USB_DEVICE_HS != tdev_speed)) { MSS_USBH_CIF_rx_ep_set_target_interval((mss_usb_ep_num_t)inpipe_num, tdev_interval); } else { MSS_USBH_CIF_rx_ep_set_target_interval((mss_usb_ep_num_t)inpipe_num, ((MSS_USBH_CIF_ctz(tdev_interval)) + 1u)); } MSS_USBH_CIF_rx_ep_set_target_ep_no((mss_usb_ep_num_t)inpipe_num, tdev_ep_num); MSS_USBH_CIF_rx_ep_set_target_protocol((mss_usb_ep_num_t)inpipe_num, tdev_xfr_type); MSS_USBH_CIF_rx_ep_set_target_speed((mss_usb_ep_num_t)inpipe_num, tdev_speed); return(0); } /******************************************************************************* * Writes a data packet on EP0 in host mode(control endpoint). */ void MSS_USBH_CIF_cep_write_pkt ( mss_usb_ep_t* hcep ) { ASSERT((hcep->num == MSS_USB_CEP) && (hcep->buf_addr != 0) && (hcep->xfr_type == MSS_USB_XFR_CONTROL)); /* null buffer, xfr type, transaction type */ if ((hcep->num == MSS_USB_CEP) && (hcep->buf_addr != 0) && (hcep->xfr_type == MSS_USB_XFR_CONTROL)) { MSS_USB_CIF_load_tx_fifo(hcep->num, hcep->buf_addr, hcep->txn_length); hcep->txn_count = hcep->txn_length; hcep->xfr_count += hcep->txn_length; } } /******************************************************************************* * Reads data packet arrived on EP0 in host mode(control endpoint). */ void MSS_USBH_CIF_cep_read_pkt ( mss_usb_ep_t* hcep ) { uint16_t received_count = 0u; ASSERT((hcep->num == MSS_USB_CEP) && (hcep->buf_addr != 0) && (hcep->xfr_type == MSS_USB_XFR_CONTROL)); /* TODO: check stalled, null buffer, xfr type, transaction type */ received_count = MSS_USB_CIF_cep_rx_byte_count(); ASSERT(received_count <= hcep->txn_length); MSS_USB_CIF_read_rx_fifo(MSS_USB_CEP, hcep->buf_addr, received_count); hcep->buf_addr += received_count; MSS_USBH_CIF_cep_clr_rxpktrdy(); hcep->xfr_count += received_count; hcep->txn_count = received_count; } /***************************************************************************//** * */ void MSS_USBH_CIF_cep_abort_xfr ( void ) { /* Flush the FIFO and reset all values */ MSS_USB_CIF_cep_disable_irq(); MSS_USB_CIF_cep_set_txpktrdy(); MSS_USB_CIF_cep_flush_fifo(); MSS_USB_CIF_cep_enable_irq(); /* clear all bits but retain the values of Data_tog_we and Disable_ping */ MSS_USBH_CIF_cep_clr_naktimeout_err(); MSS_USBH_CIF_cep_clr_rxstall_err(); MSS_USBH_CIF_cep_clr_rxpktrdy(); USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~ (CSR0L_HOST_IN_PKT_REQ_MASK | CSR0L_HOST_SETUP_PKT_MASK | CSR0L_HOST_STATUS_PKT_MASK | CSR0L_HOST_RX_PKT_RDY_MASK | CSR0H_HOST_DATA_TOG_MASK); } /***************************************************************************//** * */ void MSS_USBH_CIF_handle_connect_irq ( void ) { mss_usb_device_speed_t speed = MSS_USB_DEVICE_FS; if (MSS_USBH_CIF_is_target_ls()) { speed = MSS_USB_DEVICE_LS; } else if (MSS_USBH_CIF_is_target_fs()) { speed = (MSS_USB_DEVICE_FS); } if (MSS_USBH_CIF_is_host_suspended()) { MSS_USBH_CIF_clr_suspend_bus(); } g_mss_usbh_cb.usbh_connect(speed , MSS_USB_CIF_get_vbus_level()); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif mss_usb_host_cif.h000066400000000000000000000313541432224323300404360ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USBH-CIF driver * * USBH-CIF driver public API. * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_HOST_CIF_H_ #define __MSS_USB_HOST_CIF_H_ #include "mss_usb_common_cif.h" #include "mss_usb_core_regs.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /*-------------------------------------------------------------------------*//** Constant values which can be used by class component or the application. */ #define USB_HS_BULK_MAX_PKT_SIZE 512u #define USB_HS_INTERRUPT_MAX_PKT_SIZE 1024u #define USB_HS_ISO_MAX_PKT_SIZE 1024u #define USB_FS_BULK_MAX_PKT_SIZE 64u #define USB_FS_INTERRUPT_MAX_PKT_SIZE 64u #define USB_FS_ISO_MAX_PKT_SIZE 1023u typedef struct { void(*usbh_tx_complete)(uint8_t ep_num, uint8_t status); void(*usbh_rx)(uint8_t ep_num, uint8_t status); void(*usbh_cep)(uint8_t status); void(*usbh_sof)(uint32_t frame_number); void(*usbh_connect)(mss_usb_device_speed_t target_speed, mss_usb_vbus_level_t vbus_level); void(*usbh_disconnect)(void); void(*usbh_vbus_error)(mss_usb_vbus_level_t); void(*usbh_babble_error)(void); void(*usbh_session_request)(void); void(*usbh_dma_handler)(mss_usb_ep_num_t ep_num, mss_usb_dma_dir_t dma_dir, uint8_t status, uint32_t dma_addr_val); } mss_usbh_cb_t; /*--------------------------------Public APIs---------------------------------*/ /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_init() @param @return Example: @code @endcode */ void MSS_USBH_CIF_init ( void ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_handle_connect_irq() @param @return Example: @code @endcode */ void MSS_USBH_CIF_handle_connect_irq ( void ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_cep_configure() @param @return Example: @code @endcode */ void MSS_USBH_CIF_cep_configure ( mss_usb_ep_t* cep ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_tx_ep_configure() @param @return Example: @code @endcode */ void MSS_USBH_CIF_tx_ep_configure ( mss_usb_ep_t* host_ep ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_rx_ep_configure() @param @return Example: @code @endcode */ void MSS_USBH_CIF_rx_ep_configure ( mss_usb_ep_t* host_ep ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_bus_suspend() @param @return Example: @code @endcode */ void MSS_USBH_CIF_bus_suspend ( uint32_t enable_suspendm ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_bus_resume() @param @return Example: @code @endcode */ void MSS_USBH_CIF_bus_resume ( void ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_read_vbus_level() @param @return Example: @code @endcode */ mss_usb_vbus_level_t MSS_USBH_CIF_read_vbus_level ( void ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_ep_tx_start() @param @return Example: @code @endcode */ void MSS_USBH_CIF_ep_tx_start ( mss_usb_ep_t* host_ep ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_tx_ep_mp_configure() @param @return Example: @code @endcode */ uint32_t MSS_USBH_CIF_tx_ep_mp_configure ( uint8_t outpipe_num, uint8_t tdev_ep_num, uint8_t tdev_addr, uint8_t tdev_hub_addr, uint8_t tdev_hub_port, uint8_t tdev_hub_mtt, mss_usb_device_speed_t speed, uint32_t tdev_interval, mss_usb_xfr_type_t xfr_type ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_rx_ep_mp_configure() @param @return Example: @code @endcode */ uint32_t MSS_USBH_CIF_rx_ep_mp_configure ( uint8_t inpipe_num, uint8_t tdev_ep_num, uint8_t tdev_addr, uint8_t tdev_hub_addr, uint8_t tdev_hub_port, uint8_t tdev_hub_mtt, mss_usb_device_speed_t speed, uint32_t tdev_interval, mss_usb_xfr_type_t xfr_type ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_cep_write_pkt() @param @return Example: @code @endcode */ void MSS_USBH_CIF_cep_write_pkt ( mss_usb_ep_t* cep ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_cep_start_xfr() @param @return Example: @code @endcode */ void MSS_USBH_CIF_cep_start_xfr ( mss_usb_ep_state_t state ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_cep_abort_xfr() @param @return Example: @code @endcode */ void MSS_USBH_CIF_cep_abort_xfr ( void ); /*-------------------------------------------------------------------------*//** MSS_USBH_CIF_cep_read_pkt() @param @return Example: @code @endcode */ void MSS_USBH_CIF_cep_read_pkt ( mss_usb_ep_t* hcep ); /*-------------------------------------------------------------------------*//** Static __Inline functions */ static __INLINE void MSS_USBH_CIF_assert_bus_reset(void) { USB->POWER |= POWER_REG_BUS_RESET_SIGNAL_MASK; } static __INLINE void MSS_USBH_CIF_clr_bus_reset(void) { USB->POWER &= ~POWER_REG_BUS_RESET_SIGNAL_MASK; } static __INLINE void MSS_USBH_CIF_assert_bus_resume(void) { USB->POWER |= POWER_REG_RESUME_SIGNAL_MASK; /*clear after min. 20ms*/ } static __INLINE void MSS_USBH_CIF_clr_bus_resume(void) { USB->POWER &= ~POWER_REG_RESUME_SIGNAL_MASK; } static __INLINE void MSS_USBH_CIF_enable_suspendm_out(void) { USB->POWER |= POWER_REG_ENABLE_SUSPENDM_MASK; } static __INLINE void MSS_USBH_CIF_disable_suspendm_out(void) { USB->POWER &= ~POWER_REG_ENABLE_SUSPENDM_MASK; } static __INLINE void MSS_USBH_CIF_assert_suspend_bus(void) { USB->POWER |= POWER_REG_SUSPEND_MODE_MASK; } static __INLINE void MSS_USBH_CIF_clr_suspend_bus(void) { USB->POWER &= ~POWER_REG_SUSPEND_MODE_MASK; } static __INLINE uint8_t MSS_USBH_CIF_is_host_suspended(void) { return (((USB->POWER & POWER_REG_SUSPEND_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_end_session(void) { USB->DEV_CTRL &= ~DEV_CTRL_SESSION_MASK; } /*-------------------------------------------------------------------------*//** DEVCTL register related APIs */ static __INLINE uint8_t MSS_USBH_CIF_is_target_ls(void) { return (((USB->DEV_CTRL & DEV_CTRL_LS_DEV_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_is_target_fs(void) { return (((USB->DEV_CTRL & DEV_CTRL_FS_DEV_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_is_hs_mode(void) { return(((USB->POWER & POWER_REG_HS_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** CSR0L register related APIs */ static __INLINE void MSS_USBH_CIF_cep_clr_rxpktrdy(void) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0L_HOST_RX_PKT_RDY_MASK; } static __INLINE void MSS_USBH_CIF_cep_set_request_in_pkt(void) { /* Cleared when RxPktRdy is cleared */ USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= CSR0L_HOST_IN_PKT_REQ_MASK; } static __INLINE void MSS_USBH_CIF_cep_set_setuppktonly(void) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= (CSR0L_HOST_SETUP_PKT_MASK); } static __INLINE void MSS_USBH_CIF_cep_set_setuppktrdy(void) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= (CSR0L_HOST_SETUP_PKT_MASK | CSR0L_HOST_TX_PKT_RDY_MASK); } static __INLINE void MSS_USBH_CIF_cep_set_statuspktrdy_after_out(void) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= (CSR0L_HOST_STATUS_PKT_MASK | CSR0L_HOST_IN_PKT_REQ_MASK); } static __INLINE void MSS_USBH_CIF_cep_set_statuspktrdy_after_in(void) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= (CSR0L_HOST_STATUS_PKT_MASK | CSR0L_HOST_TX_PKT_RDY_MASK); } static __INLINE void MSS_USBH_CIF_cep_clr_statusRxpktrdy(void) { if(CSR0L_HOST_RX_PKT_RDY_MASK | USB->ENDPOINT[MSS_USB_CEP].TX_CSR) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~(CSR0L_HOST_STATUS_PKT_MASK | CSR0L_HOST_RX_PKT_RDY_MASK); } else { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~(CSR0L_HOST_STATUS_PKT_MASK); } } static __INLINE uint16_t MSS_USBH_CIF_cep_read_csr_reg(void) { return(USB->ENDPOINT[MSS_USB_CEP].TX_CSR); } static __INLINE void MSS_USBH_CIF_cep_set_txpktrdy(void) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= CSR0L_HOST_TX_PKT_RDY_MASK; } static __INLINE void MSS_USBH_CIF_cep_clr_data_tog ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0H_HOST_DATA_TOG_MASK; } static __INLINE void MSS_USBH_CIF_cep_set_data_tog_we ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0H_HOST_DATA_TOG_WE_MASK; } static __INLINE void MSS_USBH_CIF_cep_clr_data_tog_we ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0H_HOST_DATA_TOG_WE_MASK; } static __INLINE void MSS_USBH_CIF_cep_set_data_tog ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= CSR0H_HOST_DATA_TOG_MASK; } /*-------------------------------------------------------------------------*//** FIFOx register related APIs */ static __INLINE void MSS_USBH_CIF_load_tx_fifo(mss_usb_ep_num_t ep_num, void * in_data, uint32_t length) { uint32_t idx; uint32_t* temp; uint8_t* temp_8bit; uint16_t words = length / 4; temp =in_data; temp_8bit = in_data; for(idx = 0u; idx < words; ++idx) { USB->FIFO[ep_num].WORD.VALUE = (uint32_t)temp[idx]; } for(idx = (length - (length % 4)); idx < length; ++idx) { USB->FIFO[ep_num].BYTE.VALUE = (uint8_t)temp_8bit[idx]; } } static __INLINE void MSS_USBH_CIF_read_rx_fifo(mss_usb_ep_num_t ep_num, void * out_data, uint32_t length) { uint32_t idx; uint32_t* temp; uint8_t* temp_8bit; uint16_t words = length / 4; temp = out_data; temp_8bit = out_data; for(idx = 0u; idx < words; ++idx) { temp[idx] = USB->FIFO[ep_num].WORD.VALUE; } for(idx = (length - (length % 4u)); idx < length; ++idx) { temp_8bit[idx] = USB->FIFO[ep_num].BYTE.VALUE; } } /*-------------------------------------------------------------------------*//** TXFUNCADDR register related APIs */ static __INLINE void MSS_USBH_CIF_tx_ep_set_target_func_addr ( mss_usb_ep_num_t ep_num, uint8_t addr ) { /* * Device number of the target - initially zero, then determined by * enumeration process. */ USB->TAR[ep_num].TX_FUNC_ADDR = (addr & 0x7Fu); } /*-------------------------------------------------------------------------*//** TYPE0 register related APIs */ static __INLINE void MSS_USBH_CIF_cep_set_type0_reg ( mss_usb_device_speed_t speed ) { USB->ENDPOINT[MSS_USB_CEP].TX_TYPE = (speed << TYPE0_HOST_MP_TARGET_SPEED_SHIFT); } static __INLINE mss_usb_device_speed_t MSS_USBH_CIF_cep_get_type0_reg ( void ) { return ((mss_usb_device_speed_t)(USB->ENDPOINT[MSS_USB_CEP].TX_TYPE >> TYPE0_HOST_MP_TARGET_SPEED_SHIFT)); } static __INLINE void MSS_USBH_CIF_rx_ep_set_reqpkt ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRL_HOST_EPN_IN_PKT_REQ_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_clr_reqpkt ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRL_HOST_EPN_IN_PKT_REQ_MASK; } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_reqpkt ( mss_usb_ep_num_t ep_num ) { return((USB->ENDPOINT[ep_num].RX_CSR &RXCSRL_HOST_EPN_IN_PKT_REQ_MASK)? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif #endif /* __MSS_USB_HOST_CIF_H_ */ mss_usb_host_hid.c000066400000000000000000000510721432224323300404330ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBH-HID class driver. * * This file implements Host side HID class specific initialization * and request handling. * * SVN $Revision$ * SVN $Date$ */ #include "mss_usb_host_hid.h" #include "mss_usb_host.h" #include "mss_usb_std_def.h" #include #include #include "mss_assert.h" #include "mss_plic.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /***************************************************************************//** Constant values internally used by USBH-HID driver. */ #define MSS_USBH_HID_CLASS_ID 0x03u #define MSS_USBH_HID_SUBCLASS_ID 0x01u #define MSS_USBH_HID_PROTOCOL_ID 0x02u #define MSS_USBH_HID_DRIVER_ID (uint32_t)((MSS_USBH_HID_CLASS_ID << 16) |\ (MSS_USBH_HID_SUBCLASS_ID << 8)|\ (MSS_USBH_HID_PROTOCOL_ID) ) #define USBH_HID_INTR_RX_PIPE MSS_USB_RX_EP_1 #define USBH_HID_INTR_TX_PIPE_FIFOADDR 0x100u #define USBH_HID_INTR_RX_PIPE_FIFOADDR 0x300u #define USBH_HID_INTR_TX_PIPE_FIFOSZ 0x40u #define USBH_HID_INTR_RX_PIPE_FIFOSZ 0x40u #define USBH_HID_DESC_SIZE 9 #define USBH_HID_DESC 0x21 #define USBH_HID_REPORT_DESC 0x22 #define USBH_HID_SET_IDLE 0x0A #define HID_MIN_POLL 10 #define HC_PID_DATA0 0 #define HC_PID_DATA2 1 #define HC_PID_DATA1 2 #define HC_PID_SETUP 3 /* States for HID State Machine */ typedef enum { HID_IDLE= 0, HID_SEND_DATA, HID_BUSY, HID_GET_DATA, HID_READ_DATA, HID_WAIT_READ_DATA, HID_SYNC, HID_POLL, HID_ERROR, } HID_State; typedef struct USBH_HIDDescriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t bcdHID; /* indicates what endpoint this descriptor is * describing */ uint8_t bCountryCode; /* specifies the transfer type. */ uint8_t bNumDescriptors; /* specifies the transfer type. */ uint8_t bReportDescriptorType;/* Maximum Packet Size this endpoint is * capable of sending or receiving */ uint16_t wItemLength; /* is used to specify the polling interval * of certain transfers. */ } USBH_HIDDesc_TypeDef_t; USBH_HIDDesc_TypeDef_t USBH_HID_Desc; #pragma data_alignment = 4 uint8_t g_hid_report[50] = {0}; volatile uint8_t toggle_in = 0; HID_State HID_Machine_state= HID_IDLE; volatile uint8_t next = 0; volatile uint8_t USBH_HID_RX_buffer[10] = {0x00}; /***************************************************************************//** Types internally used by USBH-HID driver. */ typedef struct { uint8_t num; uint16_t maxpktsz; uint16_t desclen; } tdev_ep_t; /***************************************************************************//** Private functions declarations for USBH-HID driver. */ static volatile uint8_t g_usbh_hid_alloc_event = 0u; static volatile uint8_t g_usbh_hid_cep_event = 0u; static volatile uint8_t g_usbh_hid_tx_event = 0u; static volatile uint8_t g_usbh_hid_rx_event = 0u; static uint8_t g_hid_tdev_addr = 0u; static mss_usb_state_t hid_tdev_state = MSS_USB_NOT_ATTACHED_STATE; static uint8_t g_hid_conf_desc[34] = {0}; static tdev_ep_t g_tdev_in_ep = {0}; static volatile mss_usbh_hid_state_t g_hid_state = USBH_HID_IDLE; static mss_usbh_hid_err_code_t g_hidh_error_code = USBH_HID_NO_ERROR; static mss_usbh_hid_user_cb_t* g_hidh_user_cb; static uint8_t usbh_hid_allocate_cb(uint8_t tdev_addr); static uint8_t usbh_hid_release_cb(uint8_t tdev_addr); static uint8_t usbh_hid_cep_done_cb(uint8_t tdev_addr, uint8_t status, uint32_t count); static uint8_t usbh_hid_tx_complete_cb(uint8_t tdev_addr, uint8_t status, uint32_t count); static uint8_t usbh_hid_rx_cb(uint8_t tdev_addr, uint8_t status, uint32_t count); static mss_usbh_hid_err_code_t MSS_USBH_HID_validate_class_desc(uint8_t* p_cd); static mss_usbh_hid_err_code_t MSS_USBH_HID_extract_tdev_ep_desc(void); static void USBH_HID_Handle(void); /***************************************************************************//** Definition of Class call-back functions used by USBH driver. */ mss_usbh_class_cb_t hid_class = { MSS_USBH_HID_DRIVER_ID, usbh_hid_allocate_cb, usbh_hid_release_cb, usbh_hid_cep_done_cb, usbh_hid_tx_complete_cb, usbh_hid_rx_cb, 0 }; /******************************************************************************* * EXPORTED API Functions ******************************************************************************/ /****************************************************************************** * See mss_usb_host_hid.h for details of how to use this function. */ void MSS_USBH_HID_init ( mss_usbh_hid_user_cb_t* user_sb ) { g_hid_state = USBH_HID_IDLE; memset(g_hid_conf_desc, 0u, sizeof(g_hid_conf_desc)); g_tdev_in_ep.maxpktsz = 0u; g_tdev_in_ep.num = 0u; g_hid_tdev_addr = 0u; g_hidh_user_cb = user_sb; HID_Machine_state= HID_IDLE; } /****************************************************************************** * See mss_usb_host_hid.h for details of how to use this function. */ void* MSS_USBH_HID_get_handle ( void ) { return((void*)&hid_class); } /****************************************************************************** * See mss_usb_host_hid.h for details of how to use this function. */ void MSS_USBH_HID_task ( void ) { uint8_t std_req_buf[USB_SETUP_PKT_LEN] = {0}; static volatile uint32_t wait_mili = 0u; switch (g_hid_state) { case USBH_HID_IDLE: if (g_usbh_hid_alloc_event) { g_usbh_hid_alloc_event = 0; g_hid_state = USBH_HID_GET_CLASS_DESCR; } break; case USBH_HID_GET_CLASS_DESCR: /* Read all the User Configuration descripter, HID descripter, * Interface and Endpoint descriptor in one go instaed of reading * each descripter individually. * May seperated it after completing implementation * #define USB_CONFIGURATION_DESC_SIZE 9 * #define USB_HID_DESC_SIZE 9 * #define USB_INTERFACE_DESC_SIZE 9 * #define USB_ENDPOINT_DESC_SIZE 7 */ hid_tdev_state = MSS_USBH_get_tdev_state(g_hid_tdev_addr); if (MSS_USB_ADDRESS_STATE == hid_tdev_state) { mss_usb_ep_state_t cep_st; cep_st = MSS_USBH_get_cep_state(); if (MSS_USB_CEP_IDLE == cep_st) { MSS_USBH_configure_control_pipe(g_hid_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, /*stringID*/ 34); g_hid_state = USBH_HID_WAIT_GET_CLASS_DESCR; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_hid_conf_desc, USB_STD_REQ_DATA_DIR_IN, 34); } } break; case USBH_HID_WAIT_GET_CLASS_DESCR: if (g_usbh_hid_cep_event) { mss_usbh_hid_err_code_t res = USBH_HID_NO_ERROR; g_usbh_hid_cep_event = 0u; res = MSS_USBH_HID_validate_class_desc(0); if (res == 0u) { g_hid_state = USBH_HID_SET_CONFIG; } else { g_hid_state = USBH_HID_ERROR; g_hidh_error_code = res; } res = MSS_USBH_HID_extract_tdev_ep_desc(); if (res == 0u) { g_hid_state = USBH_HID_SET_CONFIG; } else { g_hid_state = USBH_HID_ERROR; g_hidh_error_code = res; } } break; case USBH_HID_SET_CONFIG: if (0 != g_hidh_user_cb->hidh_valid_config) { g_hidh_user_cb->hidh_valid_config(); } memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); std_req_buf[1] = USB_STD_REQ_SET_CONFIG; std_req_buf[2] = g_hid_conf_desc[5]; g_hid_state = USBH_HID_WAIT_SET_CONFIG; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_hid_conf_desc, USB_STD_REQ_DATA_DIR_IN, 0u); break; case USBH_HID_WAIT_SET_CONFIG: if (g_usbh_hid_cep_event) { g_usbh_hid_cep_event = 0; wait_mili = MSS_USBH_get_milis(); g_hid_state = USBH_HID_WAIT_DEV_SETTLE; } break; case USBH_HID_WAIT_DEV_SETTLE: /* After SET_CONFIG command, we must give time for device to settle * down as per spec*/ if ((MSS_USBH_get_milis() - wait_mili) > 60) { g_hid_state = USBH_HID_REQ_GET_HID_DESC; } break; case USBH_HID_REQ_GET_HID_DESC: { for (uint32_t i = 0; i < sizeof(g_hid_conf_desc); i++) { g_hid_conf_desc[i] = 0; } memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_INTERFACE, USB_STD_REQ_GET_DESCRIPTOR, USBH_HID_DESC, 0, /*stringID*/ USBH_HID_DESC_SIZE); g_hid_state = USBH_HID_WAIT_GET_HID_DESC; MSS_USBH_start_control_xfr(std_req_buf,(uint8_t*)&USBH_HID_Desc, USB_STD_REQ_DATA_DIR_IN, 9); } break; case USBH_HID_WAIT_GET_HID_DESC: if (g_usbh_hid_cep_event) { mss_usbh_hid_err_code_t res = USBH_HID_NO_ERROR; g_usbh_hid_cep_event = 0u; g_hid_state = USBH_HID_REQ_GET_REPORT_DESC; } break; case USBH_HID_REQ_GET_REPORT_DESC: MSS_USBH_configure_control_pipe(g_hid_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_INTERFACE, USB_STD_REQ_GET_DESCRIPTOR, USBH_HID_REPORT_DESC, 0, /*stringID*/ USBH_HID_Desc.wItemLength); g_hid_state = USBH_HID_WAIT_REQ_GET_REPORT_DESC; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_hid_report, USB_STD_REQ_DATA_DIR_IN, USBH_HID_Desc.wItemLength); break; case USBH_HID_WAIT_REQ_GET_REPORT_DESC: if (g_usbh_hid_cep_event) { mss_usbh_hid_err_code_t res = USBH_HID_NO_ERROR; g_usbh_hid_cep_event = 0u; g_hid_state = USBH_HID_REQ_SET_IDLE; } break; case USBH_HID_REQ_SET_IDLE: memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_OUT, USB_CLASS_REQUEST, USB_STD_REQ_RECIPIENT_INTERFACE, USBH_HID_SET_IDLE, 0, 0, /*stringID*/ 0); g_hid_state = USBH_HID_WAIT_REQ_SET_IDLE; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_hid_report, USB_STD_REQ_DATA_DIR_IN, 0); break; case USBH_HID_WAIT_REQ_SET_IDLE: if (g_usbh_hid_cep_event) { mss_usbh_hid_err_code_t res = USBH_HID_NO_ERROR; g_usbh_hid_cep_event = 0u; g_hid_state = USBH_HID_DEVICE_READY; if (0 != g_hidh_user_cb->hidh_tdev_ready) { g_hidh_user_cb->hidh_tdev_ready(); } } break; case USBH_HID_REQ_SET_PROTOCOL: memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); std_req_buf[0] = 0x21; std_req_buf[1] = 0x0B; std_req_buf[2] = 0x00; std_req_buf[3] = 0x01; std_req_buf[4] = 0x00; std_req_buf[5] = 0x00; std_req_buf[6] = 0x00; std_req_buf[7] = 0x00; g_hid_state = USBH_HID_WAIT_REQ_SET_PROTOCOL; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_hid_report, USB_STD_REQ_DATA_DIR_IN, 0); break; case USBH_HID_WAIT_REQ_SET_PROTOCOL: if (g_usbh_hid_cep_event) { mss_usbh_hid_err_code_t res = USBH_HID_NO_ERROR; g_usbh_hid_cep_event = 0u; g_hid_state = USBH_HID_REQ_SET_PROTOCOL; } break; case USBH_HID_DEVICE_READY: USBH_HID_Handle(); break; default: { ASSERT(0); /*Reset recovery should be tried.*/ } break; } } /******************************************************************************* * See mss_usb_host_hid.h for details of how to use this function. */ mss_usbh_hid_state_t MSS_USBH_HID_get_state ( void ) { return (g_hid_state); } /******************************************************************************* * Internal Functions ******************************************************************************/ /* This Call-back function is executed when the USBH-HID driver is allocated to the attached device by USBH driver. */ uint8_t usbh_hid_allocate_cb ( uint8_t tdev_addr ) { g_hid_tdev_addr = tdev_addr; g_usbh_hid_alloc_event = 1u; return (USB_SUCCESS); } /* This Call-back function is executed when the USBH-HID driver is released from the attached device by USBH driver. */ uint8_t usbh_hid_release_cb ( uint8_t tdev_addr ) { g_hid_state = USBH_HID_IDLE; memset(g_hid_conf_desc, 0u, sizeof(g_hid_conf_desc)); g_tdev_in_ep.maxpktsz = 0u; g_tdev_in_ep.num = 0u; g_hid_tdev_addr = 0u; MSS_USB_CIF_dma_clr_ctrlreg(MSS_USB_DMA_CHANNEL2); MSS_USB_CIF_dma_clr_ctrlreg(MSS_USB_DMA_CHANNEL1); if (0 != g_hidh_user_cb->hidh_driver_released) { g_hidh_user_cb->hidh_driver_released(); } return (USB_SUCCESS); } /* This Call-back function is executed when the control transfer initiated by this driver is complete. */ uint8_t usbh_hid_cep_done_cb ( uint8_t tdev_addr, uint8_t status, uint32_t count ) { g_usbh_hid_cep_event = status; return (USB_SUCCESS); } /* This Call-back function is executed when the data OUT transfer initiated by this driver is complete. */ uint8_t usbh_hid_tx_complete_cb ( uint8_t tdev_addr, uint8_t status, uint32_t count ) { g_usbh_hid_tx_event = 1; return (USB_SUCCESS); } /* This Call-back function is executed when the data IN transfer initiated by this driver is complete. */ uint8_t usbh_hid_rx_cb ( uint8_t tdev_addr, uint8_t status, uint32_t count ) { if (0 == status) { g_usbh_hid_rx_event = 1u; } else { if (MSS_USB_EP_NAK_TOUT & status) { /* Device responding with NAKs. Retry*/ g_hid_state = USBH_HID_DEVICE_RETRY; } else { ASSERT(0);/* Handling any other error. Not yet supported */ } } return (USB_SUCCESS); } /* This function validates the HID class descriptors. */ mss_usbh_hid_err_code_t MSS_USBH_HID_validate_class_desc ( uint8_t* p_cd ) { return (USBH_HID_NO_ERROR); } /* This function extract the endpoint information from the Config Descriptor. */ mss_usbh_hid_err_code_t MSS_USBH_HID_extract_tdev_ep_desc ( void ) { /* FirstEP Attributes Not INTR. bInterfaceclass For HID value should be 0x03 */ if (!(g_hid_conf_desc[30u] & USB_EP_DESCR_ATTR_INTR)) { return (USBH_HID_WRONG_DESCR); } /* TdevEP is IN type for HID class */ if (g_hid_conf_desc[29u] & USB_STD_REQ_DATA_DIR_MASK) { g_tdev_in_ep.num = (g_hid_conf_desc[29u] & 0x7fu); g_tdev_in_ep.maxpktsz = (uint16_t)((g_hid_conf_desc[32u] << 8u) | (g_hid_conf_desc[31u])); g_tdev_in_ep.desclen = (uint16_t)((g_hid_conf_desc[26u] << 8u) | (g_hid_conf_desc[25u])); } else { return (USBH_HID_WRONG_DESCR); } return (USBH_HID_NO_ERROR); } /* This function read the report from the hid device. */ static void USBH_HID_Handle(void) { static uint32_t wait_mili = 0; switch (HID_Machine_state) { case HID_IDLE: HID_Machine_state = HID_GET_DATA; MSS_USBH_configure_in_pipe(g_hid_tdev_addr, USBH_HID_INTR_RX_PIPE, g_tdev_in_ep.num, USBH_HID_INTR_RX_PIPE_FIFOADDR, USBH_HID_INTR_RX_PIPE_FIFOSZ, g_tdev_in_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL2, MSS_USB_XFR_INTERRUPT, ADD_ZLP_TO_XFR, 32768); HID_Machine_state = HID_READ_DATA; break; case HID_READ_DATA: MSS_USBH_read_in_pipe(g_hid_tdev_addr, USBH_HID_INTR_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, (uint8_t*)&USBH_HID_RX_buffer, g_tdev_in_ep.maxpktsz); HID_Machine_state = HID_POLL; wait_mili = MSS_USBH_get_milis(); break; case HID_POLL: if ((MSS_USBH_get_milis() - wait_mili) > HID_MIN_POLL) { HID_Machine_state = HID_WAIT_READ_DATA; } break; case HID_WAIT_READ_DATA: if (g_usbh_hid_rx_event) { g_usbh_hid_rx_event = 0; HID_Machine_state = HID_READ_DATA; if (0 != g_hidh_user_cb->hidh_decode) { g_hidh_user_cb->hidh_decode((uint8_t*)&USBH_HID_RX_buffer); } } break; default: break; } } #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif mss_usb_host_hid.h000066400000000000000000000357541432224323300404510ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Microchip PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBH-HID class driver. * * USBH-HID driver public API. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS USB driver (USBH-HID) ============================================================================== Introduction ============================================================================== The Human Interface Devices host driver implements the USB host controller as per the USB HID class specified by the USB-IF. This driver enables easy detection and data transfers with the attached USB HID devices. The HID Class is used for low bandwidth data exchange. This driver implements the HID class using USB Interrupt Transfer. One Control and one BULK IN endpoints are used to implement HID class. This driver uses the USBH driver interface functions to implement the USB HID host. ============================================================================== Hardware Flow Dependencies ============================================================================== The configuration of USB Device mode features of the MSS USB is covered by this software stack. There are no dependencies on the hardware flow when configuring the PolarFire SoC MSS USB. The base address and register addresses are defined in this driver as constants. The interrupt number assignment for the MSS USB peripherals are defined as constants in the MPFS HAL. You must ensure that the latest MPFS HAL is included in the project settings of the SoftConsole tool chain and that it is generated into your project. ============================================================================== Theory of Operation ============================================================================== The following steps are involved in the operation of USBH-HID driver: - Configuration - Initialization - Application call-back interface - Class Specific requests - Data transfer -------------------------------- Configuration -------------------------------- The MSS USB driver must first be configured in the USB Host mode using the MSS_USB_HOST_MODE to use this driver. No other configuration is necessary. -------------------------------- Initialization -------------------------------- The HID class driver must be initialized using the MSS_USBH_HID_init() function. A pointer to the structure of type mss_usbh_hid_user_cb_t must be provided as parameter with this function. This pointer is used to call the application call-back functions by the USBH-HID driver. These call-back functions can be used by the application to provide error/status messages to the user or for performing application specific handling of the events. -------------------------------- Application call-back interface -------------------------------- Application call-back interface After the USBH-Class driver is assigned to the attached device by the USBH driver, as indicated by usbh_class_allocate call-back, this driver can take over the communication with the attached device. This driver will then extend the enumeration process by requesting the class specific information from the device. During this process it will also call the call-back functions to indicate the progress of the enumeration process. These call-back functions must be implemented by application. These call-back functions can be used to take application specific action on specific event or can be used to provide error/status messages to the user. A type mss_usbh_hid_user_cb_t is provided by this driver which has all these call-back functions as its elements. Implementing these call-back functions is optional. -------------------------------- Data transfer -------------------------------- All data is exchanged between the host and the device in the form of reports. The format of the report is defined by the report descriptor defined by the device based on device need. USB HOST will request the report descriptor using interrupt transfers. Every HID device needs to have one input report in its report descriptor. An interrupt IN endpoint is required for reading reports from USB device. The interrupt OUT endpoint is optional. The HID class uses Interrupt Transfer mode, a maximum of 64 bytes can be transferred in a single frame (i.e., 64 Kbyte/s per endpoint when operating in Full-Speed mode).The USB Host driver needs to make sure that the data is polled periodically. This driver only needs to perform the USB IN transfers on the Interrupt endpoint. The period at which this transfer is repeated is defined by the device endpoint descriptor during the enumeration process. The application must call the USBH_HID_Handle() function periodically to read the report from the HID device. The application must register the call back function which will be called by the USBH driver when the report is received. *//*=========================================================================*/ #ifndef __MSS_USB_HOST_HID_H_ #define __MSS_USB_HOST_HID_H_ #include #include "mss_usb_config.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /*-------------------------------------------------------------------------*//** Types exported from USBH-HID driver ============================ */ /*-------------------------------------------------------------------------*//** The mss_usbh_HID_err_code_t provides a type to identify the error occurred during retrieving configuration and other class specific descriptors from the attached HID class device. This type can be used with hidh_error call-back function element of mss_usbh_hid_user_cb_t type to identify the exact cause of the error. The meaning of the constants is as described below | Constant | Description | |-------------------------------|----------------------------------------------| | USBH_HID_EP_NOT_VALID | Indicates that the endpoint information | | | retrieved from the attached device was not | | | consistent with the HID class. | | | | | USBH_HID_CLR_CEP_STALL_ERROR | Indicates that the host controller was not | | | able to clear the stall condition on the | | | attached device even after multiple retries. | */ typedef enum mss_usbh_hid_err_code { USBH_HID_NO_ERROR = 0, USBH_HID_EP_NOT_VALID = -1, USBH_HID_CLR_CEP_STALL_ERROR = -2, USBH_HID_WRONG_DESCR = -3, } mss_usbh_hid_err_code_t; /*-------------------------------------------------------------------------*//** The mss_usbh_HID_state_t provides a type for the states of operation of the USBH-HID driver. Most of the states are internally used by the USBH-HID driver during the enumeration process. The USBH-HID driver is ready to perform data transfers with the attached device when the driver is in state USBH_HID_DEVICE_READY. The USBH_HID_ERROR state indicates that the error was detected either during enumeration or during the normal data transfer operations with the attached device even after retries. */ typedef enum mss_usbh_hid_state { USBH_HID_IDLE, USBH_HID_GET_CLASS_DESCR, USBH_HID_WAIT_GET_CLASS_DESCR, USBH_HID_SET_CONFIG, USBH_HID_WAIT_SET_CONFIG, USBH_HID_WAIT_DEV_SETTLE, USBH_HID_REQ_GET_REPORT_DESC, USBH_HID_WAIT_REQ_GET_REPORT_DESC, USBH_HID_REQ_SET_IDLE, USBH_HID_WAIT_REQ_SET_IDLE, USBH_HID_REQ_GET_HID_DESC, USBH_HID_WAIT_GET_HID_DESC, USBH_HID_DEVICE_READY, USBH_HID_REQ_SET_PROTOCOL, USBH_HID_WAIT_REQ_SET_PROTOCOL, USBH_HID_DEVICE_RETRY, USBH_HID_ERROR } mss_usbh_hid_state_t; /*------------------------Public data structures-----------------------------*/ /*-------------------------------- USBH-HID----------------------------------*/ /*----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** The mss_usbh_hid_user_cb_t provides the prototype for all the call-back functions which must be implemented by the user application. The user application must define and initialize a structure of this type and provide the address of that structure as parameter to the MSS_USBH_HID_init() function. hidh_valid_config The function pointed by the hidh_valid_config function pointer will be called to indicate that a valid HID class configuration was found on the attached device and the device is configured for this configuration. hidh_tdev_ready The function pointed by the hidh_tdev_ready function pointer is called when this driver is able to retrieve all the HID class specific information (including sector size and sector number) from the attached device and is ready to perform the data transfers. hidh_driver_released The function pointed by the hidh_driver_released function pointer is called to indicate to the application that this driver is released by the USBH driver. This could be either because the HID class device is now detached or there is permanent error with the USBH driver. hidh_error The function pointed by the hidh_error function pointer is called to indicate that there was an error while retrieving the class specific descriptor information from the attached HID class device. The error_code parameter indicates the exact cause of the error. hidh_decode The function pointed by the hidh_decode function pointer is called to indicate that there is a new report received from the attached HID class device. The data parameter indicates the location of received data present in the internal buffer. */ typedef struct mss_usbh_hid_user_cb { void (*hidh_valid_config)(void); void (*hidh_tdev_ready)(void); void (*hidh_driver_released)(void); void (*hidh_error)(int8_t error_code); void (*hidh_decode)(uint8_t *data); } mss_usbh_hid_user_cb_t; /*----------------------------------------------------------------------------*/ /*----------------------MSS USBH-HID Public APIs------------------------------*/ /*----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** The MSS_USBH_HID_init() function must be used by the application to initialize the USBH-HID driver. This function must be called before any other function of the USBH-HID driver. @param user_cb The user_cb parameter provides a pointer to the structure of type mss_usbh_hid_user_cb_t. This pointer is used to call the application call-back functions by the USBH-HID driver. These call-back functions can be used by the application to provide error/status messages to the user or for performing the application specific handling of the events. @return This function does not return a value. Example: @code MSS_USBH_init(&MSS_USBH_user_cb); MSS_USBH_HID_init(&MSS_USBH_HID_user_cb); MSS_USBH_register_class_driver(MSS_USBH_HID_get_handle()); @endcode */ void MSS_USBH_HID_init ( mss_usbh_hid_user_cb_t* user_sb ); /***************************************************************************//** The MSS_USBH_HID_task() function is the main task of the USBH-HID driver. This function monitors the events from the USBH driver as well as the user application and makes decisions. This function must be called repeatedly by the application to allow the USBH-HID driver to perform the housekeeping tasks.A timer/scheduler can be used to call this function at regular intervals or it can be called from the main continuous foreground loop of the application. @param This function does not take any parameters. @return This function does not return a value. Example: @code @endcode */ void MSS_USBH_HID_task ( void ); /***************************************************************************//** The MSS_USBH_HID_get_handle() function must be used by the application to get the handle from the USBH-HID driver. This handle must then be used to register this driver with the USBH driver. @param This function does not take any parameters. @return This function returns a pointer to the class-handle structure. Example: @code MSS_USBH_init(&MSS_USBH_user_cb); MSS_USBH_HID_init(&MSS_USBH_HID_user_cb); MSS_USBH_register_class_driver(MSS_USBH_HID_get_handle()); @endcode */ void* MSS_USBH_HID_get_handle ( void ); /***************************************************************************//** The MSS_USBH_HID_get_state() function can be used to find out the current state of the USBH-HID driver. This information can be used by the application to check the readiness of the USBH-HID driver to start the data transfers. The USBH-HID driver can perform data transfers only when it is in the USBH_HID_DEVICE_READY state. @param This function does not take any parameters. @return This function returns a value of type mss_usbh_hid_state_t indicating the current state of the USBH-HID driver. Example: @code if (USBH_HID_DEVICE_READY == MSS_USBH_HID_get_state()) { *result = MSS_USBH_HID_get_sector_count(); return RES_OK; } else if (USBH_HID_DEVICE_READY < MSS_USBH_HID_get_state()) { *result = 0u; return RES_NOTRDY; } @endcode */ mss_usbh_hid_state_t MSS_USBH_HID_get_state ( void ); #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif #endif /* __MSS_USB_HOST_HID_H_ */ mss_usb_host_msc.c000066400000000000000000001271611432224323300404540ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBH-MSC class driver. * * * This file implements Host side MSC class specific initialization * and request handling. * * V2.4 NAKTIMEOUT error handling. * V2.4 Naming convention change, other cosmetic changes. * V2.3 Host performance improvement changes * * SVN $Revision$ * SVN $Date$ */ #include "mss_usb_host_msc.h" #include "mss_usb_host.h" #include "mss_usb_std_def.h" #include #include #include "mss_assert.h" #include "mss_plic.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /***************************************************************************//** Constant values internally used by USBH-MSC driver. */ #define MSS_USBH_MSC_CLASS_ID 0x08u #define MSS_USBH_MSC_SUBCLASS_ID 0x06u #define MSS_USBH_MSC_PROTOCOL_ID 0x50u #define MSS_USBH_MSC_DRIVER_ID (uint32_t)((MSS_USBH_MSC_CLASS_ID << 16) |\ (MSS_USBH_MSC_SUBCLASS_ID << 8)|\ (MSS_USBH_MSC_PROTOCOL_ID) ) #define SCSI_COMMAND_PASSED 0x01u #define SCSI_COMMAND_FAILED 0x02u #define SCSI_COMMAND_PHASE_ERR 0x03u #define USBH_MSC_BULK_TX_PIPE MSS_USB_TX_EP_1 #define USBH_MSC_BULK_RX_PIPE MSS_USB_RX_EP_1 #define USBH_MSC_BULK_TX_PIPE_FIFOADDR 0x100u #define USBH_MSC_BULK_RX_PIPE_FIFOADDR 0x300u #define USBH_MSC_BULK_TX_PIPE_FIFOSZ 0x200u #define USBH_MSC_BULK_RX_PIPE_FIFOSZ 0x200u /***************************************************************************//** Types internally used by USBH-MSC driver. */ typedef enum { MSC_BOT_IDLE, MSC_BOT_COMMAND_PHASE, MSC_BOT_DATA_PHASE, MSC_BOT_STATUS_PHASE, MSC_BOT_STATUS_WAITCOMPLETE, MSC_BOT_ERROR }g_msc_bot_state_t; typedef struct { uint8_t num; uint16_t maxpktsz; } msd_tdev_ep_t; typedef struct { uint8_t* cbuf; /* always31bytes */ uint8_t* dbuf; uint32_t dbuf_len; uint8_t* sbuf; /* statusalways 13bytes */ uint8_t volatile st; } scsi_command_t; /***************************************************************************//** Private functions declarations for USBH-MSC driver. */ static scsi_command_t g_scsi_command = {0}; static volatile uint8_t g_usbh_msc_alloc_event = 0u; //static uint8_t g_usbh_msc_release_event = 0u; // unused static volatile uint8_t g_usbh_msc_cep_event = 0u; static volatile uint8_t g_usbh_msc_tx_event = 0u; static volatile uint8_t g_usbh_msc_rx_event = 0u; #if defined(__GNUC__) static msd_cbw_t g_bot_cbw __attribute__ ((aligned (4))) = {0}; static uint8_t g_bot_csw[13] __attribute__ ((aligned (4))) = {0}; /* Store Inquiry response */ static uint8_t g_bot_inquiry[36] __attribute__ ((aligned (4))) = {0}; /* Store Read_capacity response */ static uint8_t g_bot_readcap[8] __attribute__ ((aligned (4)))= {0}; #elif defined(__ICCARM__) #pragma data_alignment = 4 static msd_cbw_t g_bot_cbw = {0}; static uint8_t g_bot_csw[13] = {0}; static uint8_t g_bot_inquiry[36] = {0}; static uint8_t g_bot_readcap[8] = {0}; #elif defined(__CC_ARM) __align(4) static msd_cbw_t g_bot_cbw = {0}; __align(4) static uint8_t g_bot_csw[13] = {0}; __align(4) static uint8_t g_bot_inquiry[36] = {0}; __align(4) static uint8_t g_bot_readcap[8] = {0}; #endif static volatile g_msc_bot_state_t g_msc_bot_state = MSC_BOT_IDLE; static uint8_t g_msd_tdev_addr = 0u; static mss_usb_state_t msd_tdev_state = MSS_USB_NOT_ATTACHED_STATE; static uint8_t g_msd_conf_desc[32] = {0}; /* Data type changed from uint8_t since ASSERT in start_control_xfr() */ static uint32_t g_tdev_max_lun_idx = 0u; static msd_tdev_ep_t g_tdev_in_ep = {0}; static msd_tdev_ep_t g_tdev_out_ep = {0}; static volatile mss_usbh_msc_state_t g_msc_state = USBH_MSC_IDLE; static mss_usbh_msc_err_code_t g_msch_error_code = USBH_MSC_NO_ERROR; static mss_usbh_msc_user_cb_t* g_msch_user_cb; static uint8_t usbh_msc_allocate_cb(uint8_t tdev_addr); static uint8_t usbh_msc_release_cb(uint8_t tdev_addr); static uint8_t usbh_msc_cep_done_cb(uint8_t tdev_addr, uint8_t status, uint32_t count); static uint8_t usbh_msc_tx_complete_cb(uint8_t tdev_addr, uint8_t status, uint32_t count); static uint8_t usbh_msc_rx_cb(uint8_t tdev_addr, uint8_t status, uint32_t count); static mss_usbh_msc_err_code_t MSS_USBH_MSC_validate_class_desc(uint8_t* p_cd); static mss_usbh_msc_err_code_t MSS_USBH_MSC_extract_tdev_ep_desc(void); static void usbh_msc_construct_class_req(uint8_t* buf, uint8_t req, uint8_t bInterfaceNumber); /***************************************************************************//** Definition of Class call-back functions used by USBH driver. */ mss_usbh_class_cb_t msd_class = { MSS_USBH_MSC_DRIVER_ID, usbh_msc_allocate_cb, usbh_msc_release_cb, usbh_msc_cep_done_cb, usbh_msc_tx_complete_cb, usbh_msc_rx_cb, 0 }; /******************************************************************************* * EXPORTED API Functions ******************************************************************************/ /****************************************************************************** * See mss_usb_host_msc.h for details of how to use this function. */ void MSS_USBH_MSC_init ( mss_usbh_msc_user_cb_t* user_sb ) { g_msc_state = USBH_MSC_IDLE; g_msc_bot_state = MSC_BOT_IDLE; g_tdev_max_lun_idx = 0u; memset(g_msd_conf_desc, 0u, sizeof(g_msd_conf_desc)); memset(g_bot_inquiry, 0u, sizeof(g_bot_inquiry)); memset(&g_bot_csw, 0u, sizeof(g_bot_csw)); g_tdev_in_ep.maxpktsz = 0u; g_tdev_in_ep.num = 0u; g_tdev_out_ep.maxpktsz = 0u; g_tdev_out_ep.num = 0u; g_msd_tdev_addr = 0u; g_msch_user_cb = user_sb; g_scsi_command.cbuf = (uint8_t*)0; g_scsi_command.dbuf = (uint8_t*)0; g_scsi_command.sbuf = (uint8_t*)0; g_scsi_command.dbuf_len = 0u; g_scsi_command.st = 0u; memset(g_bot_readcap, 0u, sizeof(g_bot_readcap)); } /****************************************************************************** * See mss_usb_host_msc.h for details of how to use this function. */ void* MSS_USBH_MSC_get_handle ( void ) { return ((void*)&msd_class); } /****************************************************************************** * See mss_usb_host_msc.h for details of how to use this function. */ void MSS_USBH_MSC_task ( void ) { uint8_t std_req_buf[USB_SETUP_PKT_LEN] = {0}; static volatile uint32_t wait_mili = 0u; switch (g_msc_state) { case USBH_MSC_IDLE: if (g_usbh_msc_alloc_event) { g_usbh_msc_alloc_event = 0u; g_msc_state = USBH_MSC_GET_CLASS_DESCR; } break; case USBH_MSC_GET_CLASS_DESCR: msd_tdev_state = MSS_USBH_get_tdev_state(g_msd_tdev_addr); if (MSS_USB_ADDRESS_STATE == msd_tdev_state) { mss_usb_ep_state_t cep_st; cep_st = MSS_USBH_get_cep_state(); if (MSS_USB_CEP_IDLE == cep_st) { MSS_USBH_configure_control_pipe(g_msd_tdev_addr); memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); MSS_USBH_construct_get_descr_command(std_req_buf, USB_STD_REQ_DATA_DIR_IN, USB_STANDARD_REQUEST, USB_STD_REQ_RECIPIENT_DEVICE, USB_STD_REQ_GET_DESCRIPTOR, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0u, /*stringID*/ 32u);/* config_Desc_length */ g_msc_state = USBH_MSC_WAIT_GET_CLASS_DESCR; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_msd_conf_desc, USB_STD_REQ_DATA_DIR_IN, 32u); /* config_Desc_length */ } } break; case USBH_MSC_WAIT_GET_CLASS_DESCR: if (g_usbh_msc_cep_event) { mss_usbh_msc_err_code_t res = USBH_MSC_NO_ERROR; g_usbh_msc_cep_event = 0u; res = MSS_USBH_MSC_validate_class_desc(0); if (res == 0u) { g_msc_state = USBH_MSC_SET_CONFIG; } else { g_msc_state = USBH_MSC_ERROR; g_msch_error_code = res; } res = MSS_USBH_MSC_extract_tdev_ep_desc(); if (res == 0u) { g_msc_state = USBH_MSC_SET_CONFIG; } else { g_msc_state = USBH_MSC_ERROR; g_msch_error_code = res; } } break; case USBH_MSC_SET_CONFIG: if (0 != g_msch_user_cb->msch_valid_config) { g_msch_user_cb->msch_valid_config(); } memset(std_req_buf, 0u, 8*(sizeof(uint8_t))); std_req_buf[1] = USB_STD_REQ_SET_CONFIG; /* bConfigurationValue*/ std_req_buf[2] = g_msd_conf_desc[5]; g_msc_state = USBH_MSC_WAIT_SET_CONFIG; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_msd_conf_desc, USB_STD_REQ_DATA_DIR_IN, 0u); break; case USBH_MSC_WAIT_SET_CONFIG: if (g_usbh_msc_cep_event) { g_usbh_msc_cep_event = 0u; wait_mili = MSS_USBH_get_milis(); g_msc_state = USBH_MSC_WAIT_DEV_SETTLE; } break; case USBH_MSC_WAIT_DEV_SETTLE: /* After SET_CONFIG command, we must give time for device to settle * down as per spec */ if ((MSS_USBH_get_milis() - wait_mili) > 60u) { g_msc_state = USBH_MSC_GET_MAX_LUN; } break; case USBH_MSC_GET_MAX_LUN: usbh_msc_construct_class_req(std_req_buf, USB_MSC_BOT_REQ_GET_MAX_LUN, g_msd_conf_desc[11]);/* bInterfaceNum */ MSS_USBH_configure_control_pipe(g_msd_tdev_addr); g_msc_state = USBH_MSC_WAIT_GET_MAX_LUN; MSS_USBH_start_control_xfr(std_req_buf, (uint8_t*)&g_tdev_max_lun_idx, USB_STD_REQ_DATA_DIR_IN, 1u); break; case USBH_MSC_WAIT_GET_MAX_LUN: if (g_usbh_msc_cep_event) { if (MSS_USB_EP_XFR_SUCCESS == g_usbh_msc_cep_event) { g_msc_state = USBH_MSC_CONFIG_BULK_ENDPOINTS; } else if (MSS_USB_EP_STALL_RCVD == g_usbh_msc_cep_event) { /* Stall for this command means single LUN support by Target */ g_tdev_max_lun_idx = 0u; g_msc_state = USBH_MSC_CLR_CEP_STALL; /* Clear Stall using CLR_FEATURE Command */ } else { ASSERT(0); /* Invalid CEP event */ } g_usbh_msc_cep_event = 0u; } break; case USBH_MSC_CLR_CEP_STALL: { /* Std clear CEP STALL command */ uint8_t temp_buf[8u] = {0x02u, 0x01u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u}; g_msc_state = USBH_MSC_WAIT_CLR_CEP_STALL; /* clear feature Endpoint halt on Tdev Out EP */ MSS_USBH_start_control_xfr(temp_buf, (uint8_t*)&g_tdev_max_lun_idx, USB_STD_REQ_DATA_DIR_IN, 0u); break; } case USBH_MSC_WAIT_CLR_CEP_STALL: if (g_usbh_msc_cep_event) { if (MSS_USB_EP_XFR_SUCCESS == g_usbh_msc_cep_event) { g_msc_state = USBH_MSC_CONFIG_BULK_ENDPOINTS; } else if (MSS_USB_EP_STALL_RCVD == g_usbh_msc_cep_event) { g_msc_state = USBH_MSC_ERROR; g_msch_error_code = USBH_MSC_CLR_CEP_STALL_ERROR; } else { ASSERT(0);/* Invalid CEP event */ } g_usbh_msc_cep_event = 0u; } break; case USBH_MSC_CONFIG_BULK_ENDPOINTS: /* Configure BULK TX/RX Endpoints */ MSS_USBH_configure_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, /* Targeted OUTEP Num */ USBH_MSC_BULK_TX_PIPE_FIFOADDR, USBH_MSC_BULK_TX_PIPE_FIFOSZ, g_tdev_out_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL1, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR, 32768);/* Max NAKLimit value */ MSS_USBH_configure_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, /* Targeted OutEP Num */ USBH_MSC_BULK_RX_PIPE_FIFOADDR, USBH_MSC_BULK_RX_PIPE_FIFOSZ, g_tdev_in_ep.maxpktsz, 1, DMA_DISABLE, MSS_USB_DMA_CHANNEL2, MSS_USB_XFR_BULK, NO_ZLP_TO_XFR, 32768);/* Max NAKLimit value */ g_msc_state = USBH_MSC_TEST_UNIT_READY_CPHASE; break; case USBH_MSC_TEST_UNIT_READY_CPHASE: MSS_USBH_MSC_construct_cbw_cb6byte(USB_MSC_SCSI_TEST_UNIT_READY, 0u, &g_bot_cbw); MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, (uint8_t*)&g_bot_cbw, 31u); /* std_cbw_len */ g_msc_state = USBH_MSC_TEST_UNIT_READY_SPHASE; break; case USBH_MSC_TEST_UNIT_READY_SPHASE: if (g_usbh_msc_tx_event) { g_usbh_msc_tx_event = 0u; g_msc_state = USBH_MSC_TEST_UNIT_READY_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, (uint8_t*)&g_bot_csw, 13u);/* standard status msg */ } break; case USBH_MSC_TEST_UNIT_READY_WAITCOMPLETE: if (g_usbh_msc_rx_event) { g_usbh_msc_rx_event = 0u; /* decode the received status */ if (g_bot_csw[12] == 0x00u) /* PASSED */ { g_msc_state = USBH_MSC_SCSI_INQUIRY_CPHASE; } else if (g_bot_csw[12] == 0x01u) /* FAILED */ { g_msc_state = USBH_MSC_SCSI_REQSENSE_CPHASE; } else if (g_bot_csw[12] == 0x02u) { ASSERT(0); /* phase error, reset recovery required */ } } break; case USBH_MSC_SCSI_INQUIRY_CPHASE: MSS_USBH_MSC_construct_cbw_cb6byte(USB_MSC_SCSI_INQUIRY, 36u, /*standard INQUIRY response size */ &g_bot_cbw); g_msc_state = USBH_MSC_SCSI_INQUIRY_DPHASE; MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, (uint8_t*)&g_bot_cbw, 31u); /* std_cbw_len */ break; case USBH_MSC_SCSI_INQUIRY_DPHASE: if (g_usbh_msc_tx_event) { g_usbh_msc_tx_event = 0u; g_msc_state = USBH_MSC_SCSI_INQUIRY_SPHASE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_bot_inquiry, 36u);/* standard INQUIRY response size */ } break; case USBH_MSC_SCSI_INQUIRY_SPHASE: if (g_usbh_msc_rx_event) { g_usbh_msc_rx_event = 0u; g_msc_state = USBH_MSC_SCSI_INQUIRY_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, (uint8_t*)&g_bot_csw, 13u);/* standard status msg */ } break; case USBH_MSC_SCSI_INQUIRY_WAITCOMPLETE: if (g_usbh_msc_rx_event) { g_usbh_msc_rx_event = 0x0U; g_msc_state = USBH_MSC_SCSI_READ_CAPACITY_CPHASE; } break; case USBH_MSC_SCSI_REQSENSE_CPHASE: { /* This is a standard command buffer for REQUEST SENSE command */ uint8_t cbuf[] = {0x55U, 0x53U, 0x42U, 0x43U, 0x28U, 0x2EU, 0x59U, 0xAFU, 0x12U, 0x00U, 0x00U, 0x00U, 0x80U, 0x00U, 0x0CU, 0x03U, 0x00U, 0x00U, 0x00U, 0x12U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; g_msc_state = USBH_MSC_SCSI_REQSENSE_DPHASE; MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, (uint8_t*)&cbuf, 31u); /*std_cbw_len */ } break; case USBH_MSC_SCSI_REQSENSE_DPHASE: if (g_usbh_msc_tx_event) { /* standard response from device for REQUEST sense command is 18 bytes */ static uint8_t reqsense_buf[18]; g_usbh_msc_tx_event = 0u; g_msc_state = USBH_MSC_SCSI_REQSENSE_SPHASE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, reqsense_buf, 18u); } break; case USBH_MSC_SCSI_REQSENSE_SPHASE: if (g_usbh_msc_rx_event) { g_usbh_msc_rx_event = 0u; g_msc_state = USBH_MSC_SCSI_REQSENSE_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, (uint8_t*)&g_bot_csw, 13u);/* standard status msg */ } break; case USBH_MSC_SCSI_REQSENSE_WAITCOMPLETE: if (g_usbh_msc_rx_event) { g_usbh_msc_rx_event = 0u; g_msc_state = USBH_MSC_TEST_UNIT_READY_CPHASE; } break; case USBH_MSC_SCSI_READ_CAPACITY_CPHASE: MSS_USBH_MSC_construct_cbw_cb10byte(USB_MSC_SCSI_READ_CAPACITY_10, 0u, 0u, 0u, 0u, &g_bot_cbw); g_msc_state = USBH_MSC_SCSI_READ_CAPACITY_DPHASE; MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, (uint8_t*)&g_bot_cbw, 31u); /* std_cbw_len */ break; case USBH_MSC_SCSI_READ_CAPACITY_DPHASE: if (g_usbh_msc_tx_event) { g_usbh_msc_rx_event = 0u; g_msc_state = USBH_MSC_SCSI_READ_CAPACITY_SPHASE; /* standard Read Capacity response size is 8bytes. * We need this info later so keep it in g_bot_readcap */ MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_bot_readcap, 8u); } break; case USBH_MSC_SCSI_READ_CAPACITY_SPHASE: if (g_usbh_msc_rx_event) { g_usbh_msc_rx_event = 0u; g_msc_state = USBH_MSC_SCSI_READ_CAPACITY_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, (uint8_t*)&g_bot_csw, 13u);/* standard status msg */ } break; case USBH_MSC_SCSI_READ_CAPACITY_WAITCOMPLETE: if (g_usbh_msc_rx_event) { uint32_t sector_size = 0u; g_usbh_msc_rx_event = 0u; sector_size = ((g_bot_readcap[4u] << 24u) | /*sector size */ (g_bot_readcap[5u] << 16u) | (g_bot_readcap[6u] << 8u) | g_bot_readcap[7u]); if (sector_size != 512u) { g_msc_state = USBH_MSC_ERROR; g_msch_error_code = USBH_MSC_SECTOR_SIZE_NOT_SUPPORTED; } else { g_msc_state = USBH_MSC_DEVICE_READY; if (0 != g_msch_user_cb->msch_tdev_ready) { g_msch_user_cb->msch_tdev_ready(); } } } break; case USBH_MSC_DEVICE_READY: /* * The USBH-MSC driver will stay in this state. * Being in this state, the SCSI requests will be executed as * user the user makes those requests through the APIs of this driver. */ break; case USBH_MSC_ERROR: { static uint8_t error = 0u; if (0u == error) { error = 1u; if (0 != g_msch_user_cb->msch_error) { g_msch_user_cb->msch_error(g_msch_error_code); } } } break; case USBH_MSC_BOT_RETRY: { static uint32_t first_mili = 0; static uint32_t crrent_mili = 0; if (0u == first_mili) { first_mili = MSS_USBH_get_milis(); } crrent_mili = MSS_USBH_get_milis(); /* Found that the Sandisc devices are reporting NAKTIMEOUT error. * This is mostly happening when moving from DATA phase to Status * phase of the SCSI read/write command. At this stage restarting * the status phase is able to get the device to respond properly. * The NAKLIMIT is device specific. The WIndows hosts allow up to * 5Sec before declaring NAKTIMOUT. MSS USB allows to wait up to * ~4Sec. Hence waiting for another 1 Sec here hoping that the * device is recovered by then. */ if (MSC_BOT_STATUS_WAITCOMPLETE == g_msc_bot_state) { if ((crrent_mili - first_mili) >= 1000u) { first_mili = 0u; crrent_mili = 0u; MSS_USBH_abort_in_pipe(USBH_MSC_BULK_RX_PIPE); MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_scsi_command.sbuf, 13u); g_msc_state = USBH_MSC_DEVICE_READY; } } } break; default: { ASSERT(0); /*Reset recovery should be tried.*/ } break; } } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ static void usbh_msc_construct_class_req ( uint8_t* buf, uint8_t req, uint8_t bInterfaceNumber ) { /* This implementation is as per MSC class spec */ buf[0] = 0x21u; /* bmRequestType */ buf[1] = req; /* bmRequest */ buf[2] = 0x00u; buf[3] = 0x00u; /* wValue */ buf[4] = bInterfaceNumber; buf[5] = 0x00u; /* wIndex */ if (req == USB_MSC_BOT_REQ_GET_MAX_LUN) { buf[6] = 0x01u; buf[0] = 0xA1u; /* bmRequestType */ } else if (req == USB_MSC_BOT_REQ_BMS_RESET) { buf[6] = 0x00u; buf[0] = 0x21u; /* bmRequestType */ } else { ASSERT(0);/* invalid MSC class class request */ } buf[7] = 0x00u; } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ void MSS_USBH_MSC_construct_cbw_cb6byte ( uint8_t command_opcode, uint32_t data_xfr_len, msd_cbw_t* buf ) { /* This implementation is as per MSC class spec*/ /* Inquiry, Request_sense, Test_unit_ready commands (cb10 byte commands) */ memset(buf, 0u, 31*(sizeof(uint8_t))); buf->dCBWSignature = USB_MSC_BOT_CBW_SIGNATURE; buf->dCBWTag = 0x20304050U; buf->dCBWDataTransferLength = data_xfr_len; if (USB_MSC_SCSI_TEST_UNIT_READY == command_opcode) { buf->bCBWFlags = 0x00u; } else if ((USB_MSC_SCSI_INQUIRY == command_opcode) || (USB_MSC_SCSI_REQUEST_SENSE == command_opcode)) { buf->bCBWFlags = 0x80u; } else { ASSERT(0);/* invalid cb6byte command */ } buf->bCBWCBLength = 0x06u; buf->CBWCB[0] = command_opcode; buf->CBWCB[4] = data_xfr_len; } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ void MSS_USBH_MSC_construct_cbw_cb10byte ( uint8_t command_opcode, uint8_t lun, uint32_t lb_addr, uint16_t num_of_lb, uint16_t lb_size, msd_cbw_t* buf ) { /* This implementation is as per MSC class spec */ /* Read_capacity, Read10, Write10 commands (cb10 byte commands) */ memset(buf, 0u, 31*(sizeof(uint8_t))); buf->dCBWSignature = USB_MSC_BOT_CBW_SIGNATURE; buf->dCBWTag = 0x20304050U; if (USB_MSC_SCSI_WRITE_10 == command_opcode) { buf->bCBWFlags = 0x00u; /* H2D */ } else if ((USB_MSC_SCSI_READ_10 == command_opcode) || (USB_MSC_SCSI_READ_CAPACITY_10 == command_opcode)) { buf->bCBWFlags = 0x80u; /* D2H */ } buf->bCBWCBLength = 0x0Au; buf->CBWCB[0] = command_opcode; if ((USB_MSC_SCSI_READ_10 == command_opcode) || (USB_MSC_SCSI_WRITE_10 == command_opcode)) { buf->dCBWDataTransferLength = (num_of_lb * lb_size); /* Transfer length */ buf->CBWCB[1] = lun; /* Lun Number */ buf->CBWCB[2] = (uint8_t)((lb_addr >> 24) & 0xFFU); /* MSB first */ buf->CBWCB[3] = (uint8_t)((lb_addr >> 16) & 0xFFU); buf->CBWCB[4] = (uint8_t)((lb_addr >> 8) & 0xFFU); buf->CBWCB[5] = (uint8_t)(lb_addr & 0xFFU); buf->CBWCB[7] = (uint8_t)((num_of_lb >> 8) & 0xFFU); /* MSB first */ buf->CBWCB[8] = (uint8_t)(num_of_lb & 0xFFU); } else if ((USB_MSC_SCSI_READ_CAPACITY_10 == command_opcode)) { buf->dCBWDataTransferLength = 0x08u; /* Read Capacity Transfer length */ } else { ASSERT(0);/* invalid cb10byte command */ } } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ mss_usbh_msc_state_t MSS_USBH_MSC_get_state ( void ) { return(g_msc_state); } uint8_t MSS_USBH_MSC_scsi_req ( uint8_t* command_buf, /* always31bytes */ uint8_t* data_buf, uint32_t data_buf_len, uint8_t* status_buf /* status always 13bytes */ ) { g_scsi_command.cbuf = command_buf; g_scsi_command.dbuf = data_buf; g_scsi_command.dbuf_len = data_buf_len; g_scsi_command.sbuf = status_buf; g_msc_bot_state = MSC_BOT_COMMAND_PHASE; MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, g_scsi_command.cbuf, 31u); /* std_cbw_len */ return(0); } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ uint8_t MSS_USBH_MSC_is_scsi_req_complete ( void ) { return (g_scsi_command.st); } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ uint32_t MSS_USBH_MSC_get_sector_count ( void ) { /* * TODO:Check this * Read_capacity_10 command returns the Last LAB i.e. Address of the * last Logical block. Hence Number of logical blocks(sectors) is (Last LBA+1) */ return ((g_bot_readcap[0u] << 24u) | (g_bot_readcap[1u] << 16u) | (g_bot_readcap[2u] << 8u) | g_bot_readcap[3u]); } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ uint32_t MSS_USBH_MSC_get_sector_size ( void ) { /* * Return the logical block(sector) size in bytes. */ return ((g_bot_readcap[4u] << 24u) | (g_bot_readcap[5u] << 16u) | (g_bot_readcap[6u] << 8u) | g_bot_readcap[7u]); } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ int8_t MSS_USBH_MSC_read ( uint8_t* buf, uint32_t sector, uint32_t count ) { if (0u == g_scsi_command.st) { g_scsi_command.st = 1u; MSS_USBH_MSC_construct_cbw_cb10byte(USB_MSC_SCSI_READ_10, 0u, sector, count, 512u, &g_bot_cbw); MSS_USBH_MSC_scsi_req((uint8_t*)&g_bot_cbw, buf, (count*512u), (uint8_t*)&g_bot_csw); return (0); } else { return (-1); /* previous command is in progress */ } } /******************************************************************************* * See mss_usb_host_msc.h for details of how to use this function. */ int8_t MSS_USBH_MSC_write ( uint8_t* buf, uint32_t sector, uint32_t count ) { if (0u == g_scsi_command.st) { g_scsi_command.st = 1u; MSS_USBH_MSC_construct_cbw_cb10byte(USB_MSC_SCSI_WRITE_10, 0u, sector, count, 512u, &g_bot_cbw); MSS_USBH_MSC_scsi_req((uint8_t*)&g_bot_cbw, buf, (count*512u), (uint8_t*)&g_bot_csw); return (0); } else { return (-1); /* Previous command is in progress */ } } /******************************************************************************* * Internal Functions ******************************************************************************/ /* * This Call-back function is executed when the USBH-MSC driver is allocated * to the attached device by USBH driver. */ uint8_t usbh_msc_allocate_cb ( uint8_t tdev_addr ) { g_msd_tdev_addr = tdev_addr; g_usbh_msc_alloc_event = 1u; return(USB_SUCCESS); } /* * This Call-back function is executed when the USBH-MSC driver is released * from the attached device by USBH driver. */ uint8_t usbh_msc_release_cb ( uint8_t tdev_addr ) { g_msc_state = USBH_MSC_IDLE; g_msc_bot_state = MSC_BOT_IDLE; g_tdev_max_lun_idx = 0u; memset(g_msd_conf_desc, 0u, sizeof(g_msd_conf_desc)); memset(g_bot_inquiry, 0u, sizeof(g_bot_inquiry)); memset(&g_bot_csw, 0u, sizeof(g_bot_csw)); g_tdev_in_ep.maxpktsz = 0u; g_tdev_in_ep.num = 0u; g_tdev_out_ep.maxpktsz = 0u; g_tdev_out_ep.num = 0u; g_msd_tdev_addr = 0u; g_scsi_command.cbuf = (uint8_t*)0; g_scsi_command.dbuf = (uint8_t*)0; g_scsi_command.sbuf = (uint8_t*)0; g_scsi_command.dbuf_len = 0u; g_scsi_command.st = 0u; memset(g_bot_readcap, 0u, sizeof(g_bot_readcap)); MSS_USB_CIF_tx_ep_disable_irq(USBH_MSC_BULK_RX_PIPE); MSS_USB_CIF_tx_ep_clr_csrreg(USBH_MSC_BULK_RX_PIPE); MSS_USB_CIF_dma_clr_ctrlreg(MSS_USB_DMA_CHANNEL2); MSS_USB_CIF_rx_ep_disable_irq(USBH_MSC_BULK_TX_PIPE); MSS_USB_CIF_rx_ep_clr_csrreg(USBH_MSC_BULK_TX_PIPE); MSS_USB_CIF_dma_clr_ctrlreg(MSS_USB_DMA_CHANNEL1); if (0 != g_msch_user_cb->msch_driver_released) { g_msch_user_cb->msch_driver_released(); } return(USB_SUCCESS); } /* * This Call-back function is executed when the control transfer initiated by this * driver is complete. */ uint8_t usbh_msc_cep_done_cb ( uint8_t tdev_addr, uint8_t status, uint32_t count ) { g_usbh_msc_cep_event = status; return (USB_SUCCESS); } /* * This Call-back function is executed when the data OUT transfer initiated by * this driver is complete. */ uint8_t usbh_msc_tx_complete_cb ( uint8_t tdev_addr, uint8_t status, uint32_t count ) { if (g_msc_state < USBH_MSC_DEVICE_READY) { g_usbh_msc_tx_event = 1u; } else { if (0u == status) { switch (g_msc_bot_state) { case MSC_BOT_COMMAND_PHASE: if (0u == g_scsi_command.dbuf_len)/* zdl request */ { g_msc_bot_state = MSC_BOT_STATUS_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_scsi_command.sbuf, 13u); } else { g_msc_bot_state = MSC_BOT_DATA_PHASE; if (g_scsi_command.cbuf[12] & 0x80U) /* bmCBWFLags field -- Read Command */ { MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_scsi_command.dbuf, g_scsi_command.dbuf_len); } else /* write command */ { MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, g_scsi_command.dbuf, g_scsi_command.dbuf_len); /* data_length */ } } break; case MSC_BOT_DATA_PHASE: if (count == g_scsi_command.dbuf_len) { g_msc_bot_state = MSC_BOT_STATUS_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_scsi_command.sbuf, 13u); } else { ASSERT(0); /* at this point all data must be transfered */ } break; case MSC_BOT_STATUS_WAITCOMPLETE: break; default: ASSERT(0); /* g_msc_bot_state must not be in any other state */ break; } } else if (MSS_USB_EP_NAK_TOUT & status) { /* Device responding with NAKs. Retry */ g_msc_state = USBH_MSC_BOT_RETRY; } else { ASSERT(0);/* Handling any other error. Not yet supported */ } } return (USB_SUCCESS); } /* * This Call-back function is executed when the data IN transfer initiated by * this driver is complete. */ uint8_t usbh_msc_rx_cb ( uint8_t tdev_addr, uint8_t status, uint32_t count ) { if (g_msc_state < USBH_MSC_DEVICE_READY) { g_usbh_msc_rx_event = 1u; } else { if (0x0U == status) { switch (g_msc_bot_state) { case MSC_BOT_DATA_PHASE: if (count == g_scsi_command.dbuf_len) { g_msc_bot_state = MSC_BOT_STATUS_WAITCOMPLETE; MSS_USBH_read_in_pipe(g_msd_tdev_addr, USBH_MSC_BULK_RX_PIPE, g_tdev_in_ep.num, g_tdev_in_ep.maxpktsz, g_scsi_command.sbuf, 13u); } else { ASSERT(0);/* at this point all data must be transferred */ } break; case MSC_BOT_STATUS_WAITCOMPLETE: g_usbh_msc_rx_event = 0u; g_scsi_command.st = 0u; g_msc_bot_state = MSC_BOT_IDLE; break; default: ASSERT(0);/*g_msc_bot_state must not be in any other state */ break; } } else if (MSS_USB_EP_NAK_TOUT & status) { /* Device responding with NAKs. Retry */ g_msc_state = USBH_MSC_BOT_RETRY; } else { ASSERT(0);/* Handling any other error. Not yet supported */ } } return (USB_SUCCESS); } /* * This function validates the MSC class descriptors. */ mss_usbh_msc_err_code_t MSS_USBH_MSC_validate_class_desc ( uint8_t* p_cd ) { return(USBH_MSC_NO_ERROR); } /* * This function extract the endpoint information from the Config Descriptor. */ mss_usbh_msc_err_code_t MSS_USBH_MSC_extract_tdev_ep_desc ( void ) { mss_usbh_msc_err_code_t error = USBH_MSC_NO_ERROR; if (!(g_msd_conf_desc[21u] & USB_EP_DESCR_ATTR_BULK)) /* FirstEP Attributes Not BulkEP */ { error = USBH_MSC_WRONG_DESCR; } if (!(g_msd_conf_desc[28u] & USB_EP_DESCR_ATTR_BULK)) /*SecondEP Attributes Not BulkEP */ { error = USBH_MSC_WRONG_DESCR; } if (g_msd_conf_desc[20u] & USB_STD_REQ_DATA_DIR_MASK) /* TdevEP is IN type */ { g_tdev_in_ep.num = (g_msd_conf_desc[20u] & 0x7fu); g_tdev_in_ep.maxpktsz = (uint16_t)((g_msd_conf_desc[23u] << 8u) | (g_msd_conf_desc[22u])); g_tdev_out_ep.num = (g_msd_conf_desc[27u] & 0x7fu); g_tdev_out_ep.maxpktsz = (uint16_t)((g_msd_conf_desc[30u] << 8u) | (g_msd_conf_desc[29u])); } else if (g_msd_conf_desc[27u] & USB_STD_REQ_DATA_DIR_MASK) { g_tdev_in_ep.num = (g_msd_conf_desc[27u] & 0x7fu); g_tdev_in_ep.maxpktsz = (uint16_t)((g_msd_conf_desc[30u] << 8u) | (g_msd_conf_desc[29u])); g_tdev_out_ep.num = (g_msd_conf_desc[20u] & 0x7fu); g_tdev_out_ep.maxpktsz = (uint16_t)((g_msd_conf_desc[23u] << 8u) | (g_msd_conf_desc[22u])); } else { error = USBH_MSC_WRONG_DESCR; } return(error); } #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif mss_usb_host_msc.h000066400000000000000000001104721432224323300404560ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Microchip PolarFire SoC MSS USB Host logical driver layer Implementation. * * Microchip PolarFire SoC MSS USB Driver Stack * USB Logical Layer (USB-LL) * USBH-MSC class driver. * * USBH-MSC driver public API. * * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire SoC MSS USB driver (USBH-MSC) ============================================================================== Introduction ============================================================================== The Mass Storage Class host driver implements the USB host controller as per the USB MSC class specified by the USB-IF. This driver enables easy detection and data transfers with the attached USB mass storage devices. This driver implements the MSC class using Bulk Only transport (BOT). One BULK IN and one BULK OUT endpoints are used to implement BOT. This MSC class host supports one LUN. This driver uses the USBH driver interface functions to implement the USB MSC host. This host controller will be able to work with all the USB flash drives which fall in "Memory stick" category. ============================================================================== Theory of Operation ============================================================================== The following steps are involved in the operation of USBH-MSC driver: - Configuration - Initialization - Enumeration - Class Specific requests - Data transfer -------------------------------- Configuration -------------------------------- The MSS USB driver must first be configured in the USB Host mode using the MSS_USB_HOST_MODE to use this driver. No other configuration is necessary. -------------------------------- Initialization -------------------------------- The MSC class driver must be initialized using the MSS_USBH_MSC_init() function. A pointer to the structure of type mss_usbh_msc_user_cb_t must be provided as parameter with this function. This pointer is used to call the application call-back functions by the USBH-MSC driver. These call-back functions can be used by the application to provide error/status messages to the user or for performing application specific handling of the events. -------------------------------- Class Specific requests -------------------------------- The class specific requests are handled internally by this driver. Both the GET_MAX_LUN and the RESET_RECOVERY requests are supported. The GET_MAX_LUN request is executed after the enumeration process to find out the number of LUNs on the attached device. This driver supports one LUN (index 0). -------------------------------- Application call-back interface -------------------------------- After the USBH-Class driver is assigned to the attached device by the USBH driver, as indicated by usbh_class_allocate call-back, this driver can take over the communication with the attached device. This driver will then extend the enumeration process by requesting the class specific information from the device. During this process it will also call the call-back functions to indicate the progress of the enumeration process. These call-back functions must be implemented by application. These call-back functions can be used to take application specific action on specific event or can be used to provide error/status messages to the user. A type mss_usbh_msc_user_cb_t is provided by this driver which has all these call-back functions as its elements. Implementing these call-back functions is optional. | Element | Call-back Event | |----------------------------------------|-----------------------------------| | void (*msch_valid_config)(void) | Called to indicate that a valid | | | MSC class configuration was found | | | on the attached device and the | | | device is configured for this | | | configuration. | | | | | void (*msch_tdev_ready)(void) | Called when this driver is able | | | to retrieve all the MSC class | | | specific info (including sector | | | size and sector number) from the | | | attached device and is ready to | | | perform data transfers. | | | | | void (*msch_driver_released)(void) | Called to indicate to the | | | application that this driver is | | | released by the USBH driver | | | | | void (*msch_error)(int8_t error_code) | Called to indicate that there was | | | an error while retrieving the | | | class specific descriptor | | | information from the attached MSC | | | class device. | -------------------------------- Data transfer -------------------------------- The MSC class driver performs the data transfers using one BULK IN endpoint and one BULK OUT endpoint. The data transfers use transparent SCSI commands and follow the BoT specification. The BoT read/write operations happen on logical units of fixed block size. During initialization this driver takes care of finding all information about the attached device. The MSS_USBH_MSC_get_sector_count() and MSS_USBH_MSC_get_sector_size() functions can be used to find out the sector count and the sector size on the attached MSC class device. Most of the times the read (READ_10) and write (WRITE_10) are the only SCSI operations that the application needs to do. The MSS_USBH_MSC_read() and MSS_USBH_MSC_write() functions are provided for this purpose. The application can use the MSS_USBH_MSC_scsi_req() function if it needs to perform any other SCSI operation. This function can be used for READ_10 and WRITE_10 commands as well. Once the SCSI request is initiated using any of the above functions, the MSS_USBH_MSC_is_scsi_req_complete() function can be used to find out when the operation is complete. The USBH driver supports multi-packet Bulk transfers. The USBH-MSC driver makes full use of this feature by passing on the multi-sector transfers from the application to the USBH driver. To free up the application from transferring data to/from MSS USB FIFO, this driver can configure USBH driver to use the MSS USB internal DMA. The MSS_USBH_MSC_construct_cbw_cb10byte() and MSS_USBH_MSC_construct_cbw_cb6byte() functions are provided so that the user can easily prepare the CBW format buffer by providing appropriate parameters instead of manually creating the CBW command buffer. *//*=========================================================================*/ #ifndef __MSS_USB_HOST_MSC_H_ #define __MSS_USB_HOST_MSC_H_ #include #include "mss_usb_config.h" #ifdef __cplusplus extern "C" { #endif #ifdef MSS_USB_HOST_ENABLED /*-------------------------------------------------------------------------*//** Types exported from USBH-MSC driver ============================ */ /*-------------------------------------------------------------------------*//** The mss_usbh_msc_err_code_t provides a type to identify the error occurred during retrieving configuration and other class specific descriptors from the attached MSC class device. This type can be used with msch_error call-back function element of mss_usbh_msc_user_cb_t type to identify the exact cause of the error. The meaning of the constants is as described below | Value | Description | |----------------------------- |----------------------------------------------| | USBH_MSC_EP_NOT_VALID | Indicates that the endpoint information | | | retrieved from the attached device was not | | | consistent with the MSC class. | | | | | USBH_MSC_CLR_CEP_STALL_ERROR | Indicates that the host controller was not | | | able to clear the stall condition on the | | | attached device even after multiple retries. | | | | | USBH_MSC_SECTOR_SIZE_NOT_ | Indicates that the attached device sector | | SUPPORTED | size is not supported by this driver. | */ typedef enum { USBH_MSC_NO_ERROR = 0, USBH_MSC_EP_NOT_VALID = -1, USBH_MSC_CLR_CEP_STALL_ERROR = -2, USBH_MSC_SECTOR_SIZE_NOT_SUPPORTED = -3, USBH_MSC_WRONG_DESCR = -4, } mss_usbh_msc_err_code_t; /*-------------------------------------------------------------------------*//** The mss_usbh_msc_state_t provides a type for the states of operation of the USBH-MSC driver. Most of the states are internally used by the USBH-MSC driver during the enumeration process. The USBH-MSC driver is ready to perform data transfers with the attached device when the driver is in state USBH_MSC_DEVICE_READY. The USBH_MSC_ERROR state indicates that the error was detected either during enumeration or during the normal data transfer operations with the attached device even after retries. */ typedef enum { USBH_MSC_IDLE, USBH_MSC_GET_CLASS_DESCR, USBH_MSC_WAIT_GET_CLASS_DESCR, USBH_MSC_SET_CONFIG, USBH_MSC_WAIT_SET_CONFIG, USBH_MSC_WAIT_DEV_SETTLE, USBH_MSC_GET_MAX_LUN, USBH_MSC_WAIT_GET_MAX_LUN, USBH_MSC_CLR_CEP_STALL, USBH_MSC_WAIT_CLR_CEP_STALL, USBH_MSC_CONFIG_BULK_ENDPOINTS, USBH_MSC_TEST_UNIT_READY_CPHASE, USBH_MSC_TEST_UNIT_READY_SPHASE, USBH_MSC_TEST_UNIT_READY_WAITCOMPLETE, USBH_MSC_SCSI_INQUIRY_CPHASE, USBH_MSC_SCSI_INQUIRY_DPHASE, USBH_MSC_SCSI_INQUIRY_SPHASE, USBH_MSC_SCSI_INQUIRY_WAITCOMPLETE, USBH_MSC_SCSI_REQSENSE_CPHASE, USBH_MSC_SCSI_REQSENSE_DPHASE, USBH_MSC_SCSI_REQSENSE_SPHASE, USBH_MSC_SCSI_REQSENSE_WAITCOMPLETE, USBH_MSC_SCSI_READ_CAPACITY_CPHASE, USBH_MSC_SCSI_READ_CAPACITY_DPHASE, USBH_MSC_SCSI_READ_CAPACITY_SPHASE, USBH_MSC_SCSI_READ_CAPACITY_WAITCOMPLETE, USBH_MSC_DEVICE_READY, USBH_MSC_BOT_RETRY, USBH_MSC_ERROR } mss_usbh_msc_state_t; /*----------------------------------------------------------------------------*/ /*---------------Data structures exported by USBH-MSC driver ---------------*/ /*----------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*//** The mss_usbh_msc_user_cb_t provides the prototype for all the call-back functions which must be implemented by the user application. The user application must define and initialize a structure of this type and provide the address of that structure as parameter to the MSS_USBH_MSC_init() function. msch_valid_config The function pointed by the msch_valid_config function pointer will be called to indicate that a valid MSC class configuration was found on the attached device and the device is configured for this configuration. msch_tdev_ready The function pointed by the msch_tdev_ready function pointer is called when this driver is able to retrieve all the MSC class specific information (including sector size and sector number) from the attached device and is ready to perform the data transfers. msch_driver_released The function pointed by the msch_driver_released function pointer is called to indicate to the application that this driver is released by the USBH driver. This could be either because the MSC class device is now detached or there is permanent error with the USBH driver. msch_error The function pointed by the msch_error function pointer is called to indicate that there was an error while retrieving the class specific descriptor information from the attached MSC class device. The error_code parameter indicates the exact cause of the error. */ typedef struct mss_usbh_msc_user_cb { void (*msch_valid_config)(void); void (*msch_tdev_ready)(void); void (*msch_driver_released)(void); void (*msch_error)(int8_t error_code); } mss_usbh_msc_user_cb_t; /*-------------------------------------------------------------------------*//** The msd_cbw_t type provides the prototype for the Command Block Wrapper (CBW) as defined in Universal Serial Bus Mass Storage Class Bulk-Only Transport Revision 1.0. This type can be used by the application to create buffer of this type for creating the CBW which can then be passed on to functions provided by this driver as parameter. dCBWSignature Signature that helps identify this data packet as a CBW. The signature field shall contain the value 43425355h (little endian), indicating a CBW. dCBWTag A Command Block Tag sent by the host. The device shall echo the contents of this field back to the host in the dCSWTagfield of the associated CSW. The dCSWTagpositively associates a CSW with the corresponding CBW. dCBWDataTransferLength The number of bytes of data that the host expects to transfer on the Bulk-In or Bulk-Out endpoint (as indicated by the Direction-bit) during the execution of this command. If this field is zero, the device and the host shall transfer no data between the CBW and the associated CSW, and the device shall ignore the value of the Direction-bit in bmCBWFlags. bCBWFlags The bits of this field are defined as follows: | Bit | Description | |------------|-------------------------------------------------------------| | Bit 7 | Direction- the device shall ignore this bit if the | | | dCBWDataTransferLengthfield is zero, otherwise: | | | 0 = Data-Out from host to the device, | | | 1 = Data-In from the device to the host. | | | | | Bit 6 | Obsolete. The host shall set this bit to zero. | | Bits 5..0 | Reserved - the host shall set these bits to zero. | bCBWLUN The device Logical Unit Number (LUN) to which the command block is being sent. For devices that support multiple LUNs, the host shall place into this field the LUN to which this command block is addressed. Otherwise, the host shall set this field to zero. bCBWCBLength The valid length of the CBWCBin bytes. This defines the valid length of the command block. The only legal values are 1 through 16 (01h through 10h). All other values are reserved. CBWCB[16] The command block to be executed by the device. The device shall interpret the first bCBWCBLength bytes in this field as a command block as defined by the command set identified by bInterfaceSubClass. If the command set supported by the device uses command blocks of fewer than 16 (10h) bytes in length, the significant bytes shall be transferred first, beginning with the byte at offset 15 (0Fh). The device shall ignore the content of the CBWCBfield past the byte at offset (15 + bCBWCBLength- 1) */ typedef struct { uint32_t dCBWSignature; uint32_t dCBWTag; uint32_t dCBWDataTransferLength; uint8_t bCBWFlags; uint8_t bCBWLUN; uint8_t bCBWCBLength; uint8_t CBWCB[16]; } msd_cbw_t; /*-------------------------------------------------------------------------*//** The msd_csw_t type provides the prototype for the Command Status Wrapper (CSW) as defined in Universal Serial Bus Mass Storage Class Bulk-Only Transport Revision 1.0. This type can be used by application to create buffer of this type for creating CSW which can then be passed on to APIs provided by this driver as parameter. dCSWSignature Signature that helps identify this data packet as a CSW. The signature field shall contain the value 53425355h (little endian), indicating CSW. dCSWTag The device shall set this field to the value received in the dCBWTag of the associated CBW. dCSWDataResidue For Data-Out the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLength, and the actual amount of data processed by the device. For Data-In the device shall report in the dCSWDataResiduethe difference between the amount of data expected as stated in the dCBWDataTransferLengthand the actual amount of relevant data sent by the device. The dCSWDataResidueshall not exceed the value sent in the dCBWDataTransferLength. dCSWStatus bCSWStatusindicates the success or failure of the command. The device shall set this byte to zero if the command completed successfully. A non-zero value shall indicate a failure during command execution according to the following table: | Value | Description | |----------------------|---------------------------------------| | 00h | Command Passed ("good status") | | 01h | Command Failed | | 02h | Phase Error | | 03h and 04h | Reserved (Obsolete) | | 05h to FFh | Reserved */ typedef struct { uint32_t dCSWSignature; uint32_t dCSWTag; uint32_t dCSWDataResidue; uint32_t dCSWStatus; } msd_csw_t; /*-------------------------------------------------------------------------*//** EXPORTED APIs from USBH-MSC driver ============================ */ /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_init() function must be used by the application to initialize the USBH-MSC driver. This function must be called before any other function of the USBH-MSC driver. @param user_cb The user_cb parameter provides a pointer to the structure of type mss_usbh_msc_user_cb_t. This pointer is used to call the application call-back functions by the USBH-MSC driver. These call-back functions can be used by the application to provide error/status messages to the user or for performing the application specific handling of the events. @return This function does not return a value. Example: @code Initialize the USBH driver MSS_USBH_init(&MSS_USBH_user_cb); Initialize the USBH-MSC driver MSS_USBH_MSC_init(&MSS_USBH_MSC_user_cb); Get Class driver handle from the USBH-MSC class driver and register it with the USBH driver. On Device attachment, USBH driver will look for Device information through Descriptors and if match it with the Class driver using this Handle. MSS_USBH_register_class_driver(MSS_USBH_MSC_get_handle()); @endcode */ void MSS_USBH_MSC_init ( mss_usbh_msc_user_cb_t* user_sb ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_task() function is the main task of the USBH-MSC driver. This function monitors the events from the USBH driver as well as the user application and makes decisions. This function must be called repeatedly by the application to allow the USBH-MSC driver to perform the housekeeping tasks. A timer/scheduler can be used to call this function at regular intervals or it can be called from the main continuous foreground loop of the application. @param This function does not take any parameters. @return This function does not return a value. Example: @code #define SYS_TICK_LOAD_VALUE 48000u int main() { Initialize SysTick SysTick_Config(SYS_TICK_LOAD_VALUE); NVIC_EnableIRQ(SysTick_IRQn); } void SysTick_Handler(void) { MSS_USBH_MSC_task(); } @endcode */ void MSS_USBH_MSC_task ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_get_handle() function must be used by the application to get the handle from the USBH-MSC driver. This handle must then be used to register this driver with the USBH driver. @param This function does not take any parameters. @return This function returns a pointer to the class-handle structure. Example: @code MSS_USBH_init(&MSS_USBH_user_cb); MSS_USBH_MSC_init(&MSS_USBH_MSC_user_cb); MSS_USBH_register_class_driver(MSS_USBH_MSC_get_handle()); @endcode */ void* MSS_USBH_MSC_get_handle ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_get_state() function can be used to find out the current state of the USBH-MSC driver. This information can be used by the application to check the readiness of the USBH-MSC driver to start the data transfers. The USBH-MSC driver can perform data transfers only when it is in the USBH_MSC_DEVICE_READY state. @param This function does not take any parameters. @return This function returns a value of type mss_usbh_msc_state_t indicating the current state of the USBH-MSC driver. Example: @code if(USBH_MSC_DEVICE_READY == MSS_USBH_MSC_get_state()) { *result = MSS_USBH_MSC_get_sector_count(); return RES_OK; } else if(USBH_MSC_DEVICE_READY < MSS_USBH_MSC_get_state()) { *result = 0u; return RES_NOTRDY; } @endcode */ mss_usbh_msc_state_t MSS_USBH_MSC_get_state ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_read() function can be used to read data from the attached mass storage device. This is a non-blocking function. The function prepares the MSS USB for the USB IN transfer. Once prepared, the MSS USB will start this IN transfer depending on the configuration of the IN pipe on which this transfer is occurring. The USBH-MSC driver takes care of the allocation and configuration of the IN pipe during enumeration process depending on the attached mass storage device. After preparing the IN pipe for the IN transfer, the MSS_USBH_MSC_is_scsi_req_complete() function can be used to find out the completion of the transfer. @param buf The buf parameter is a pointer to the buffer where the data received in the IN transfer from the attached MSC class device is stored. @param sector The sector parameter indicates the sector number (logical block address) on the mass storage device starting from which the data is to be read. @param count The count parameter indicates the number of sectors to be read. @return This function returns a zero value when execution was successful. Example: @code DRESULT disk_read (BYTE drv, BYTE *buff, DWORD sector, BYTE count) { if (0u != drv) return(RES_ERROR); if (USBH_MSC_DEVICE_READY < MSS_USBH_MSC_get_state()) { return(RES_NOTRDY); } else if (USBH_MSC_DEVICE_READY == MSS_USBH_MSC_get_state()) { MSS_USBH_MSC_read(buff, sector, count); while (MSS_USBH_MSC_is_scsi_req_complete()); return (RES_OK); } else return (RES_ERROR); } @endcode */ int8_t MSS_USBH_MSC_read ( uint8_t* buf, uint32_t sector, uint32_t count ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_write() function can be used to write data to the attached mass storage device. This is a non-blocking function. The function readies the MSS USB for the USB OUT transfer. Once ready, the MSS USB will start this OUT transfer depending on the configuration of the OUT pipe on which this transfer is occurring. The USBH-MSC driver takes care of the allocation and configuration of the OUT pipe during enumeration process depending on the attached mass storage device. After starting the OUT transfer on the specified OUT pipe, the MSS_USBH_MSC_is_scsi_req_complete() function can be used to find out the completion of the transfer. @param buf The buf parameter is a pointer to the buffer from which data need to be transmitted to the attached MSC class device. @param sector The sector parameter indicates the sector number (logical block address) on the mass storage device starting from which the data is to be written. @param count The count parameter indicates the number of sectors to be written. @return This function returns a zero value when execution was successful. Example: @code DRESULT disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, BYTE count) { if (0u != pdrv) return(RES_ERROR); if (USBH_MSC_DEVICE_READY < MSS_USBH_MSC_get_state()) { return(RES_NOTRDY); } else if (USBH_MSC_DEVICE_READY == MSS_USBH_MSC_get_state()) { MSS_USBH_MSC_write((uint8_t*)buff, sector, count); while (MSS_USBH_MSC_is_scsi_req_complete()); return (RES_OK); } else return (RES_ERROR); } @endcode */ int8_t MSS_USBH_MSC_write ( uint8_t* buf, uint32_t sector, uint32_t count ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_get_sector_count() function can be used to find out the number of sectors (logical blocks) available on the attached MSC class device. @param This function does not take any parameters. @return This function returns a value of type uint32_t indicating the number of sectors (logical blocks) available on the attached MSC class device. Example: @code DRESULT disk_ioctl ( BYTE pdrv, BYTE ctrl, void *buff) ) { UINT *result = (UINT *)buff; switch (ctrl) { case GET_SECTOR_COUNT: if (USBH_MSC_DEVICE_READY == MSS_USBH_MSC_get_state()) { *result = MSS_USBH_MSC_get_sector_count(); return RES_OK; } else if (USBH_MSC_DEVICE_READY < MSS_USBH_MSC_get_state()) { *result = 0u; return RES_NOTRDY; } else { *result = 0u; return RES_ERROR; } break; default: return RES_NOTRDY; } } @endcode */ uint32_t MSS_USBH_MSC_get_sector_count ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_get_sector_size() function can be used to find out the size of a sector (in bytes) on the attached MSC class device. @param This function does not take any parameters. @return This function returns a value of type uint32_t indicating the sector size (in bytes) on the attached MSC class device. Example: @code DRESULT disk_ioctl ( BYTE pdrv, BYTE ctrl, void *buff ) { UINT *result = (UINT *)buff; switch (ctrl) { case GET_SECTOR_SIZE: if(USBH_MSC_DEVICE_READY == MSS_USBH_MSC_get_state()) { *result = MSS_USBH_MSC_get_sector_size(); return RES_OK; } else if(USBH_MSC_DEVICE_READY < MSS_USBH_MSC_get_state()) { *result = 0u; return RES_NOTRDY; } else { *result = 0u; return RES_ERROR; } break; default: return RES_NOTRDY; } } @endcode */ uint32_t MSS_USBH_MSC_get_sector_size ( void ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_construct_cbw_cb10byte() function can be used to create the SCSI request command block wrapper (CBW) as per MSC class which has command block(CB) of length 10bytes. @param command_opcode The command_opcode parameter provides the transparent SCSI command code. @param lun The lun parameter indicates the logical unit number on the attached MSC class device. @param lb_addr The lb_addr parameter provides the logical block address on which the operation indicated by the command_opcode parameter is applicable. For the commands where logical block address is not applicable, a zero value must be provided. @param num_of_lb The num_of_addr parameter provides the number of logical blocks on which the operation indicated by the command_opcode parameter is applicable. For the commands where logical block address is not applicable, a zero value must be provided. @param lb_size The lb_size parameter provides the size of the logical block on the attached MSC class device. @param buf The buf parameter provides the pointer to the buffer where the formatted SCSI command is to be stored. @return This function does not return any value. Example: @code int8_t MSS_USBH_MSC_read(uint8_t* buf, uint32_t sector, uint32_t count) { MSS_USBH_MSC_construct_cbw_cb10byte(USB_MSC_SCSI_READ_10, 0u, sector, count, 512u, &g_bot_cbw); MSS_USBH_MSC_scsi_req((uint8_t*)&g_bot_cbw, buf, (count*512u), (uint8_t*)&g_bot_csw); return(0); } @endcode */ void MSS_USBH_MSC_construct_cbw_cb10byte ( uint8_t command_opcode, uint8_t lun, uint32_t lb_addr, uint16_t num_of_lb, uint16_t lb_size, msd_cbw_t* buf ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_construct_cbw_cb6byte() function can be used to create the SCSI request command block wrapper (CBW) as per MSC class which has command block(CB) of length 6 bytes. @param command_opcode The command_opcode parameter provides the transparent SCSI command code. @param xfr_length The xfr_length parameter provides the number of bytes to be transferred in the data phase of the command. @param buf The buf parameter provides the pointer to the buffer where the formatted SCSI command is to be stored. @return This function does not return any value. Example: @code MSS_USBH_MSC_construct_cbw_cb6byte(USB_MSC_SCSI_TEST_UNIT_READY, 0u, &g_bot_cbw); MSS_USBH_write_out_pipe(g_msd_tdev_addr, USBH_MSC_BULK_TX_PIPE, g_tdev_out_ep.num, g_tdev_out_ep.maxpktsz, (uint8_t*)&g_bot_cbw, 31u); @endcode */ void MSS_USBH_MSC_construct_cbw_cb6byte ( uint8_t command_opcode, uint32_t data_xfr_len, msd_cbw_t* buf ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_scsi_req() function can be used to execute any SCSI command required by the MSC class on the attached MSC device. In most cases using the MSS_USBH_MSC_write() and MSS_USBH_MSC_read() functions is enough for the application. However, if the application wants to execute other SCSI commands it can use the MSS_USBH_MSC_scsi_req() function. This function can be used as alternative to MSS_USBH_MSC_write() and MSS_USBH_MSC_read() functions. The MSS_USBH_MSC_is_scsi_req_complete() function can be used to find out when the transfer started using this function is complete. @param command_buf The command_buf parameter provides the pointer to the buffer where the SCSI command (CBW format) to be executed is stored. @param data_buf The data_buf parameter provides the pointer to the data buffer which is to be used in the data phase of the command. This parameter is the source of the data when the data direction is from the host to the device. This parameter is the destination for the data when the data direction is from the device to the host. This function extracts the data direction from the CBW format command provided using command_buf parameter. @param data_buf_len The data_buf_len parameter indicates the number of bytes to be transferred in the data phase of the current command. @param status_buf The status_buf parameter provides the pointer to the buffer where the status (CSW format) received from the attached MSC device for the current SCSI operation is to be stored. @return This function returns zero value when successfully executed. Example: @code int8_t MSS_USBH_MSC_read ( uint8_t* buf, uint32_t sector, uint32_t count ) { MSS_USBH_MSC_construct_cbw_cb10byte(USB_MSC_SCSI_READ_10, 0u, sector, count, 512u, &g_bot_cbw); MSS_USBH_MSC_scsi_req((uint8_t*)&g_bot_cbw, buf, (count*512u), (uint8_t*)&g_bot_csw); return(0); } @endcode */ uint8_t MSS_USBH_MSC_scsi_req ( uint8_t* command_buf, /* always31bytes */ uint8_t* data_buf, uint32_t data_buf_len, uint8_t* status_buf /* status always 13bytes */ ); /*-------------------------------------------------------------------------*//** The MSS_USBH_MSC_is_scsi_req_complete() function must be used to find out whether the SCSI request initiated using MSS_USBH_MSC_scsi_req() or MSS_USBH_MSC_read() or MSS_USBH_MSC_write() function is complete. @param This function does not take any parameters. @return This function returns zero value when the current command is completed. Example: @code MSS_USBH_MSC_write((uint8_t*)buff, sector, count); while (MSS_USBH_MSC_is_scsi_req_complete()); return (RES_OK); @endcode */ uint8_t MSS_USBH_MSC_is_scsi_req_complete ( void ); #endif /* MSS_USB_HOST_ENABLED */ #ifdef __cplusplus } #endif #endif /* __MSS_USB_HOST_MSC_H_ */ mss_usb_host_reg_io.h000066400000000000000000000524751432224323300411500ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USBH-CIF * * This file provides interfaces to perform register and register bit level * read / write operations in USB Host mode. * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_HOST_REG_IO_H_ #define __MSS_USB_HOST_REG_IO_H_ #ifdef __cplusplus extern "C" { #endif #include "mss_usb_core_regs.h" /*------------------------------------------------------------------------- *//** Host Mode Functions ============================ */ /*------------------------------------------------------------------------- *//** CSR0L register related APIs */ static __INLINE uint8_t MSS_USBH_CIF_cep_is_rxstall_err ( void ) { return (((USB->ENDPOINT[MSS_USB_CEP].TX_CSR & CSR0L_HOST_STALL_RCVD_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_cep_clr_rxstall_err ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0L_HOST_STALL_RCVD_MASK; } static __INLINE uint8_t MSS_USBH_CIF_cep_is_retry_err ( void ) { return (((USB->ENDPOINT[MSS_USB_CEP].TX_CSR & CSR0L_HOST_RETRY_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_cep_clr_retry_err ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0L_HOST_RETRY_ERR_MASK; } static __INLINE void MSS_USBH_CIF_cep_clr_csr_reg ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR = 0x0000u; } static __INLINE uint8_t MSS_USBH_CIF_cep_is_naktimeout_err ( void ) { return (((USB->ENDPOINT[MSS_USB_CEP].TX_CSR & CSR0L_HOST_NAK_TIMEOUT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_cep_clr_naktimeout_err ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0L_HOST_NAK_TIMEOUT_MASK; } /*-------------------------------------------------------------------------*//** CSR0H register related APIs */ static __INLINE void MSS_USBH_CIF_cep_flush_fifo ( mss_usb_ep_num_t ep_num ) { /* should be set when TxPktRdy/RxPktRdy is set */ if ((USB->ENDPOINT[ep_num].TX_CSR) & (TxCSRL_HOST_EPN_TX_PKT_RDY_MASK | CSR0L_HOST_RX_PKT_RDY_MASK)) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= CSR0H_HOST_FLUSH_FIFO_MASK; } } static __INLINE uint8_t MSS_USBH_CIF_cep_is_data_tog ( void ) { return (((USB->ENDPOINT[MSS_USB_CEP].TX_CSR & CSR0H_HOST_DATA_TOG_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_cep_disable_ping ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR |= CSR0H_HOST_DISABLE_PING_MASK; } static __INLINE void MSS_USBH_CIF_cep_enable_ping ( void ) { USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~CSR0H_HOST_DISABLE_PING_MASK; } /*-------------------------------------------------------------------------*//** NAKLIMIT0 register related APIs */ static __INLINE void MSS_USBH_CIF_cep_set_naklimit ( uint8_t naklimit ) { if((naklimit >= 2u ) && (naklimit <= 16u)) { USB->ENDPOINT[MSS_USB_CEP].TX_INTERVAL = naklimit; } } /*-------------------------------------------------------------------------*//** ENDOF - Host mode functions */ /* TXMAXP is common to host and device */ /*-------------------------------------------------------------------------*//** TXCSRL register related APIs */ static __INLINE void MSS_USBH_CIF_tx_ep_set_txpktrdy(mss_usb_ep_num_t ep_num) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_HOST_EPN_TX_PKT_RDY_MASK; } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_txpktrdy ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_HOST_EPN_TX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_fifo_ne ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_HOST_EPN_TX_FIFO_NE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_retry_err ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_HOST_EPN_RESPONSE_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_tx_ep_clr_retry_err ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_HOST_EPN_RESPONSE_ERR_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_flush_fifo_reg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= (TxCSRL_HOST_EPN_FLUSH_FIFO_MASK | TxCSRL_HOST_EPN_TX_PKT_RDY_MASK); } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_rxstall_err ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_HOST_EPN_STALL_RCVD_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_tx_ep_clr_rxstall_err ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_HOST_EPN_STALL_RCVD_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_clr_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRL_HOST_EPN_CLR_DATA_TOG_MASK; } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_naktimeout_err ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRL_HOST_EPN_NAK_TIMEOUT_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_tx_ep_clr_naktimeout_err ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRL_HOST_EPN_NAK_TIMEOUT_MASK ; } /*-------------------------------------------------------------------------*//** TXCSRH register related APIs */ static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_data_tog ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_HOST_EPN_DATA_TOG_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_tx_ep_write_data_tog ( mss_usb_ep_num_t ep_num, uint32_t data_tog ) { /* data_tog has to be 0 or 1 */ USB->ENDPOINT[ep_num].TX_CSR = data_tog & 0x00000001U; } static __INLINE void MSS_USBH_CIF_tx_ep_set_data_tog_we ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_HOST_EPN_DATA_TOG_WE_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_clr_data_tog_we ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_HOST_EPN_DATA_TOG_WE_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_set_dma_mode1 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_HOST_EPN_DMA_MODE_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_set_dma_mode0 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_HOST_EPN_DMA_MODE_MASK; } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_get_dma_mode ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_HOST_EPN_DMA_MODE_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_tx_ep_set_force_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_HOST_EPN_FRC_DATA_TOG_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_clr_force_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_HOST_EPN_FRC_DATA_TOG_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_enable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_HOST_EPN_ENABLE_DMA_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_disable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_HOST_EPN_ENABLE_DMA_MASK; } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_dma_enabled ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_HOST_EPN_ENABLE_DMA_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_tx_ep_set_autoset ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR |= TxCSRH_HOST_EPN_ENABLE_AUTOSET_MASK; } static __INLINE void MSS_USBH_CIF_tx_ep_clr_autoset ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_CSR &= ~TxCSRH_HOST_EPN_ENABLE_AUTOSET_MASK; } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_is_autoset ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].TX_CSR & TxCSRH_HOST_EPN_ENABLE_AUTOSET_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** RXCSRL register related APIs */ static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_rxpktrdy ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRL_HOST_EPN_RX_PKT_RDY_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_fifo_full ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRL_HOST_EPN_RX_FIFO_FULL_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_retry_err ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRL_HOST_EPN_RESPONSE_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_rx_ep_clr_retry_err ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRL_HOST_EPN_RESPONSE_ERR_MASK; } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_naktimeout_err ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRL_HOST_EPN_NAK_TIMEOUT_ERR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_rx_ep_clr_naktimeout_err ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRL_HOST_EPN_NAK_TIMEOUT_ERR_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_flush_fifo_reg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRL_HOST_EPN_FLUSH_FIFO_MASK; } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_rxstall_err ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRL_HOST_EPN_STALL_RCVD_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_rx_ep_clr_rxstall_err ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRL_HOST_EPN_STALL_RCVD_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_clr_data_tog ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRL_HOST_EPN_CLR_DATA_TOG_MASK; } /*-------------------------------------------------------------------------*//** RXCSRH register related APIs */ static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_iso_incomp ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRH_HOST_EPN_RX_ISO_INCOMP) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_data_tog ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRH_HOST_EPN_DATA_TOG_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_rx_ep_write_data_tog ( mss_usb_ep_num_t ep_num, uint32_t data_tog ) { USB->ENDPOINT[ep_num].RX_CSR = data_tog; } static __INLINE void MSS_USBH_CIF_rx_ep_set_data_tog_we ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRH_HOST_EPN_DATA_TOG_WE_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_clr_data_tog_we ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRH_HOST_EPN_DATA_TOG_WE_MASK; } static __INLINE mss_usb_dma_mode_t MSS_USBH_CIF_rx_ep_get_dma_mode ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRH_HOST_EPN_DMA_MODE_MASK) ? MSS_USB_DMA_MODE1 : MSS_USB_DMA_MODE0)); } static __INLINE void MSS_USBH_CIF_rx_ep_set_dma_mode1 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRH_HOST_EPN_DMA_MODE_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_set_dma_mode0 ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRH_HOST_EPN_DMA_MODE_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_enable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRH_HOST_EPN_ENABLE_DMA_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_disable_dma ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRH_HOST_EPN_ENABLE_DMA_MASK; } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_dma_enabled ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRH_HOST_EPN_ENABLE_DMA_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } static __INLINE void MSS_USBH_CIF_rx_ep_set_autoreq ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRH_HOST_EPN_ENABLE_AUTOREQ_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_clr_autoreq ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRH_HOST_EPN_ENABLE_AUTOREQ_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_set_autoclr ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR |= RXCSRH_HOST_EPN_ENABLE_AUTOCLR_MASK; } static __INLINE void MSS_USBH_CIF_rx_ep_clr_autoclr ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_CSR &= ~RXCSRH_HOST_EPN_ENABLE_AUTOCLR_MASK; } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_is_autoclr ( mss_usb_ep_num_t ep_num ) { return (((USB->ENDPOINT[ep_num].RX_CSR & RXCSRH_HOST_EPN_ENABLE_AUTOCLR_MASK) ? MSS_USB_BOOLEAN_TRUE : MSS_USB_BOOLEAN_FALSE)); } /*-------------------------------------------------------------------------*//** TXTYPE register related APIs */ static __INLINE void MSS_USBH_CIF_tx_ep_set_target_speed ( mss_usb_ep_num_t ep_num, mss_usb_device_speed_t speed ) { USB->ENDPOINT[ep_num].TX_TYPE &= ~TXTYPE_HOST_TARGET_EP_SPEED_MASK; USB->ENDPOINT[ep_num].TX_TYPE |= (speed << TXTYPE_HOST_TARGET_EP_SPEED_SHIFT); } static __INLINE mss_usb_device_speed_t MSS_USBH_CIF_tx_ep_get_target_speed ( mss_usb_ep_num_t ep_num ) { return ((mss_usb_device_speed_t)((USB->ENDPOINT[ep_num].TX_TYPE & TXTYPE_HOST_TARGET_EP_SPEED_MASK) >> TXTYPE_HOST_TARGET_EP_SPEED_SHIFT)); } static __INLINE void MSS_USBH_CIF_tx_ep_set_target_protocol ( mss_usb_ep_num_t ep_num, mss_usb_xfr_type_t xfr_type ) { USB->ENDPOINT[ep_num].TX_TYPE &= ~TXTYPE_HOST_TARGET_EP_PROTOCOL_MASK; USB->ENDPOINT[ep_num].TX_TYPE |= (xfr_type << TXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT); } static __INLINE mss_usb_xfr_type_t MSS_USBH_CIF_tx_ep_get_target_protocol ( mss_usb_ep_num_t ep_num ) { return ((mss_usb_xfr_type_t)((USB->ENDPOINT[ep_num].TX_TYPE & TXTYPE_HOST_TARGET_EP_PROTOCOL_MASK) >> TXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT)); } static __INLINE void MSS_USBH_CIF_tx_ep_set_target_ep_no ( mss_usb_ep_num_t ep_num, uint8_t tdev_ep_num ) { USB->ENDPOINT[ep_num].TX_TYPE &= ~TXTYPE_HOST_TARGET_EP_NUM_MASK; USB->ENDPOINT[ep_num].TX_TYPE |= (tdev_ep_num << TXTYPE_HOST_TARGET_EP_NUM_SHIFT); } static __INLINE uint8_t MSS_USBH_CIF_tx_ep_get_target_ep_no ( mss_usb_ep_num_t ep_num ) { return ((mss_usb_ep_num_t)((USB->ENDPOINT[ep_num].TX_TYPE & TXTYPE_HOST_TARGET_EP_NUM_MASK) >> TXTYPE_HOST_TARGET_EP_NUM_SHIFT)); } static __INLINE void MSS_USBH_CIF_tx_ep_clr_txtypereg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].TX_TYPE = 0x0000U; } /*-------------------------------------------------------------------------*//** TXINTERVAL register related APIs */ static __INLINE void MSS_USBH_CIF_tx_ep_set_target_interval ( mss_usb_ep_num_t ep_num, uint8_t interval ) { USB->ENDPOINT[ep_num].TX_INTERVAL = interval; } /*-------------------------------------------------------------------------*//** RXTYPE register related APIs */ static __INLINE void MSS_USBH_CIF_rx_ep_set_target_speed ( mss_usb_ep_num_t ep_num, mss_usb_device_speed_t speed ) { USB->ENDPOINT[ep_num].RX_TYPE &= ~RXTYPE_HOST_TARGET_EP_SPEED_MASK; USB->ENDPOINT[ep_num].RX_TYPE |= (speed << RXTYPE_HOST_TARGET_EP_SPEED_SHIFT); } static __INLINE mss_usb_device_speed_t MSS_USBH_CIF_rx_ep_get_target_speed ( mss_usb_ep_num_t ep_num ) { return ((mss_usb_device_speed_t)((USB->ENDPOINT[ep_num].RX_TYPE & RXTYPE_HOST_TARGET_EP_SPEED_MASK) >> RXTYPE_HOST_TARGET_EP_SPEED_SHIFT)); } static __INLINE void MSS_USBH_CIF_rx_ep_set_target_protocol ( mss_usb_ep_num_t ep_num, mss_usb_xfr_type_t xfr_type ) { USB->ENDPOINT[ep_num].RX_TYPE &= ~RXTYPE_HOST_TARGET_EP_PROTOCOL_MASK; USB->ENDPOINT[ep_num].RX_TYPE |= (xfr_type << RXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT); } static __INLINE mss_usb_xfr_type_t MSS_USBH_CIF_rx_ep_get_target_protocol ( mss_usb_ep_num_t ep_num ) { return ((mss_usb_xfr_type_t)((USB->ENDPOINT[ep_num].RX_TYPE & RXTYPE_HOST_TARGET_EP_PROTOCOL_MASK) >> RXTYPE_HOST_TARGET_EP_PROTOCOL_SHIFT)); } static __INLINE void MSS_USBH_CIF_rx_ep_set_target_ep_no ( mss_usb_ep_num_t ep_num, uint8_t tdev_ep_num ) { USB->ENDPOINT[ep_num].RX_TYPE &= ~RXTYPE_HOST_TARGET_EP_NUM_MASK; USB->ENDPOINT[ep_num].RX_TYPE |= (tdev_ep_num << RXTYPE_HOST_TARGET_EP_NUM_SHIFT); } static __INLINE uint8_t MSS_USBH_CIF_rx_ep_get_target_ep_no ( mss_usb_ep_num_t ep_num ) { return ((mss_usb_ep_num_t)((USB->ENDPOINT[ep_num].RX_TYPE & RXTYPE_HOST_TARGET_EP_NUM_MASK) >> RXTYPE_HOST_TARGET_EP_NUM_SHIFT)); } static __INLINE void MSS_USBH_CIF_rx_ep_clr_rxtypereg ( mss_usb_ep_num_t ep_num ) { USB->ENDPOINT[ep_num].RX_TYPE = 0x0000U; } /*-------------------------------------------------------------------------*//** RXINTERVAL register related APIs */ static __INLINE void MSS_USBH_CIF_rx_ep_set_target_interval ( mss_usb_ep_num_t ep_num, uint8_t interval ) { USB->ENDPOINT[ep_num].RX_INTERVAL = interval; } /*-------------------------------------------------------------------------*//** REQPKTCOUNT register related APIs */ static __INLINE void MSS_USBH_CIF_rx_ep_set_reqpkt_count ( mss_usb_ep_num_t ep_num, uint32_t count ) { /* * Used with AUTOREQ option. * Multiple packets combined into a single bulk packet within the FIFO count * as one packet. */ USB->RQ_PKT_CNT[ep_num] = count; } /*-------------------------------------------------------------------------*//** RXFUNCADDR register related APIs */ static __INLINE void MSS_USBH_CIF_rx_ep_set_target_func_addr ( mss_usb_ep_num_t ep_num, uint32_t addr ) { /* Device number of the target - initially zero, then determined by * enumeration process. */ USB->TAR[ep_num].RX_FUNC_ADDR = (addr & 0x7Fu); } /*-------------------------------------------------------------------------*//** * TXHUBADDR register related APIs */ static __INLINE void MSS_USBH_CIF_tx_ep_set_target_hub_addr ( mss_usb_ep_num_t ep_num, uint32_t addr, uint32_t mtt ) { /* Device number of the target - initially zero, then determined by * enumeration process. */ USB->TAR[ep_num].TX_HUB_ADDR = ((uint8_t)(mtt << TARGET_DEVICE_HUB_MT_SHIFT) | (addr & 0x7Fu)); } /*-------------------------------------------------------------------------*//** RXHUBADDR register related APIs */ static __INLINE void MSS_USBH_CIF_rx_ep_set_target_hub_addr ( mss_usb_ep_num_t ep_num, uint32_t addr, uint32_t mtt ) { /* Device number of the target - initially zero, then determined by * enumeration process. */ USB->TAR[ep_num].RX_HUB_ADDR = ((uint8_t)(mtt << TARGET_DEVICE_HUB_MT_SHIFT) | (addr & 0x7Fu)); } /*-------------------------------------------------------------------------*//** TXHUBADDR register related APIs */ static __INLINE void MSS_USBH_CIF_tx_ep_set_target_hub_port ( mss_usb_ep_num_t ep_num, uint32_t port_no ) { /* for FS/LS devices only */ USB->TAR[ep_num].TX_HUB_PORT = (port_no & 0xFFu); } /*-------------------------------------------------------------------------*//** RXHUBADDR register related APIs */ static __INLINE void MSS_USBH_CIF_rx_ep_set_target_hub_port ( mss_usb_ep_num_t ep_num, uint32_t port_no ) { /* for FS/LS devices only */ USB->TAR[ep_num].RX_HUB_PORT = (port_no & 0xFFu); } /* Trailing zeros */ static __INLINE uint32_t MSS_USBH_CIF_ctz ( uint32_t number ) { uint32_t c = 32u; number &= -(int32_t)(number); if (number) { c--; } if (number & 0x0000FFFFU) { c -= 16; } if (number & 0x00FF00FFU) { c -= 8; } if (number & 0x0F0F0F0FU) { c -= 4; } if (number & 0x33333333U) { c -= 2; } if (number & 0x55555555U) { c -= 1; } return c; } #ifdef __cplusplus } #endif #endif /* __MSS_USB_HOST_REG_IO_H_ */ mss_usb_regs.h000066400000000000000000000010221432224323300375650ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * USB Core Interface Layer (USB-CIFL) * USB-CIF. * * MSS USB register map * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_REGS_H_ #define __MSS_USB_REGS_H_ #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif /* __MSS_USB_COMMON_REG_IO_H_ */ mss_usb_std_def.h000066400000000000000000000217761432224323300402570ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_usb/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Microchip PolarFire SoC MSS USB Driver Stack * * * Standard USB definitions. * * * SVN $Revision$ * SVN $Date$ */ #ifndef __MSS_USB_STD_DEF_H_ #define __MSS_USB_STD_DEF_H_ #ifdef __cplusplus extern "C" { #endif /*-------------------------------------------------------------------------*//** Constant values which are internally used by the driver. ============================ */ /* USB request types */ #define USB_STANDARD_REQUEST 0x00u #define USB_CLASS_REQUEST 0x20u #define USB_VENDOR_REQUEST 0x40u /* USB request type masks */ #define USB_STD_REQ_DATA_DIR_MASK 0x80u #define USB_STD_REQ_TYPE_MASK 0x60u #define USB_STD_REQ_RECIPIENT_MASK 0x1Fu #define USB_STD_REQ_DATA_DIR_OUT 0x00u #define USB_STD_REQ_DATA_DIR_IN 0x80u #define USB_STD_REQ_RECIPIENT_DEVICE 0x00u #define USB_STD_REQ_RECIPIENT_INTERFACE 0x01u #define USB_STD_REQ_RECIPIENT_ENDPOINT 0x02u #define USB_STD_REQ_GET_STATUS 0x00u #define USB_STD_REQ_CLEAR_FEATURE 0x01u #define USB_STD_REQ_SET_FEATURE 0x03u #define USB_STD_REQ_SET_ADDRESS 0x05u #define USB_STD_REQ_GET_DESCRIPTOR 0x06u #define USB_STD_REQ_SET_DESCRIPTOR 0x07u #define USB_STD_REQ_GET_CONFIG 0x08u #define USB_STD_REQ_SET_CONFIG 0x09u #define USB_STD_REQ_GET_INTERFACE 0x0Au #define USB_STD_REQ_SET_INTERFACE 0x0Bu #define USB_STD_REQ_SYNCH_FRAME 0x0Cu /* USB Feature selector */ #define USB_STD_FEATURE_REMOTE_WAKEUP 0x0001u #define USB_STD_FEATURE_TEST_MODE 0x0002u #define USB_STD_FEATURE_EP_HALT 0x0000u /* USB Test Mode, Test selectors */ #define USB_TEST_MODE_SELECTOR_TEST_J 0x01u #define USB_TEST_MODE_SELECTOR_TEST_K 0x02u #define USB_TEST_MODE_SELECTOR_TEST_SE0NAK 0x03u #define USB_TEST_MODE_SELECTOR_TEST_PACKET 0x04u #define USB_TEST_MODE_SELECTOR_TEST_FORCE_ENA 0x05u /* Descriptor types */ #define USB_DEVICE_DESCRIPTOR_TYPE 1u #define USB_CONFIGURATION_DESCRIPTOR_TYPE 2u #define USB_STRING_DESCRIPTOR_TYPE 3u #define USB_INTERFACE_DESCRIPTOR_TYPE 4u #define USB_ENDPOINT_DESCRIPTOR_TYPE 5u #define USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE 6u #define USB_OTHER_SPEED_CONFIG_DESCRIPTOR_TYPE 7u #define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 8u #define USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE 11u #define USB_WVALUE_HIBITE_SHIFT 8u #define USB_WINDEX_HIBITE_SHIFT 8u #define USB_EP_DESCR_ATTR_CONTROL 0x00u #define USB_EP_DESCR_ATTR_ISO 0x01u #define USB_EP_DESCR_ATTR_BULK 0x02u #define USB_EP_DESCR_ATTR_INTR 0x03u #define USB_BCD_VERSION_2_0 0x0200u #define USB_BCD_VERSION_2_1 0x0210u #define USB_BCD_VERSION_1_1 0x0110u #define USB_BCD_VERSION_1_0 0x0100u #define USB_DEFAULT_TARGET_ADDR 0u #define USB_SETUP_PKT_LEN 8u #define USB_STD_DEVICE_DESCR_LEN 18u #define USB_STD_CONFIG_DESCR_LEN 9u #define USB_STD_INTERFACE_DESCR_LEN 9u #define USB_STD_ENDPOINT_DESCR_LEN 7u #define USB_STD_IA_DESCR_LEN 8u #define USB_STD_DEV_QUAL_DESCR_LENGTH 10u #define USB_DEVICE_BUS_POWER_MASK 0x40u #define USB_DEVICE_REM_WAKEUP_MASK 0x20u #define USB_MAX_BUS_POWER 250u /*num = mA/2*/ #define USB_CLASS_CODE_MSD 0x08u /* bInterfaceClass */ #define USB_CLASS_MSD_SUBCLASS_SCSI 0x06u /* bInterfaceSubClass */ #define USB_CLAS_MSD_PROTOCOL_BOT 0x50u /* bInterfaceProtocol */ #define USB_DEF_CONFIG_NUM 0u /*-------------------------------------------------------------------------*//** Maximum allowed Packet Sizes for respective transfer types */ #define USB_HS_BULK_MAX_PKT_SIZE 512u #define USB_HS_INTERRUPT_MAX_PKT_SIZE 1024u #define USB_HS_ISO_MAX_PKT_SIZE 1024u #define USB_FS_BULK_MAX_PKT_SIZE 64u #define USB_FS_INTERRUPT_MAX_PKT_SIZE 64u #define USB_FS_ISO_MAX_PKT_SIZE 1023u /*-------------------------------------------------------------------------*//** MSC class related definitions */ /* BoT protocol constants */ #define USBD_MSC_BOT_CSW_LENGTH 13u #define USBD_MSC_BOT_CBW_LENGTH 31u #define USB_MSC_BOT_REQ_GET_MAX_LUN 0xFEu #define USB_MSC_BOT_REQ_BMS_RESET 0xFFu #define USB_MSC_BOT_CBW_SIGNATURE 0x43425355u #define USB_MSC_BOT_CSW_SIGNATURE 0x53425355u /* Supported SCSI commands*/ #define USB_MSC_SCSI_INQUIRY 0x12u #define USB_MSC_SCSI_READ_FORMAT_CAPACITIES 0x23u #define USB_MSC_SCSI_READ_CAPACITY_10 0x25u #define USB_MSC_SCSI_READ_10 0x28u #define USB_MSC_SCSI_REQUEST_SENSE 0x03u #define USB_MSC_SCSI_TEST_UNIT_READY 0x00u #define USB_MSC_SCSI_WRITE_10 0x2Au #define USB_MSC_SCSI_MODE_SENSE_6 0x1Au #define USB_MSC_SCSI_MODE_SELECT_6 0x15u #define USB_MSC_SCSI_PREVENT_ALLW_MDM_RMVL 0x1Eu #define USB_MSC_SCSI_VERIFY_10 0x2Fu #define USB_MSC_SCSI_INVALID_COMMAND_CODE 0xFFu /* Additional sense codes */ #define SC_NO_SENSE 0x00u #define SC_RECOVERED_ERR 0x01u #define SC_NOT_READY 0x02u #define SC_MEDIUM_ERROR 0x03u #define SC_HARDWARE_ERR 0x04u #define SC_ILLEGAL_REQUEST 0x05u #define SC_UNIT_ATTENTION 0x06u #define SC_DATA_PROTECT 0x07u #define SC_BLANK_CHECK 0x08u #define SC_VENDOR_SPECIFIC 0x09u #define SC_COPY_ABORTED 0x0Au #define SC_ABORTED_COMMAND 0x0Bu /*0x0C is obsolete*/ #define SC_VOLUME_OVERFLOW 0x0Du #define SC_MISCOMPARE 0x0Eu /*0x0F is reserved*/ #define ASC_INVALID_CDB 0x20u #define ASC_INVALID_FIELED_IN_COMMAND 0x24u #define ASC_PARAMETER_LIST_LENGTH_ERROR 0x1Au #define ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26u #define ASC_ADDRESS_OUT_OF_RANGE 0x21u #define ASC_MEDIUM_NOT_PRESENT 0x3Au #define ASC_MEDIUM_HAS_CHANGED 0x28u #define ASC_WRITE_PROTECTED 0x27u #define ASC_UNRECOVERED_READ_ERROR 0x11u #define ASC_WRITE_FAULT 0x03u /*-------------------------------------------------------------------------*//** CDC class related definitions */ /* CDC Requests for ACM sub-class */ #define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00u #define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01u #define USB_CDC_SET_COMM_FEATURE 0x02u #define USB_CDC_GET_COMM_FEATURE 0x03u #define USB_CDC_CLEAR_COMM_FEATURE 0x04u #define USB_CDC_SET_LINE_CODING 0x20u #define USB_CDC_GET_LINE_CODING 0x21u #define USB_CDC_SET_CONTROL_LINE_STATE 0x22u #define USB_CDC_SEND_BREAK 0x23u /*-------------------------------------------------------------------------*//** HID class related definitions */ #define USB_HID_DESCR_LENGTH 9u #define USB_HID_DESCRIPTOR_TYPE 0x21u #define USB_REPORT_DESCRIPTOR_TYPE 0x22u #ifdef __cplusplus } #endif #endif /* __MSS_USB_STD_DEF_H_ */ pf_pcie/000077500000000000000000000000001432224323300340565ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/driverspf_pcie.c000066400000000000000000001443161432224323300356400ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/pf_pcie/***************************************************************************** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire and PolarFire SoC PCIe subsystem software driver implementation. * * SVN $Revision$ * SVN $Date$ */ #include "pf_pcie.h" #ifdef __cplusplus extern "C" { #endif /**************************************************************************/ /* Preprocessor Macros */ /**************************************************************************/ /* PCIe enumeration values */ /* At Present PCIe supports one Root Port and End Point */ #define PCIE_CFG_MAX_NUM_OF_BUS 8u #define PCIE_CFG_MAX_NUM_OF_DEV 2u #define PCIE_CFG_MAX_NUM_OF_FUN 8u #define PCIE_CFG_FUN_NOT_IMP_MASK 0xFFFFu #define PCIE_CFG_HEADER_TYPE_MASK 0x00EF0000u #define PCIE_CFG_MUL_FUN_DEV_MASK 0x00800000u #define PCIE_CFG_HEADER_O_TYPE 0x00000000u #define PCIE_CFG_CATCHE_SIZE 0x10u /* ECAM Address Register bitmaps and masks */ /* Mask of all valid bits */ #define PCIE_ECAM_MASK 0x0FFFFFFFu /* Bus Number Mask */ #define PCIE_ECAM_BUS_MASK 0x0FF00000u /* Device Number Mask */ #define PCIE_ECAM_DEV_MASK 0x000F8000u /* Function Number Mask */ #define PCIE_ECAM_FUN_MASK 0x00007000u /* Bus Number Shift Value */ #define PCIE_ECAM_BUS_SHIFT 20u /* Device Number Shift Value */ #define PCIE_ECAM_DEV_SHIFT 15u /* Function Number Shift Value */ #define PCIE_ECAM_FUN_SHIFT 12u #define BAR_MASK 0xFFFFFFFFu #define BAR_SIZE_MASK 0xFFFFFFF0u #define BAR_LSB_MASK 0x0000000Fu #define VENDOR_ID_MASK 0xFFFFu /* 64-bit Address space of BAR */ #define ADDR_SPACE_64BIT 0x00000004u /* Translated ID */ #define PCIE_TX_RX_INTERFACE 0x00000000u #define PCIE_CONFIG_INTERFACE 0x00000001u #define AXI4_MASTER_0_INTERFACE 0x00000004u /* Translation table size 256MB */ #define SIZE_256MB_TRANSLATE_TABLE_EN 0x00000037u /* PCIe Root Port Control & Status Register: enable I/O, memory access, bus master,Parity Error Response and SERR# */ #define RP_CFG_PRMSCR_DATA 0x00000147u /* PCIe EndPoint Control & Status Register: enable Memory access, bus master */ #define EP_CFG_PRMSCR_DATA 0x00000006u /* device conrol status register: maxrdreq=512, maxpayloadsize=256 */ #define RP_DEVICE_CTRL_STATUS_DATA 0x0000202Fu #define EP_DEVICE_CTRL_STATUS_DATA 0x00FF2830u /* PCIe Sub bus:FF, sec bus:0, prim bus:0 */ #define PRIM_SEC_SUB_BUS_DEFAULT 0x00FF0000u /* Non-prefetchable Limit, Non-prefetchable Base */ #define RP_MEM_LIMIT_BASE_DATA 0xEEE0EEE0u /* Prefetchable Limit, Prefetchable Base */ #define RP_PREF_MEM_LIMIT_BASE_DATA 0xFFF1FFF1u /* Prefetchable Base upper */ #define RP_PREF_BASE_UPPER_DATA 0xFFFFFFFFu /* Prefetchable upper limit*/ #define RP_PREF_LIMIT_UPPER_DATA 0x00000000u /* PCIe Config space MSI capability structure */ #define PCIE_ENABLE_MSI 0x00010000u #define PCIE_CAPB_ID_MSI 0x05u #define PCIE_CAPB_ID_MASK 0xFFu #define PCIE_CONFIG_CAPB_ID_MASK 0xFFFFFFFFFFFFFF00u #define PCIE_MSI_64BIT_CAPB_ADDR 0x00800000u #define PCIE_MSI_MULTI_VECTOR_SHIFT 17u #define PCIE_MSI_MULTI_VECTOR_MASK 7u #define PCIE_MSI_MULTI_ENABLE_SHIFT 20u /* PCI Express Capability structure ID */ #define PCIE_CAPB_ID_STRUCT 0x10u /****************************************************************************/ /* PCIe AXI master table init defines */ #define ATR0_PCIE_WIN0_OFFSET 0x600u #define ATR_WIN_REG_TABLE_SIZE 0x20u #define WIN0_SRCADDR_PARAM 0x00u #define WIN0_SRC_ADDR 0x01u #define WIN0_TRSL_ADDR_LSB 0x02u #define WIN0_TRSL_ADDR_UDW 0x03u #define WIN0_TRSL_PARAM 0x04u #define ATR_ADDR_MASK 0xFFFFF000u #define TLP_SHIFT 16u #define BAR_01_DW0 0xE4u /****************************************************************************/ /* PCIe AXI slave table init defines */ #define ATR0_AXI4_SLV0_OFFSET 0x800u #define ATR_SLV_REG_TABLE_SIZE 0x20u #define SLV0_SRCADDR_PARAM 0x00u #define SLV0_SRC_ADDR 0x01u #define SLV0_TRSL_ADDR_LSB 0x02u #define SLV0_TRSL_ADDR_UDW 0x03u #define SLV0_TRSL_PARAM 0x04u /****************************************************************************/ /* DMA */ #define EP_DMA_START_DATA 0x00002321u #define EP_DMA_INTERFACE_AXI 0x00000004u #define EP_DMA_INTERFACE_PCIE 0x00000000u /* EP DMA interrupt and error status */ #define DMA_INT_STATUS 0x00000003u #define DMA_ERR_STATUS 0x00000300u /* Enable PCIe Host MSI, INTx DMAx interrupts */ #define PCIE_HOST_INT_ENABLE 0x1F000FFFu /* Enable PCIe local DMAx, DMA error interrupts */ #define PCIE_LOCAL_INT_ENABLE 0x1F0000FFu /****************************************************************************/ /* Clear PCIe interrupt events */ #define PCIE_EVENT_INT_DATA 0x00070007u #define PCIE_ECC_DISABLE 0x0F000000u #define PCIE_SEC_ERROR_INT_CLEAR 0x0000FFFFu #define PCIE_DED_ERROR_INT_CLEAR 0x0000FFFFu #define PCIE_ISTATUS_CLEAR 0xFFFFFFFFu #define PCIE_CLEAR 0x00000000u #define PCIE_SET 0x00000001u #define ROOT_PORT_ENABLE 0x00000001u #define NULL_POINTER ((void *)0) #define MASK_32BIT 0xFFFFFFFFu #define SHIFT_32BIT 32u struct pcie_dma_instance_t { volatile pf_pcie_ep_dma_status_t state; pf_pcie_write_callback_t tx_complete_handler; pf_pcie_read_callback_t rx_complete_handler; }; /* EP dma struct variable */ static struct pcie_dma_instance_t g_pcie_dma; /* RP and EP bridge and controller structure variable */ static PCIE_BRIDGE * g_rp_pcie_bridge = PCIE_CLEAR; static PCIE_BRIDGE * g_ep_bridge_reg = PCIE_CLEAR; static PCIE_CTRL * g_ep_ctrl_reg = PCIE_CLEAR; static PCIE_CTRL * g_rp_pcie_ctrl = PCIE_CLEAR; /* Enumeration and BAR structure variable */ pf_pcie_ebuff_t g_pcie_enumeration; pf_pcie_bar_info_t g_pcie_bar_allocate; /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * * This function is valid only when IP is configured as a root complex. * */ pf_pcie_ebuff_t * PF_PCIE_enumeration ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr ) { PCIE_BRIDGE * p_pcie_bridge; PCIE_END_CONF * p_pcie_config_space; PCIE_ROOT_CONF * p_pcie_root_config; PCIE_CTRL * p_pcie_ctrl; uint32_t * p_pcie_ep_config_space = PCIE_CLEAR; uint32_t pcie_header_type; uint32_t pcie_multi_fun; uint8_t pcie_bus_num; uint8_t pcie_dev_num; uint8_t pcie_fun_num; uint16_t pcie_vendor_id; uint64_t src_ecam_addr; uint32_t addr_inc; uint32_t p_reg; uint32_t ecam_addr_low; uint32_t ecam_addr_high; /* Default attached bridges and devices are 0 */ uint8_t bridges_attached = PCIE_CLEAR; uint8_t devices_attached = PCIE_CLEAR; uint32_t prim_sec_num = PRIM_SEC_SUB_BUS_DEFAULT; /* Default bridge and device enumeration number is 0 */ g_pcie_enumeration.no_of_bridges_attached = PCIE_CLEAR; g_pcie_enumeration.no_of_devices_attached = PCIE_CLEAR; /* Check PCIe Controller is 0 or 1 */ if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { /* PCIe Bridge Controller 0 */ p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE0_CRTL_PHY_ADDR_OFFSET))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { /* PCIe Bridge Controller 1 */ p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE1_CRTL_PHY_ADDR_OFFSET))); } else { /* Not supports PCIe Bridge Controller */ p_pcie_bridge = PCIE_CLEAR; } /* Check Root Port is enabled or not */ if ((NULL_POINTER != p_pcie_bridge) && (ROOT_PORT_ENABLE == ((p_pcie_bridge->GEN_SETTINGS) & ROOT_PORT_ENABLE))) { g_rp_pcie_bridge = p_pcie_bridge; g_rp_pcie_ctrl = p_pcie_ctrl; /* Clear interrupts on PCIe RootPort */ p_pcie_ctrl->ECC_CONTROL = PCIE_ECC_DISABLE; p_pcie_ctrl->PCIE_EVENT_INT = PCIE_EVENT_INT_DATA; p_pcie_ctrl->SEC_ERROR_INT = PCIE_SEC_ERROR_INT_CLEAR; p_pcie_ctrl->DED_ERROR_INT = PCIE_DED_ERROR_INT_CLEAR; p_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; p_pcie_bridge->IMASK_LOCAL = PCIE_CLEAR; p_pcie_bridge->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; p_pcie_bridge->IMASK_HOST = PCIE_CLEAR; ecam_addr_low = (uint32_t)(ecam_addr & MASK_32BIT); ecam_addr_high = (uint32_t)((ecam_addr >> SHIFT_32BIT) & MASK_32BIT); /* Select PCIe Config space */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; /* Address Translation table setup */ p_pcie_bridge->ATR0_AXI4_SLV0_SRCADDR_PARAM = ecam_addr_low | SIZE_256MB_TRANSLATE_TABLE_EN; p_pcie_bridge->ATR0_AXI4_SLV0_SRC_ADDR = ecam_addr_high; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_LSB = ecam_addr_low; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_UDW = ecam_addr_high; /* Enumeration starts here */ for (pcie_bus_num = PCIE_CLEAR; pcie_bus_num < PCIE_CFG_MAX_NUM_OF_BUS; pcie_bus_num++) { for (pcie_dev_num = PCIE_CLEAR; pcie_dev_num < PCIE_CFG_MAX_NUM_OF_DEV; pcie_dev_num++) { for (pcie_fun_num = PCIE_CLEAR; pcie_fun_num < PCIE_CFG_MAX_NUM_OF_FUN; pcie_fun_num++) { /* Calculate ECAM address based on AXI slave base address and bus, device and fun num */ src_ecam_addr = ecam_address_calc(ecam_addr, pcie_bus_num, pcie_dev_num, pcie_fun_num); p_pcie_config_space = (PCIE_END_CONF *)((uintptr_t)src_ecam_addr); /* Read Vendor ID of PCIe RP or EP */ pcie_vendor_id = ((uint16_t)((p_pcie_config_space->VID_DEVID) & VENDOR_ID_MASK)); /* Check Vendor ID is 0xFFFF then no need search */ if (PCIE_CFG_FUN_NOT_IMP_MASK == pcie_vendor_id) { if (PCIE_CLEAR == pcie_fun_num) { /* * don't need to search * further on this device. */ break; } } else { /* Header Type */ pcie_header_type = p_pcie_config_space->BIST_HEADER & PCIE_CFG_HEADER_TYPE_MASK; pcie_multi_fun = p_pcie_config_space->BIST_HEADER & PCIE_CFG_MUL_FUN_DEV_MASK; /* Check header type is type0 for PCIe EndPoint */ if (PCIE_CFG_HEADER_O_TYPE == pcie_header_type) { g_pcie_enumeration.devices[devices_attached].bus_num = pcie_bus_num; g_pcie_enumeration.devices[devices_attached].dev_num = pcie_dev_num; g_pcie_enumeration.devices[devices_attached].fun_num = pcie_fun_num; g_pcie_enumeration.devices[devices_attached].vendor_id = pcie_vendor_id; ++devices_attached; g_pcie_enumeration.no_of_devices_attached = devices_attached; /* Enable config space memory access bus master and cache size */ p_pcie_config_space->CFG_PRMSCR |= (EP_CFG_PRMSCR_DATA); p_pcie_config_space->BIST_HEADER = PCIE_CFG_CATCHE_SIZE; p_pcie_ep_config_space = (uint32_t *)((uintptr_t)src_ecam_addr); /* PCIe configuration header starts after standard size - 0x40/4 = 0x10 */ p_pcie_ep_config_space = p_pcie_ep_config_space + 0x10u; for (addr_inc = PCIE_CLEAR; addr_inc < 48u; ++addr_inc) { /* Read Capability ID 10h for PCI Express Capability structure */ p_reg = *(p_pcie_ep_config_space + addr_inc); if (PCIE_CAPB_ID_STRUCT == (p_reg & PCIE_CAPB_ID_MASK)) { break; } } if (addr_inc < 48u) { /* Device control and status offset */ addr_inc = addr_inc + 2u; /* End Point control and status configure */ *(p_pcie_ep_config_space + addr_inc) = EP_DEVICE_CTRL_STATUS_DATA; } } else { /* Header type is Type1 * This is a bridge or Root Port */ /* Check bus num is '0' for Root Port*/ if (PCIE_CLEAR == pcie_bus_num) { p_pcie_root_config = (PCIE_ROOT_CONF *)((uintptr_t)src_ecam_addr); prim_sec_num |= (uint32_t)(((((uint32_t)pcie_bus_num) + PCIE_SET) << 8u) | pcie_bus_num); /* Sub bus num 0xFF, sec bus num 1, and prime bus num 0 */ p_pcie_root_config->PRIM_SEC_BUS_NUM = prim_sec_num; /* Control & Status Register: enable bus master, * Parity Error Response and SERR# */ p_pcie_root_config->CFG_PRMSCR = RP_CFG_PRMSCR_DATA; /* Non-prefetchable Limit, Non-prefetchable Base */ p_pcie_root_config->MEM_LIMIT_BASE = RP_MEM_LIMIT_BASE_DATA; /* Prefetchable Limit, Prefetchable Base */ p_pcie_root_config->PREF_MEM_LIMIT_BASE = RP_PREF_MEM_LIMIT_BASE_DATA; /* Prefetchable Base upper */ p_pcie_root_config->PREF_BASE_UPPER = RP_PREF_BASE_UPPER_DATA; /* Prefetchable upper limit*/ p_pcie_root_config->PREF_LIMIT_UPPER = RP_PREF_LIMIT_UPPER_DATA; p_pcie_root_config->DEVICE_CTRL_STAT = RP_DEVICE_CTRL_STATUS_DATA; } else { /* The PCIe bridge primary and secondary bus setup */ prim_sec_num |= (uint32_t)(((((uint32_t)pcie_bus_num) + PCIE_SET) << 8u) | pcie_bus_num); p_pcie_root_config = (PCIE_ROOT_CONF *)((uintptr_t)src_ecam_addr); p_pcie_root_config->PRIM_SEC_BUS_NUM = prim_sec_num; p_pcie_root_config->CFG_PRMSCR = RP_CFG_PRMSCR_DATA; } g_pcie_enumeration.bridges[bridges_attached].bus_num = pcie_bus_num; g_pcie_enumeration.bridges[bridges_attached].dev_num = pcie_dev_num; g_pcie_enumeration.bridges[bridges_attached].fun_num = pcie_fun_num; g_pcie_enumeration.bridges[bridges_attached].vendor_id = pcie_vendor_id; ++bridges_attached; g_pcie_enumeration.no_of_bridges_attached = bridges_attached; } if ((PCIE_CLEAR == pcie_fun_num) && (PCIE_CLEAR == pcie_multi_fun)) { /* * If it is function 0 and it is not a * multi function device, don't need * to search further on this device */ break; } } } } } /* Selects PCIe Tx/RxInterface */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } return &g_pcie_enumeration; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ pf_pcie_bar_info_t * PF_PCIE_allocate_memory ( uint64_t ecam_addr, uint64_t allocate_addr ) { PCIE_END_CONF * p_pcie_config_space; uint32_t pcie_header_type; uint64_t axi_trns_base_addr = allocate_addr; uint32_t axi_trns_base_addr_low; uint32_t axi_trns_base_addr_high; uint32_t read_bar, lsb4bits_bar; axi_trns_base_addr_low = (uint32_t)(allocate_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((allocate_addr >> SHIFT_32BIT) & MASK_32BIT); /* Default BAR and BAR size is 0 */ g_pcie_bar_allocate.bar0_address = PCIE_CLEAR; g_pcie_bar_allocate.bar0_size = PCIE_CLEAR; g_pcie_bar_allocate.bar1_address = PCIE_CLEAR; g_pcie_bar_allocate.bar1_size = PCIE_CLEAR; g_pcie_bar_allocate.bar2_address = PCIE_CLEAR; g_pcie_bar_allocate.bar2_size = PCIE_CLEAR; g_pcie_bar_allocate.bar3_address = PCIE_CLEAR; g_pcie_bar_allocate.bar3_size = PCIE_CLEAR; g_pcie_bar_allocate.bar4_address = PCIE_CLEAR; g_pcie_bar_allocate.bar4_size = PCIE_CLEAR; g_pcie_bar_allocate.bar5_address = PCIE_CLEAR; g_pcie_bar_allocate.bar5_size = PCIE_CLEAR; /* Check PCIe bridge is enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { /* Select PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; p_pcie_config_space = (PCIE_END_CONF *)((uintptr_t)ecam_addr); pcie_header_type = PCIE_CLEAR; /* Header Type */ pcie_header_type = p_pcie_config_space->BIST_HEADER & PCIE_CFG_HEADER_TYPE_MASK; /* Write 0xFFFFFFFF to read PCIe BAR0 */ p_pcie_config_space->BAR0 = BAR_MASK; /* Read BAR0 */ read_bar = p_pcie_config_space->BAR0; /* Lower 4-bits of BAR0 */ lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR0 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR0 */ p_pcie_config_space->BAR0 = axi_trns_base_addr_low | lsb4bits_bar; if (ADDR_SPACE_64BIT == (lsb4bits_bar & ADDR_SPACE_64BIT)) { p_pcie_config_space->BAR1 = axi_trns_base_addr_high; g_pcie_bar_allocate.bar1_address = axi_trns_base_addr_high; } g_pcie_bar_allocate.bar0_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar0_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } /* Check BAR0 is not 64-bit address space */ if (ADDR_SPACE_64BIT != (lsb4bits_bar & ADDR_SPACE_64BIT)) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR1 */ p_pcie_config_space->BAR1 = BAR_MASK; /* Read BAR1 */ read_bar = p_pcie_config_space->BAR1; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR1 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR1 */ p_pcie_config_space->BAR1 = axi_trns_base_addr_low | lsb4bits_bar; g_pcie_bar_allocate.bar1_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar1_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } } if (PCIE_CFG_HEADER_O_TYPE == pcie_header_type) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR2 */ p_pcie_config_space->BAR2 = BAR_MASK; /* Read BAR2 */ read_bar = p_pcie_config_space->BAR2; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR2 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR2 */ p_pcie_config_space->BAR2 = axi_trns_base_addr_low | lsb4bits_bar; if (ADDR_SPACE_64BIT == (lsb4bits_bar & ADDR_SPACE_64BIT)) { p_pcie_config_space->BAR3 = axi_trns_base_addr_high; g_pcie_bar_allocate.bar3_address = axi_trns_base_addr_high; } g_pcie_bar_allocate.bar2_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar2_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } /* Check BAR2 is not 64-bit address space */ if (ADDR_SPACE_64BIT != (lsb4bits_bar & ADDR_SPACE_64BIT)) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR3 */ p_pcie_config_space->BAR3 = BAR_MASK; /* Read BAR3 */ read_bar = p_pcie_config_space->BAR3; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR3 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR3 */ p_pcie_config_space->BAR3 = axi_trns_base_addr_low | lsb4bits_bar; g_pcie_bar_allocate.bar3_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar3_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } } axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR4 */ p_pcie_config_space->BAR4 = BAR_MASK; /* Read BAR4 */ read_bar = p_pcie_config_space->BAR4; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR4 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR4 */ p_pcie_config_space->BAR4 = axi_trns_base_addr_low | lsb4bits_bar; if (ADDR_SPACE_64BIT == (lsb4bits_bar & ADDR_SPACE_64BIT)) { p_pcie_config_space->BAR5 = axi_trns_base_addr_high; g_pcie_bar_allocate.bar5_address = axi_trns_base_addr_high; } g_pcie_bar_allocate.bar4_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar4_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } /* Check BAR4 is not 64-bit address space */ if (ADDR_SPACE_64BIT != (lsb4bits_bar & ADDR_SPACE_64BIT)) { axi_trns_base_addr_low = (uint32_t)(axi_trns_base_addr & MASK_32BIT); axi_trns_base_addr_high = (uint32_t)((axi_trns_base_addr >> SHIFT_32BIT) & MASK_32BIT); /* Write 0xFFFFFFFF to read PCIe BAR5 */ p_pcie_config_space->BAR5 = BAR_MASK; /* Read BAR5 */ read_bar = p_pcie_config_space->BAR5; lsb4bits_bar = read_bar & BAR_LSB_MASK; /* Calculate BAR5 size */ read_bar &= BAR_SIZE_MASK; read_bar = ~(read_bar) + PCIE_SET; if (read_bar != PCIE_CLEAR) { /* Write Translation address in EP BAR5 */ p_pcie_config_space->BAR5 = axi_trns_base_addr_low | lsb4bits_bar; g_pcie_bar_allocate.bar5_address = axi_trns_base_addr_low; g_pcie_bar_allocate.bar5_size = read_bar; axi_trns_base_addr = axi_trns_base_addr + read_bar; } } } /* Selects PCIe Tx/RxInterface */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } return &g_pcie_bar_allocate; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_enable_config_space_msi ( uint64_t ecam_addr, uint64_t msi_addr, uint16_t msi_data ) { uint32_t * p_pcie_config_space; uint32_t addr_inc; uint32_t p_reg; uint32_t msi_addr_low; uint32_t msi_addr_high; if (NULL_POINTER != g_rp_pcie_bridge) { msi_addr_low = (uint32_t)(msi_addr & MASK_32BIT); msi_addr_high = (uint32_t)((msi_addr >> SHIFT_32BIT) & MASK_32BIT); /* Select PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; p_pcie_config_space = (uint32_t *)((uintptr_t)(ecam_addr & PCIE_CONFIG_CAPB_ID_MASK)); /* PCIe configuration header starts after standard size - 0x40/4 = 0x10*/ p_pcie_config_space = p_pcie_config_space + 0x10u; for (addr_inc = PCIE_CLEAR; addr_inc < 48u; ++addr_inc) { /* Read Capability ID 05h for MSI */ p_reg = *(p_pcie_config_space + addr_inc); if (PCIE_CAPB_ID_MSI == (p_reg & PCIE_CAPB_ID_MASK)) { break; } } if (addr_inc < 48u) { p_reg = *(p_pcie_config_space + addr_inc); /* Read number of requested vectors(multiple messages capable) */ p_reg = (p_reg >> PCIE_MSI_MULTI_VECTOR_SHIFT) & PCIE_MSI_MULTI_VECTOR_MASK; /* Numbers of allocated vectors (multiple messages enable) */ p_reg = p_reg << PCIE_MSI_MULTI_ENABLE_SHIFT; /* Enable MSI */ *(p_pcie_config_space + addr_inc) |= (p_reg | PCIE_ENABLE_MSI); p_reg = *(p_pcie_config_space + addr_inc); ++addr_inc; /* MSI message lower address */ *(p_pcie_config_space + addr_inc) = msi_addr_low; ++addr_inc; /* MSI mesage upper address */ if (PCIE_MSI_64BIT_CAPB_ADDR == (p_reg & PCIE_MSI_64BIT_CAPB_ADDR)) { *(p_pcie_config_space + addr_inc) = msi_addr_high; ++addr_inc; } /* MSI message data */ *(p_pcie_config_space + addr_inc) = msi_data; } /* Selects PCIe Tx/RxInterface */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * PCIe reads type1 configuration space of pcie bridge or switch. */ void PF_PCIE_type1_header_read ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr, PCIE_ROOT_CONF * p_type1_header ) { PCIE_BRIDGE * p_pcie_bridge; PCIE_ROOT_CONF * p_pcie_type1_header; uint32_t pcie_header_type; uint32_t ecam_addr_low; uint32_t ecam_addr_high; if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); } else { p_pcie_bridge = NULL_POINTER; } /* Check Root Port */ if ((NULL_POINTER != p_pcie_bridge) && (ROOT_PORT_ENABLE == (p_pcie_bridge->GEN_SETTINGS & ROOT_PORT_ENABLE))) { ecam_addr_low = (uint32_t)(ecam_addr & MASK_32BIT); ecam_addr_high = (uint32_t)((ecam_addr >> SHIFT_32BIT) & MASK_32BIT); /* Selects PCIe Config space */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; p_pcie_bridge->ATR0_AXI4_SLV0_SRCADDR_PARAM = ecam_addr_low | SIZE_256MB_TRANSLATE_TABLE_EN ; p_pcie_bridge->ATR0_AXI4_SLV0_SRC_ADDR = ecam_addr_high; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_LSB = ecam_addr_low; p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_UDW = ecam_addr_high; p_pcie_type1_header = (PCIE_ROOT_CONF *)((uintptr_t)ecam_addr); /* Header Type */ pcie_header_type = p_pcie_type1_header->BIST_HEADER & PCIE_CFG_HEADER_TYPE_MASK; if (PCIE_CFG_HEADER_O_TYPE != pcie_header_type) { p_type1_header->VID_DEVID = p_pcie_type1_header->VID_DEVID; p_type1_header->CFG_PRMSCR = p_pcie_type1_header->CFG_PRMSCR; p_type1_header->CLASS_CODE = p_pcie_type1_header->CLASS_CODE; p_type1_header->BIST_HEADER = p_pcie_type1_header->BIST_HEADER; p_type1_header->BAR0 = p_pcie_type1_header->BAR0; p_type1_header->BAR1 = p_pcie_type1_header->BAR1; p_type1_header->PRIM_SEC_BUS_NUM = p_pcie_type1_header->PRIM_SEC_BUS_NUM; p_type1_header->IO_LIMIT_BASE = p_pcie_type1_header->IO_LIMIT_BASE; p_type1_header->MEM_LIMIT_BASE = p_pcie_type1_header->MEM_LIMIT_BASE; p_type1_header->PREF_MEM_LIMIT_BASE = p_pcie_type1_header->PREF_MEM_LIMIT_BASE; p_type1_header->PREF_BASE_UPPER = p_pcie_type1_header->PREF_BASE_UPPER; p_type1_header->PREF_LIMIT_UPPER = p_pcie_type1_header->PREF_LIMIT_UPPER; p_type1_header->IO_LIMIT_BASE_UPPER = p_pcie_type1_header->IO_LIMIT_BASE_UPPER; p_type1_header->CAPAB_POINTER = p_pcie_type1_header->CAPAB_POINTER; p_type1_header->EXPAN_ROM_BASE = p_pcie_type1_header->EXPAN_ROM_BASE; p_type1_header->INT_LINE_PIN = p_pcie_type1_header->INT_LINE_PIN; } /* Selects PCIe Tx/RxInterface */ p_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ uint8_t PF_PCIE_config_space_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr ) { uint8_t returnval = PF_PCIE_ATR_TABLE_INIT_SUCCESS; uint32_t ecam_addr_low; uint32_t ecam_addr_high; if (NULL_POINTER == g_rp_pcie_bridge) { if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { g_rp_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); g_rp_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE0_CRTL_PHY_ADDR_OFFSET))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { g_rp_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); g_rp_pcie_ctrl = ((PCIE_CTRL *)((uintptr_t)(apb_addr + PCIE1_CRTL_PHY_ADDR_OFFSET))); } else { g_rp_pcie_bridge = NULL_POINTER; returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } if (NULL_POINTER != g_rp_pcie_bridge) { /* Clear interrupts on PCIe RootPort */ g_rp_pcie_ctrl->ECC_CONTROL = PCIE_ECC_DISABLE; g_rp_pcie_ctrl->PCIE_EVENT_INT = PCIE_EVENT_INT_DATA; g_rp_pcie_ctrl->SEC_ERROR_INT = PCIE_SEC_ERROR_INT_CLEAR; g_rp_pcie_ctrl->DED_ERROR_INT = PCIE_DED_ERROR_INT_CLEAR; g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->IMASK_LOCAL = PCIE_CLEAR; g_rp_pcie_bridge->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->IMASK_HOST = PCIE_CLEAR; } } if (NULL_POINTER != g_rp_pcie_bridge) { /* Check Root Port */ if (ROOT_PORT_ENABLE == (g_rp_pcie_bridge->GEN_SETTINGS & ROOT_PORT_ENABLE)) { ecam_addr_low = (uint32_t)(ecam_addr & MASK_32BIT); ecam_addr_high = (uint32_t)((ecam_addr >> SHIFT_32BIT) & MASK_32BIT); /* Selects PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_CONFIG_INTERFACE; g_rp_pcie_bridge->ATR0_AXI4_SLV0_SRCADDR_PARAM = ecam_addr_low | SIZE_256MB_TRANSLATE_TABLE_EN; g_rp_pcie_bridge->ATR0_AXI4_SLV0_SRC_ADDR = ecam_addr_high; g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_LSB = ecam_addr_low; g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_ADDR_UDW = ecam_addr_high; } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } } return returnval; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_config_space_atr_table_terminate(void) { if (NULL_POINTER != g_rp_pcie_bridge) { /* Selects PCIe Tx/Rx Interface, disable PCIe Config space */ g_rp_pcie_bridge->ATR0_AXI4_SLV0_TRSL_PARAM = PCIE_TX_RX_INTERFACE; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * PCIe reads configuration space of end point or root port. */ void PF_PCIE_config_space_read ( uint64_t ecam_addr, uint16_t config_space_offset, uint32_t * value ) { volatile uint32_t * cfg_reg = (uint32_t *)((uintptr_t)(ecam_addr + config_space_offset)); *value = *(cfg_reg); } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * PCIe writes configuration space of end point or root port. */ void PF_PCIE_config_space_write ( uint64_t ecam_addr, uint16_t config_space_offset, uint32_t value ) { volatile uint32_t * cfg_reg = (uint32_t *)((uintptr_t)(ecam_addr + config_space_offset)); *(cfg_reg) = value; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ uint8_t PF_PCIE_master_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, pf_pcie_master_atr_cfg_t * cfg, uint8_t master_table_num, uint8_t tlp_type ) { uint32_t * p_pcie_master_table; uint32_t * p_pcie_bar; PCIE_BRIDGE * p_pcie_bridge; uint32_t phy_reg; uint8_t returnval = PF_PCIE_ATR_TABLE_INIT_SUCCESS; /* Set pcie bridge base address for ATR master table based on pcie controller 0/1 */ if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_master_table = ((uint32_t *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + ATR0_PCIE_WIN0_OFFSET + (master_table_num * ATR_WIN_REG_TABLE_SIZE)))); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 8u)))); } else { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 4u)))); } } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { p_pcie_bridge = ((PCIE_BRIDGE *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET))); p_pcie_master_table = ((uint32_t *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + ATR0_PCIE_WIN0_OFFSET + (master_table_num * ATR_WIN_REG_TABLE_SIZE)))); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 8u)))); } else { p_pcie_bar = ((uint32_t *)((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + BAR_01_DW0 + (master_table_num * 4u)))); } } else { p_pcie_bridge = NULL_POINTER; } /* Check for pcie bridge controller base address */ if (NULL_POINTER != p_pcie_bridge) { /* Check for PCIe Root Port */ if (ROOT_PORT_ENABLE == (p_pcie_bridge->GEN_SETTINGS & ROOT_PORT_ENABLE)) { if (master_table_num < 2u) { /* Write BAR_01 or BAR_23 size and bar type */ phy_reg = ~((1u << (cfg->bar_size + 1u)) -1u); *p_pcie_bar = (phy_reg | cfg->bar_type); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { /* Bar size mask in BAR_01/23_DW1 [64:32] bit */ *(p_pcie_bar + 1u) = BAR_MASK; } } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } } else /* End Point */ { if (master_table_num < 6u) { /* Write BAR_01 or BAR_23 or BAR_45 size and bar type */ phy_reg = ~((1u << (cfg->bar_size + 1u)) -1u); *p_pcie_bar = (phy_reg | cfg->bar_type); if (cfg->bar_type == PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM) { /* Bar size mask in BAR_01/23/45_DW1 [64:32] bit */ *(p_pcie_bar + 1u) = BAR_MASK; } } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } } if (PF_PCIE_ATR_TABLE_INIT_SUCCESS == returnval) { phy_reg = (uint32_t)(cfg->src_addr & ATR_ADDR_MASK); phy_reg |= (uint32_t)((cfg->table_size) << PCIE_SET); phy_reg |= (uint32_t)(cfg->state); /* Set ATR Master SRC LSB address */ *(p_pcie_master_table + WIN0_SRCADDR_PARAM) = phy_reg; /* Set ATR Master SRC MSB address */ *(p_pcie_master_table + WIN0_SRC_ADDR) = (cfg->src_addr_msb); /* Set ATR Master TRNSL LSB address */ *(p_pcie_master_table + WIN0_TRSL_ADDR_LSB) = (cfg->trns_addr & ATR_ADDR_MASK); /* Set ATR Master TRNSL MSB address */ *(p_pcie_master_table + WIN0_TRSL_ADDR_UDW) = (cfg->trns_addr_msb); /* Set TLP type and TRSL_ID value */ *(p_pcie_master_table + WIN0_TRSL_PARAM) = ((uint32_t)tlp_type << TLP_SHIFT) | AXI4_MASTER_0_INTERFACE; } } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } return returnval; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ uint8_t PF_PCIE_slave_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, pf_pcie_slave_atr_cfg_t * cfg, uint8_t slave_table_num, uint8_t tlp_type ) { uint32_t * p_pcie_slave; uint32_t phy_reg = PCIE_CLEAR; uint8_t returnval = PF_PCIE_ATR_TABLE_INIT_SUCCESS; /* Set pcie bridge base address for ATR slave table based on pcie controlle 0/1 */ if (PF_PCIE_CTRL_0 == pcie_ctrl_num) { p_pcie_slave = ((uint32_t * )((uintptr_t)(apb_addr + PCIE0_BRIDGE_PHY_ADDR_OFFSET + ATR0_AXI4_SLV0_OFFSET + (slave_table_num * ATR_SLV_REG_TABLE_SIZE)))); } else if (PF_PCIE_CTRL_1 == pcie_ctrl_num) { p_pcie_slave = ((uint32_t * )((uintptr_t)(apb_addr + PCIE1_BRIDGE_PHY_ADDR_OFFSET + ATR0_AXI4_SLV0_OFFSET + (slave_table_num * ATR_SLV_REG_TABLE_SIZE)))); } else { p_pcie_slave = NULL_POINTER; } /* Check for pcie bridge controller base address */ if (NULL_POINTER != p_pcie_slave) { phy_reg = (uint32_t)(cfg->src_addr & ATR_ADDR_MASK); phy_reg |= (uint32_t)((cfg->size) << PCIE_SET); phy_reg |= (uint32_t)(cfg->state); /* Set ATR slave SRC LSB address */ *(p_pcie_slave + SLV0_SRCADDR_PARAM) = phy_reg; /* Set ATR slave SRC MSB address */ *(p_pcie_slave + SLV0_SRC_ADDR) = (cfg->src_addr_msb); /* Set ATR slave TRNSL LSB address */ phy_reg = (cfg->trns_addr & ATR_ADDR_MASK); *(p_pcie_slave + SLV0_TRSL_ADDR_LSB) = phy_reg; /* Set ATR slave TRNSL LSB address */ *(p_pcie_slave + SLV0_TRSL_ADDR_UDW) = (cfg->trns_addr_msb); /* Set TLP type */ *(p_pcie_slave + SLV0_TRSL_PARAM) = ((uint32_t)tlp_type << TLP_SHIFT) | PCIE_TX_RX_INTERFACE; } else { returnval = PF_PCIE_ATR_TABLE_INIT_FAILURE; } return returnval; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_init(uint64_t allocated_addr) { g_ep_bridge_reg = (PCIE_BRIDGE *)((uintptr_t)allocated_addr); g_ep_ctrl_reg = (PCIE_CTRL *)((uintptr_t)(allocated_addr + 0x2000u)); /* Disable EP ECC interrupts and clear status bits */ g_ep_ctrl_reg->ECC_CONTROL = PCIE_ECC_DISABLE; g_ep_ctrl_reg->PCIE_EVENT_INT = PCIE_EVENT_INT_DATA; g_ep_ctrl_reg->SEC_ERROR_INT = PCIE_SEC_ERROR_INT_CLEAR; g_ep_ctrl_reg->DED_ERROR_INT = PCIE_DED_ERROR_INT_CLEAR; /* Disable and clear Local and Host interrupts on EP */ g_ep_bridge_reg->IMASK_LOCAL = PCIE_CLEAR; g_ep_bridge_reg->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_ep_bridge_reg->IMASK_HOST = PCIE_CLEAR; g_ep_bridge_reg->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; /* Enable PCIe Host MSI, INTx DMAx interrupts on EP */ g_ep_bridge_reg->IMASK_HOST= PCIE_HOST_INT_ENABLE; g_ep_bridge_reg->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; /* initialize default interrupt handlers */ g_pcie_dma.tx_complete_handler = NULL_POINTER; g_pcie_dma.rx_complete_handler = NULL_POINTER; g_pcie_dma.state = PF_PCIE_EP_DMA_COMPLETED; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_set_dma_write_callback ( pf_pcie_write_callback_t write_callback ) { g_pcie_dma.tx_complete_handler = write_callback; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_set_dma_read_callback ( pf_pcie_read_callback_t rx_callback ) { g_pcie_dma.rx_complete_handler = rx_callback; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_abort(void) { if(NULL_POINTER != g_ep_bridge_reg) { g_ep_bridge_reg->DMA0_CONTROL = PCIE_CLEAR; g_ep_bridge_reg->DMA1_CONTROL = PCIE_CLEAR; } g_pcie_dma.state = PF_PCIE_EP_DMA_COMPLETED; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_read ( uint64_t src_address, uint64_t dest_address, uint32_t rx_lenth ) { /* Check EP bridge access enabled with DMA */ if (NULL_POINTER != g_ep_bridge_reg) { if ((PF_PCIE_EP_DMA_IN_PROGRESS != g_pcie_dma.state) && (rx_lenth > 0u)) { g_ep_bridge_reg->DMA1_CONTROL = PCIE_CLEAR; /* DMA from EP to RP - source EP AXI-Master, destination PCIe - DMA1 */ /* AXI4-Master Interface for Source*/ g_ep_bridge_reg->DMA1_SRC_PARAM = EP_DMA_INTERFACE_AXI; /* PCIe Interface for Destination */ g_ep_bridge_reg->DMA1_DESTPARAM = EP_DMA_INTERFACE_PCIE; /* Set source address */ g_ep_bridge_reg->DMA1_SRCADDR_LDW = (uint32_t)(src_address & MASK_32BIT); g_ep_bridge_reg->DMA1_SRCADDR_UDW = (uint32_t)((src_address >> SHIFT_32BIT) & MASK_32BIT); /* Set destination address*/ g_ep_bridge_reg->DMA1_DESTADDR_LDW = (uint32_t)(dest_address & MASK_32BIT); g_ep_bridge_reg->DMA1_DESTADDR_UDW = (uint32_t)((dest_address >> SHIFT_32BIT) & MASK_32BIT); /* Set dma size */ g_ep_bridge_reg->DMA1_LENGTH = rx_lenth; /*Start dma transaction */ g_ep_bridge_reg->DMA1_CONTROL = EP_DMA_START_DATA; g_pcie_dma.state = PF_PCIE_EP_DMA_IN_PROGRESS; } } else { g_pcie_dma.state = PF_PCIE_EP_DMA_NOT_INITIALIZED; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_dma_write ( uint64_t src_address, uint64_t dest_address, uint32_t tx_lenth ) { /* Check EP bridge access enabled with DMA */ if (NULL_POINTER != g_ep_bridge_reg) { if ((PF_PCIE_EP_DMA_IN_PROGRESS != g_pcie_dma.state) && (tx_lenth > 0u)) { g_ep_bridge_reg->DMA0_CONTROL = PCIE_CLEAR; /* DMA from RP to EP - source RP-PCIe, destination AXI-Master - DMA0 */ /* PCIe Interface for Source */ g_ep_bridge_reg->DMA0_SRC_PARAM = EP_DMA_INTERFACE_PCIE; /*AXI4-Master Interface for Destination*/ g_ep_bridge_reg->DMA0_DESTPARAM = EP_DMA_INTERFACE_AXI; /* Set source address */ g_ep_bridge_reg->DMA0_SRCADDR_LDW = (uint32_t)(src_address & MASK_32BIT); g_ep_bridge_reg->DMA0_SRCADDR_UDW = (uint32_t)((src_address >> SHIFT_32BIT) & MASK_32BIT); /* Set destination address*/ g_ep_bridge_reg->DMA0_DESTADDR_LDW = (uint32_t)(dest_address & MASK_32BIT); g_ep_bridge_reg->DMA0_DESTADDR_UDW = (uint32_t)((dest_address >> SHIFT_32BIT) & MASK_32BIT); /* Set dma size */ g_ep_bridge_reg->DMA0_LENGTH = tx_lenth; /*Start dma transaction */ g_ep_bridge_reg->DMA0_CONTROL = EP_DMA_START_DATA; g_pcie_dma.state = PF_PCIE_EP_DMA_IN_PROGRESS; } } else { g_pcie_dma.state = PF_PCIE_EP_DMA_NOT_INITIALIZED; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ pf_pcie_ep_dma_status_t PF_PCIE_dma_get_transfer_status ( void ) { return g_pcie_dma.state; } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_enable_interrupts(void) { /* Check RP bridge access enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { g_rp_pcie_bridge->IMASK_LOCAL = PCIE_LOCAL_INT_ENABLE; g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->ISTATUS_MSI = PCIE_ISTATUS_CLEAR; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_disable_interrupts(void) { /* Check RP bridge access enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->IMASK_LOCAL= PCIE_CLEAR; } } /**************************************************************************//** * See pf_pciess.h for details of how to use this function. * */ void PF_PCIE_isr(void) { uint32_t phy_reg; /* Check RP bridge access enabled */ if (NULL_POINTER != g_rp_pcie_bridge) { phy_reg = g_rp_pcie_bridge->ISTATUS_LOCAL; phy_reg = g_rp_pcie_bridge->ISTATUS_MSI; /* Check EP bridge access enabled with DMA */ if (NULL_POINTER != g_ep_bridge_reg) { phy_reg = g_ep_bridge_reg->ISTATUS_HOST; /* Check EP DMA0/1 interrupt occurred */ if (PCIE_CLEAR != (phy_reg & DMA_INT_STATUS)) { g_ep_bridge_reg->ISTATUS_HOST = DMA_INT_STATUS; g_pcie_dma.state = PF_PCIE_EP_DMA_COMPLETED; if (NULL_POINTER != g_pcie_dma.tx_complete_handler) { g_pcie_dma.tx_complete_handler(PF_PCIE_EP_DMA_COMPLETED); } } else if (PCIE_CLEAR != (phy_reg & DMA_ERR_STATUS)) { g_ep_bridge_reg->ISTATUS_HOST = DMA_ERR_STATUS; g_pcie_dma.state = PF_PCIE_EP_DMA_ERROR; if (NULL_POINTER != g_pcie_dma.rx_complete_handler) { g_pcie_dma.rx_complete_handler(PF_PCIE_EP_DMA_ERROR); } } else { g_ep_bridge_reg->ISTATUS_HOST = PCIE_ISTATUS_CLEAR; } } g_rp_pcie_bridge->ISTATUS_MSI = PCIE_ISTATUS_CLEAR; g_rp_pcie_bridge->ISTATUS_LOCAL = PCIE_ISTATUS_CLEAR; } } /**************************************************************************** Compose an address to be written to configuration address port @param Bus is the external PCIe function's Bus number. @param Device is the external PCIe function's Device number. @param Function is the external PCIe function's Function number. @return 32 bit composed value (address). */ uint64_t ecam_address_calc ( uint64_t axi_addr, uint8_t bus, uint8_t device, uint8_t function ) { uint64_t location = PCIE_CLEAR; location |= ((((uint64_t)bus) << PCIE_ECAM_BUS_SHIFT) & PCIE_ECAM_BUS_MASK); location |= ((((uint64_t)device) << PCIE_ECAM_DEV_SHIFT) & PCIE_ECAM_DEV_MASK); location |= ((((uint64_t)function) << PCIE_ECAM_FUN_SHIFT) & PCIE_ECAM_FUN_MASK); location &= PCIE_ECAM_MASK; axi_addr = axi_addr + location; return axi_addr; } #ifdef __cplusplus } #endif pf_pcie.h000066400000000000000000001067011432224323300356410ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/pf_pcie/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * PolarFire and PolarFire SoC PCIe subsystem software driver public API * and data structure. * * SVN $Revision$ * SVN $Date$ */ /*=========================================================================*//** @mainpage PolarFire and PolarFire SoC PCIe Bare Metal Driver. @section intro_sec Introduction Microsemi PolarFire(tm) FPGAs(PolarFire and PolarFire SoC devices) contain a fully integrated PCIe endpoint and root port subsystems with optimized embedded controller blocks that connect to the physical layer interface of the PolarFire transceiver. Each PolarFire device includes two PolarFire embedded PCIe subsystem (PCIESS) blocks. The PCIESS is a hard PCI Express protocol stack embedded within every PolarFire device. It includes the transaction layer, data link layer, and physical layer. The PolarFire PCIESS includes both a physical coding sublayer (PCS) and a physical medium attachment (PMA) sublayer that supports x1, x2, and x4 endpoint and root port configurations at up to 5 Gbps (Gen 2) speeds. Note: All references to PolarFire in this document include both PolarFire and PolarFire SoC devices unless stated otherwise. The PolarFire PCIe software driver, provided as C source code, supports a set of functions for controlling PCIe as part of a bare-metal system where no operating system is available. The driver can be adapted for use as part of an operating system, but the implementation of the adaptation layer between the driver and the operating system's driver model is outside the scope of the driver. @section theory_op Theory of Operation The PolarFire PCIe driver functions are grouped into the following categories: * Enumeration * Memory Allocation * MSI Enabling * Configuration Space Read and Write * Address Translation Table * Interrupt Control * End Point DMA Operation * Supports PCIe for both PolarFire and PolarFire SoC devices Enumeration If the PolarFire PCI Express is configured as a root port, the application must call the PF_PCIE_enumeration() function to enumerate the PCIe system components. The PF_PCIE_enumeration() function uses the PCIe base address, the dual PCIe controller number, and the ECAM base address as its parameters, and returns the number of PCIe bridges/switches and endpoint devices attached to the PCIe system. The initial ECAM base address for the enumeration must start with 0 for bus, device, and function numbers. Memory Allocation The PF_PCIE_allocate_memory() function allocates memory on the PCIe root port host processor for the PCIe endpoints. The application must call this function after it calls the PF_PCIE_enumeration() function. This function uses the ECAM base address and allocated memory address from the host processor memory map as its parameters. MSI Enabling The PF_PCIE_enable_config_space_msi() enables MSI in the PCIe configuration space of the MSI capability register set. The application must call this function after it calls the PF_PCIE_enumeration() function. The function must be called separately to enable MSI in the PCIe root port and PCIe endpoint. Configuration Space Read and Write The following functions are used for configuration space read and write: * PF_PCIE_type1_header_read() * PF_PCIE_config_space_atr_table_init() * PF_PCIE_config_space_atr_table_terminate() * PF_PCIE_config_space_read() * PF_PCIE_config_space_write() The PF_PCIE_config_space_read() and PF_PCIE_config_space_write() functions are used by the application to read and write data to the PCIe type 0 or type 1 configuration space registers. Before calling the configuration space read or write function, the application must initialize the address translation table for the configuration space using the PF_PCIE_config_space_atr_table_init() function. The application can terminate the configuration space read or write operation using the PF_PCIE_config_space_atr_table_terminate() function. The application can read the entire PCIe type 1 configuration space header information using the PF_PCIE_type1_header_read() function. Address Translation table The following functions are used for address translation table setup: * PF_PCIE_master_atr_table_init() * PF_PCIE_slave_atr_table_init() The PF_PCIE_master_atr_table_init() function initializes the address translation table for the PCIe to perform address translation from the PCIe address space (BAR) to the AXI4 master. The PF_PCIE_slave_atr_table_init() function initializes the address translation table for the PCIe to perform address translation from the AXI4 slave to the PCIe address space. Interrupt Control Interrupts generated by the PCIe controller configured for MSI, INTx, and DMA transfer using the following functions: * PF_PCIE_enable_interrupts() * PF_PCIE_disable_interrupts() * PF_PCIE_isr() The PF_PCIE_enable_interrupts() function is used to enable the local MSI, INTx, and DMA transfer interrupts on the PCIe Root Port. The PF_PCIE_disable_interrupts() function is used to disable the local MSI, INTx, and DMA transfer interrupts on the PCIe Root Port. The PF_PCIE_isr() function is used to handle the PCIe interrupts. The user must call the PF_PCIE_isr() function from the system level interrupt handler. End Point DMA Operation The Application on the PCIe Root Port host processor initializes and configures the PolarFire PCIe End Point DMA engine for DMA transfer. The following functions are used for DMA transfer: * PF_PCIE_dma_init() * PF_PCIE_dma_read() * PF_PCIE_dma_write() * PF_PCIE_dma_abort() * PF_PCIE_set_dma_write_callback() * PF_PCIE_set_dma_read_callback() * PF_PCIE_dma_get_transfer_status() Initialization The PF_PCIE_dma_init() function in the PCIe root port application initializes the PolarFire PCIe endpoint DMA. This function must be called before any other PolarFire PCIe DMA driver functions. This function uses the allocated memory address from the memory map for the PCIe endpoint BAR on the host processor as its parameter. The application can call this function after the PF_PCIE_enumeration() and PF_PCIE_allocate_memory() functions. Data Transfer Control The PF_PCIE_dma_read() function starts a DMA transfer from the PCIe endpoint memory to the PCIe root port memory. It reads the data from the PCIe endpoint memory and writes it to the PCIe root port memory. The PF_PCIE_dma_write() function starts a DMA transfer from PCIe root port memory to the PCIe endpoint memory. It reads the data from the PCIe root port memory and writes it to the PCIe endpoint memory. For all DMA transfers, the user must provide the source and destination address, along with the transfer size. The PF_PCIE_dma_abort() function aborts a dma transfer that is in progress. Data transfer status The status of the PCIe DMA transfer initiated by the last call to PF_PCIE_dma_read() or PF_PCIE_dma_write() can be retrieved using the PF_PCIE_dma_get_transfer_status() function. Interrupt Handling PCIe DMA read and write operations are interrupt driven. The application must register read and write callback functions with the driver. This relevant callback function is then called by the PCIe driver every time data is written to or read from the destination address. The PF_PCIE_set_dma_read_callback() and PF_PCIE_set_dma_write_callback() functions are used to register a handler function that is called by the driver when the endpoint DMA transfer is completed. The driver passes the outcome of the transfer to the completion handler in the form of a pf_pcie_ep_dma_status_t parameter, which indicates whether the transfer was successful, and in case of an error during the transfer, indicates the type of error that occurred. The user must create and register transfer completion handler functions suitable for the application. The user must call the PF_PCIE_enable_interupts() function or the PF_PCIE_disable_interupts() function to enable or disable PCIe interrupts. And also, the user must call the PF_PCIE_isr() function from the system level interrupt handler for handling DMA interrupts. *//*=========================================================================*/ #ifndef PF_PCIESS_H_ #define PF_PCIESS_H_ #include "pf_pcie_regs.h" #include "pf_pcie_types.h" #ifdef __cplusplus extern "C" { #endif /*****************************************************************************/ /* PCIe Controller 0 */ #define PF_PCIE_CTRL_0 0u /* PCIe Controller 1 */ #define PF_PCIE_CTRL_1 1u /* It indicates that the ATR table is enabled */ #define PF_PCIE_ATR_TABLE_ENABLE 1u /* It indicates that the the ATR table is disabled */ #define PF_PCIE_ATR_TABLE_DISABLE 0u /***************************************************************************** The address translation table initialization is successfully assigned to a ATR table of AXI4 master/slave */ #define PF_PCIE_ATR_TABLE_INIT_SUCCESS 0u /***************************************************************************** The address translation table initialization is not successfully assigned to a ATR table of AXI4 master/slave */ #define PF_PCIE_ATR_TABLE_INIT_FAILURE 1u /****************************************************************************** The PF_PCIE_enumeration() function enumerates all the components in a PCIe system, including endpoints, bridges, and switches connected to the system. @param apb_addr Specifies the base address in the processor's memory map for the registers of the PCI Express hardware instance being initialized. @param pcie_ctrl_num Specifies the PCIe controller number 0 or 1. @param ecam_addr Specifies the ECAM address of PCIe system. The address is calculated based on the bus number, device number, function number, and the PCIe AXI4 slave base address from the processor's memory map. The bus, device, and function number should be 0 so the enumeration starts with bus number 0 and ends with bus number 8. @return The PF_PCIE_enumeration() function returns a pointer to the PCIe enumerate buffer structure for all the devices and bridges connected to the PCIe system. @code uint64_t apb_addr = 0x60000000 uint64_t ecam_addr = 0x70000000; uint8_t slv_table_no = 0; uint8_t tlp = PF_PCIE_TLP_MEM; pf_pcie_slave_atr_cfg_t s_cfg; pf_pcie_ebuff_t * p_pcie_enum_data; s_cfg.state = PF_PCIE_ATR_TABLE_ENABLE; s_cfg.size = PF_PCIE_SIZE_256MB; s_cfg.src_addr = 0x70000000; s_cfg.src_addr_msb = 0; s_cfg.trns_addr = 0x70000000; s_cfg.trns_addr_msb = 0; PF_PCIE_slave_atr_table_init(apb_addr, PF_PCIE_CTRL_1, &s_cfg, slv_table_no, tlp); p_pcie_enumer_data = PF_PCIE_enumeration(apb_addr, PF_PCIE_CTRL_1, ecam_addr); if(p_pcie_enum_data->no_of_devices_attached != 0) { } @endcode */ pf_pcie_ebuff_t * PF_PCIE_enumeration ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr ); /**************************************************************************** The PF_PCIE_allocate_memory() function allocates memory on the PCIe root port host processor for the PCIe endpoint BARs. This function must be called after the PF_PCIE_enumeration() function. @param ecam_addr Specifies the ECAM address of the PCIe system. The address is calculated based on the bus number, device number, function number, and PCIe AXI4 slave base address from the processor's memory map. @param allocate_addr Provides the translated address from the PCIe root port AXI4 slave address translation table. This address is assigned to the PCIe endpoint BAR. @return The PF_PCIE_allocate_memory() function returns a pointer to the PCIe bar info structure for the assigned BAR address and BAR size to the PCIe endpoint. @code uint64_t apb_addr = 0x60000000 uint64_t ecam_addr = 0x70000000; uint64_t ecam_addr1 = 0x70100000; uint8_t slv_table_no = 0; uint8_t tlp = PF_PCIE_TLP_MEM; pf_pcie_slave_atr_cfg_t s_cfg; pf_pcie_bar_info_t *p_pcie_bar_data; pf_pcie_ebuff_t * p_pcie_enum_data; s_cfg.state = PF_PCIE_ATR_TABLE_ENABLE; s_cfg.size = PF_PCIE_SIZE_256MB; s_cfg.src_addr = 0x70000000; s_cfg.src_addr_msb = 0; s_cfg.trns_addr = 0x70000000; s_cfg.trns_addr_msb = 0; PF_PCIE_slave_atr_table_init(apb_addr, PF_PCIE_CTRL_1, &s_cfg, slv_table_no, tlp); p_pcie_enumer_data = PF_PCIE_enumeration(apb_addr, PF_PCIE_CTRL_1, ecam_addr); if(p_pcie_enum_data->no_of_devices_attached != 0) { p_pcie_bar_data = PF_PCIE_allocate_memory(ecam_addr1, 0x70000000); } @endcode */ pf_pcie_bar_info_t * PF_PCIE_allocate_memory ( uint64_t ecam_addr, uint64_t allocate_addr ); /**************************************************************************** The PF_PCIE_enable_config_space_msi() function enables the PCIe root port or endpoint MSI in the PCIe configuration space. It also sets up the message address and other data required to generate MSI. @param ecam_addr Specifies the ECAM address of the PCIe system. The address is calculated based on the bus number, device number, function number, and PCIe AXI4 slave base address from the processor's memory map. @param msi_addr Specifies the target memory address on the PCIe root port to generate MSI from the PCIe endpoint. @param msi_data Specifies the data value to write into the msi_addr parameter. @return The PF_PCIE_enable_config_space_msi() function does not return a value. @code uint64_t apb_addr = 0x60000000 uint64_t ecam_addr = 0x70000000; uint64_t ecam_addr1 = 0x70100000; uint8_t slv_table_no = 0; uint8_t tlp = PF_PCIE_TLP_MEM; pf_pcie_slave_atr_cfg_t s_cfg; pf_pcie_master_atr_cfg_t m_cfg; pf_pcie_bar_info_t *p_pcie_bar_data; pf_pcie_ebuff_t * p_pcie_enum_data; s_cfg.state = PF_PCIE_ATR_TABLE_ENABLE; s_cfg.size = PF_PCIE_SIZE_256MB; s_cfg.src_addr = 0x70000000; s_cfg.src_addr_msb = 0; s_cfg.trns_addr = 0x70000000; s_cfg.trns_addr_msb = 0; PF_PCIE_slave_atr_table_init(apb_addr, PF_PCIE_CTRL_1, &s_cfg, slv_table_no, tlp); m_cfg.state = PF_PCIE_ATR_TABLE_ENABLE; m_cfg.bar_type = PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM; m_cfg.bar_size = PF_PCIE_SIZE_64KB; m_cfg.table_size = PF_PCIE_SIZE_64KB; m_cfg.src_addr = 0x10000000; m_cfg.src_addr_msb = 0; m_cfg.trns_addr = 0x00000000; m_cfg.trns_addr_msb = 0; PF_PCIE_master_atr_table_init(apb_addr, PF_PCIE_CTRL_1, &m_cfg, slv_table_no, tlp); p_pcie_enumer_data = PF_PCIE_enumeration(apb_addr, PF_PCIE_CTRL_1, ecam_addr); if(p_pcie_enum_data->no_of_devices_attached != 0) { PF_PCIE_enable_config_space_msi(ecam_addr, 0x190, 0x120); PF_PCIE_enable_config_space_msi(ecam_addr1, 0x190, 0x120); } @endcode */ void PF_PCIE_enable_config_space_msi ( uint64_t ecam_addr, uint64_t msi_addr, uint16_t msi_data ); /**************************************************************************** The PF_PCIE_type1_header_read() function reads the PCIe type1 (bridge or switch) configuration space header information. @param apb_addr Specifies the base address in the processor's memory map for the registers of the PCI Express hardware instance being initialized. @param pcie_ctrl_num Specifies the PCIe controller number, 0 or 1. @param ecam_addr Specifies the ECAM address of the PCIe system. The address is calculated based on the bus number, device number, function number, and PCIe AXI4 slave base address from the processor's memory map. @param p_type1_header Contains the output of the PCIe type1 header. The PCIe bridge/switch type 1 header information is stored in this parameter. @return The PF_PCIE_type1_header_read() function does not return a value. @code uint64_t apb_addr = 0x60000000 uint64_t ecam_addr = 0x70000000; PCIE_ROOT_CONF read_type1_header; PF_PCIE_type1_header_read(apb_addr, PF_PCIE_CTRL_1, ecam_addr, &read_type1_header) @endcode */ void PF_PCIE_type1_header_read ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr, PCIE_ROOT_CONF * p_type1_header ); /**************************************************************************** The PF_PCIE_config_space_atr_table_init() function initializes the PCIe AXI4 slave address translation table using the ecam_addr parameter, and enables the PCIe configuration interface to read or write data to the configuration space registers. @param apb_addr Specifies the base address in the processor's memory map for the registers of the PCI Express hardware instance being initialized. @param pcie_ctrl_num Specifies the PCIe controller number, 0 or 1. @param ecam_addr Specifies the ECAM address of the PCIe system. The address is calculated based on the bus number, device number, function number, and PCIe AXI4 slave base address from the processor's memory map. @return The PF_PCIE_config_space_atr_table_init() function returns success or failure of the PCIe ATR table initialization. The two possible return values are: -PF_PCIE_ATR_TABLE_INIT_SUCCESS -PF_PCIE_ATR_TABLE_INIT_FAILURE */ uint8_t PF_PCIE_config_space_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, uint64_t ecam_addr ); /**************************************************************************** The PF_PCIE_config_space_atr_table_terminate() function disables the PCIe configuration interface in the address translation table and enables the PCIe Tx/Rx interface for PCIe transactions. @param The PF_PCIE_config_space_atr_table_terminate() function does not have parameters. @return The PF_PCIE_config_space_atr_table_terminate() function does not return a value. */ void PF_PCIE_config_space_atr_table_terminate(void); /**************************************************************************** The PF_PCIE_config_space_read() function reads the data from configuration space of PCIe device register, bridge/switch register. @param ecam_addr Specifies the ECAM address of the PCIe system. The address is calculated based on the bus number, device number, function number, and PCIe AXI4 slave base address from the processor's memory map. @param config_space_offset Specifies a PCIe type 0/1 configuration space address offset. @param value Specifies the output value to read from the PCIe type 0/1 configuration space. @return The PF_PCIE_config_space_read() function does not return a value. @code uint64_t apb_addr = 0x60000000 uint64_t ecam_addr = 0x70100000; uint32_t read_value0; uint32_t read_value1; PF_PCIE_config_space_atr_table_init(apb_addr, PF_PCIE_CTRL_1, ecam_addr); PF_PCIE_config_space_read(ecam_addr, DEVICE_VID_DEVID, &read_value0); PF_PCIE_config_space_read(ecam_addr, DEVICE_CFG_PRMSCR, &read_value1); PF_PCIE_config_space_atr_table_terminate(); @endcode */ void PF_PCIE_config_space_read ( uint64_t ecam_addr, uint16_t config_space_offset, uint32_t *value ); /**************************************************************************** The PF_PCIE_config_space_write() function writes the data on configuration space of PCIe device, bridge/switch register. @param ecam_addr Specifies the ECAM address of the PCIe system. The address is calculated based on the bus number, device number, function number, and PCIe AXI4 slave base address from the processor's memory map. @param config_space_offset Specifies a PCIe type 0/1 configuration space address offset. @param value Specifies the input value to write on the PCIe type 0/1 configuration space. @return The PF_PCIE_config_space_write() function does not return a value. @code uint64_t apb_addr = 0x60000000 uint64_t ecam_addr = 0x70100000; uint32_t write_value0 = 0x11AA; uint32_t write_value1 = 0x6; PF_PCIE_config_space_atr_table_init(apb_addr, PF_PCIE_CTRL_1, ecam_addr); PF_PCIE_config_space_write(ecam_addr, DEVICE_VID_DEVID, write_value0); PF_PCIE_config_space_write(ecam_addr, DEVICE_CFG_PRMSCR, write_value1); PF_PCIE_config_space_atr_table_terminate(); @endcode */ void PF_PCIE_config_space_write ( uint64_t ecam_addr, uint16_t config_space_offset, uint32_t value ); /**************************************************************************** The PF_PCIE_master_atr_table_init() function sets up the address translation table for the PCIe AXI4 master. @param apb_addr Specifies the base address in the processor's memory map for the registers of the PCI Express hardware instance being initialized. @param pcie_ctrl_num Specifies the PCIe controller number, 0 or 1. @param cfg Specifies the configuration data structure of the PCIe AXI4 Master address translation table. @param master_table_num Specifies the PCIe to AXI4 master address translation table number. There are a total of six AXI master address translation tables in the PCIESS. @param tlp_type Specifies the Transaction Layer Packet(TLP) type. Available options are: * PF_PCIE_TLP_MEM * PF_PCIE_TLP_MEM_LOCKED * PF_PCIE_TLP_IO * PF_PCIE_TLP_TRSNL_REQUEST * PF_PCIE_TLP_MESSAGE * PF_PCIE_TLP_MEM_TRSNL_REQUEST @return The PF_PCIE_master_atr_table_init() function returns success or failure of the PCIe ATR table initialization. The two possible return values are: -PF_PCIE_ATR_TABLE_INIT_SUCCESS -PF_PCIE_ATR_TABLE_INIT_FAILURE @code pf_pcie_master_atr_cfg_t m_cfg; uint64_t apb_addr = 0x60000000 uint8_t mst_table_no = 0; uint8_t tlp = PF_PCIE_TLP_MEM; m_cfg.state = PF_PCIE_ATR_TABLE_ENABLE; m_cfg.bar_type = PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM; m_cfg.bar_size = PF_PCIE_SIZE_64KB; m_cfg.table_size = PF_PCIE_SIZE_64KB; m_cfg.src_addr = 0x10000000; m_cfg.src_addr_msb = 0; m_cfg.trns_addr = 0x00000000; m_cfg.trns_addr_msb = 0; PF_PCIE_master_atr_table_init(apb_addr, PF_PCIE_CTRL_1, &m_cfg, mst_table_no, tlp); @endcode */ uint8_t PF_PCIE_master_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, pf_pcie_master_atr_cfg_t * cfg, uint8_t master_table_num, uint8_t tlp_type ); /**************************************************************************** The PF_PCIE_slave_atr_table_init() function sets up the address translation table for the PCIe AXI4 slave. @param apb_addr Specifies the base address in the processor's memory map for the registers of the PCI Express hardware instance being initialized. @param pcie_ctrl_num Specifies the PCIe controller number, 0 or 1. @param cfg Specifies the configuration data structure of AXI4 slave to PCIe address translation table. @param slave_table_num Specifies the AXI4 slave to PCIe transaction address translation table number. There are a total of eight AXI slave address translation tables in the PCIESS. @param tlp_type Specifies the transaction layer packet(TLP) type. * PF_PCIE_TLP_MEM * PF_PCIE_TLP_MEM_LOCKED * PF_PCIE_TLP_IO * PF_PCIE_TLP_TRSNL_REQUEST * PF_PCIE_TLP_MESSAGE * PF_PCIE_TLP_MEM_TRSNL_REQUEST @return The PF_PCIE_slave_atr_table_init() function returns success or failure of the PCIe ATR table initialization. The two possible return values are: -PF_PCIE_ATR_TABLE_INIT_SUCCESS -PF_PCIE_ATR_TABLE_INIT_FAILURE @code uint64_t apb_addr = 0x60000000 uint8_t slv_table_no = 0; uint8_t tlp = PF_PCIE_TLP_MEM; pf_pcie_slave_atr_cfg_t s_cfg; s_cfg.state = PF_PCIE_ATR_TABLE_ENABLE; s_cfg.size = PF_PCIE_SIZE_256MB; s_cfg.src_addr = 0x70000000; s_cfg.src_addr_msb = 0; s_cfg.trns_addr = 0x70000000; s_cfg.trns_addr_msb = 0; PF_PCIE_slave_atr_table_init(apb_addr, PF_PCIE_CTRL_1, &s_cfg, slv_table_no, tlp); @endcode */ uint8_t PF_PCIE_slave_atr_table_init ( uint64_t apb_addr, uint8_t pcie_ctrl_num, pf_pcie_slave_atr_cfg_t * cfg, uint8_t slave_table_num, uint8_t tlp_type ); /**************************************************************************** The PF_PCIE_dma_init() function initializes the PCIe endpoint DMA from the PCIe root port host processor. @param allocated_addr Specifies the memory address allocated on the PCIe root port host processor for PCIe endpoint BAR. The BAR accesses the endpoint DMA engine. @return The PF_PCIE_dma_init() function does not return a value. */ void PF_PCIE_dma_init(uint64_t allocated_addr); /******************************************************************************* The PF_pcie_set_dma_write_callback() function registers the function called by the PCIe driver when the data has been written. @param write_callback Points to the function that will be called when the data is written by the PCIe DMA. @return The PF_PCIE_set_dma_write_callback() function does not return a value. @code void transfer_complete_handler(pf_pcie_ep_dma_status_t status); volatile uint32_t g_xfer_in_progress = 0; uint8_t External_30_IRQHandler(void) { PF_PCIE_isr(); return(EXT_IRQ_KEEP_ENABLED); } void demo_transfer(void) { PF_PCIE_dma_init(0x70008000); PF_PCIE_set_dma_write_callback(transfer_complete_handler); g_xfer_in_progress = 1; PF_PCIE_enable_interrupts(); HAL_enable_interrupts(); PF_PCIE_dma_write(RP_SRAM_ADDR, EP_SRAM_ADDR, 128); while(g_xfer_in_progress) { ; } } void transfer_complete_handler(pf_pcie_ep_dma_status_t status) { g_xfer_in_progress = 0; switch(status) { case PF_PCIE_EP_DMA_COMPLETED: display("Transfer complete"); break; case PF_PCIE_EP_DMA_ERROR: display("Transfer failed: error"); break; } } @endcode */ void PF_PCIE_set_dma_write_callback ( pf_pcie_write_callback_t write_callback ); /******************************************************************************* The PF_PCIE_set_dma_read_callback() function registers the function called by the PCIe driver when the data has been read. @param read_callback Points to the function that will be called when the data is read by the PCIe DMA. @return The PF_PCIE_set_dma_read_callback() function does not return a value. @code void transfer_complete_handler(pf_pcie_ep_dma_status_t status); volatile uint32_t g_xfer_in_progress = 0; uint8_t External_30_IRQHandler(void) { PF_PCIE_isr(); return(EXT_IRQ_KEEP_ENABLED); } void demo_transfer(void) { PF_PCIE_dma_init(0x70008000); PF_PCIE_set_dma_read_callback(transfer_complete_handler); g_xfer_in_progress = 1; PF_PCIE_enable_interrupts(); HAL_enable_interrupts(); PF_PCIE_dma_write(EP_SRAM_ADDR, RP_SRAM_ADDR, 128); while(g_xfer_in_progress) { ; } } void transfer_complete_handler(pf_pcie_ep_dma_status_t status) { g_xfer_in_progress = 0; switch(status) { case PF_PCIE_EP_DMA_COMPLETED: display("Transfer complete"); break; case PF_PCIE_EP_DMA_ERROR: display("Transfer failed: error"); break; } } @endcode */ void PF_PCIE_set_dma_read_callback ( pf_pcie_read_callback_t read_callback ); /**************************************************************************** The PF_PCIE_dma_read() function initiates PCIe endpoint DMA data transfer from the PCIe root port host processor. Its parameters specify the source and destination addresses of the transfer, as well as its size. The PCIe DMA data transfers for read operations always use the PCIe endpoint memory as the source and the PCIe root port memory as the destination for the transfer. Note: A call to PF_PCIE_dma_read() while a transfer is in progress will not initiate a new transfer. Use the PF_PCIE_dma_get_transfer_status() function or a completion handler registered by the PF_PCIE_set_dma_read_callback() function to check the status of the current transfer before calling the PF_PCIE_dma_read() function again. @param src_address Specifies the source address of the PCIe endpoint memory (AXI4 master ATR table sourceaddress). @param dest_address Specifies the destination address of the PCIe root port memory (AXI4 master ATR table destination address). @param rx_lenth Specifies the length (in bytes) of the data to be read. @return The PF_PCIE_dma_read() function does not return a value. */ void PF_PCIE_dma_read ( uint64_t src_address, uint64_t dest_address, uint32_t rx_lenth ); /******************************************************************************* The PF_PCIE_dma_write() function initiates PCIe endpoint DMA data transfer from the PCIe root port host processor. Its parameters specify the source and destination addresses of the transfer as well as its size. The PCIe DMA data transfers for write operations always use the PCIe root port memory as the source and the PCIe endpoint memory as the destination for the transfer. Note: A call to PF_pcie_dma_write() while a transfer is in progress will not initiate a new transfer. Use the PF_pcie_dma_get_transfer_status() function or a completion handler registered by the PF_pcie_set_dma_write_callback() function to check the status of the current transfer before calling the PF_pcie_dma_write() function again. @param src_address Specifies the source address of the PCIe root port memory (AXI4 master ATR table source address). @param dest_address Specifies the destination address of the PCIe endpoint memory (AXI4 master ATR table destination address). @param tx_lenth Specifies the length (in bytes) of the data to be written. @return The PF_PCIE_dma_write() function does not return a value. */ void PF_PCIE_dma_write ( uint64_t src_address, uint64_t dest_address, uint32_t tx_lenth ); /******************************************************************************* The PF_PCIE_dma_abort() function aborts a PCIe DMA transfer that is in progress. @param The PF_PCIE_dma_abort() function has no parameters. @return The PF_PCIE_dma_abort() function does not return a value. */ void PF_PCIE_dma_abort(void); /******************************************************************************* The PF_PCIE_dma_get_transfer_status() function indicates the status of a PCIe endpoint DMA transfer initiated by a call to the PF_PCIE_dma_write() or PF_PCIE_dma_read() function. @param The PF_PCIE_dma_get_transfer_status() function has no parameters. @return The PF_PCIE_dma_get_transfer_status() function returns the status of the PCIE DMA transfer as a value of type pf_pcie_ep_dma_status_t. The possible return values are: - PF_PCIE_EP_DMA_NOT_INITIALIZED - PF_PCIE_EP_DMA_IN_PROGRESS - PF_PCIE_EP_DMA_COMPLETED - PF_PCIE_EP_DMA_ERROR @code void copy_ep_to_rp(void) { PF_PCIE_dma_init(0x70008000); PF_PCIE_dma_read(EP_SRAM_ADDR, RP_SRAM_ADDR, 128); do { xfer_state = PF_PCIE_dma_get_transfer_status(); }while(PF_PCIE_EP_DMA_IN_PROGRESS == xfer_state); } @endcode */ pf_pcie_ep_dma_status_t PF_PCIE_dma_get_transfer_status ( void ); /**************************************************************************** The PF_pcie_enable_interrupts() function enables local interrupts(MSI, INTx, DMAx) on the PCIe RootPort. @param The PF_PCIE_enable_interrupts() function has no parameters. @return The PF_PCIE_enable_interrupts() function does not return a value. */ void PF_PCIE_enable_interrupts(void); /**************************************************************************** The PF_pcie_disable_interrupts() function disables the local interrupts on the PCIe RootPort. @param The PF_PCIE_disable_interrupts() function has no parameters. @return The PF_PCIE_disable_interrupts() function does not return a value. */ void PF_PCIE_disable_interrupts(void); /******************************************************************************* The PF_PCIE_isr() function is a PCIe root port local interrupt handler. The PF_PCIE_isr() function is the top level interrupt handler function for the PolarFire PCIe driver. The user must call the PF_PCIE_isr() function from the system level interrupt handler assigned to the interrupt triggered by the PF_PCIE/PCIE_#_INTERRUPT_OUT signal. @param The PF_PCIE_isr() function does not take any parameters @return The PF_PCIE_isr() function does not return a value. @code uint8_t External_30_IRQHandler(void) { PF_PCIE_isr(); return(EXT_IRQ_KEEP_ENABLED); } @endcode */ void PF_PCIE_isr(void); /*****************************************************************************/ uint64_t ecam_address_calc ( uint64_t axi_addr, uint8_t bus, uint8_t device, uint8_t function ); /*****************************************************************************/ #ifdef __cplusplus } #endif #endif /* PF_PCIESS_H_ */ pf_pcie_regs.h000066400000000000000000001323021432224323300366550ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/pf_pcie/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire and PolarFire SoC PCIe subsystem Core Registers data structures. * * SVN $Revision$ * SVN $Date$ */ #ifndef PF_PCIESS_REGS_H_ #define PF_PCIESS_REGS_H_ #include #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------------ PCS LANE Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t LFWF_R0; volatile uint32_t LOVR_R0; volatile uint32_t LPIP_R0; volatile uint32_t L64_R0; volatile uint32_t L64_R1; volatile uint32_t L64_R2; volatile uint32_t L64_R3; volatile uint32_t L64_R4; volatile uint32_t L64_R5; volatile uint32_t L64_R6; volatile uint32_t L64_R7; volatile uint32_t L64_R8; volatile uint32_t L64_R9; volatile uint32_t L64_R10; volatile uint32_t RESERVED0; volatile uint32_t L8_R0; volatile uint32_t RESERVED1[3]; volatile uint32_t LNTV_R0; volatile uint32_t RESERVED2; volatile uint32_t LCLK_R0; volatile uint32_t LCLK_R1; volatile uint32_t RESERVED3[2]; volatile uint32_t LRST_R0; volatile uint32_t LRST_OPT; volatile uint32_t RESERVED4[2]; volatile uint32_t OOB_R0; volatile uint32_t OOB_R1; volatile uint32_t OOB_R2; volatile uint32_t OOB_R3; volatile uint32_t PMA_CTRL_R0; volatile uint32_t PMA_CTRL_R1; volatile uint32_t PMA_CTRL_R2; volatile uint32_t MSTR_CTRL; } PCS_LANE_TypeDef; /*------------------------------------------------------------------------------ PCS Common Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t GSSCLK_CTRL; volatile uint32_t QRST_R0; volatile uint32_t QDBG_R0; } PCS_CMN_TypeDef; /*------------------------------------------------------------------------------ PMA Lane Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t DES_CDR_CTRL_1; volatile uint32_t DES_CDR_CTRL_2; volatile uint32_t DES_CDR_CTRL_3; volatile uint32_t DES_DFEEM_CTRL_1; volatile uint32_t DES_DFEEM_CTRL_2; volatile uint32_t DES_DFEEM_CTRL_3; volatile uint32_t RESERVED0; volatile uint32_t DES_DFE_CTRL_1; volatile uint32_t DES_DFE_CTRL_2; volatile uint32_t DES_EM_CTRL_1; volatile uint32_t DES_EM_CTRL_2; volatile uint32_t DES_IN_TERM; volatile uint32_t DES_PKDET; volatile uint32_t DES_RTL_EM; volatile uint32_t DES_RTL_LOCK_CTR; volatile uint32_t DES_RXPLL_DIV; volatile uint32_t DES_TEST_BUS; volatile uint32_t DES_CLK_CTRL; volatile uint32_t DES_RSTPD; volatile uint32_t DES_RTL_ERR_CHK; volatile uint32_t DES_PCIE1_2_RXPLL_DIV; volatile uint32_t DES_SATA1_2_RXPLL_DIV; volatile uint32_t DES_SATA3_RXPLL_DIV; volatile uint32_t RESERVED1[4]; volatile uint32_t SER_CTRL; volatile uint32_t SER_CLK_CTRL; volatile uint32_t SER_RSTPD; volatile uint32_t SER_DRV_BYP; volatile uint32_t SER_RXDET_CTRL; volatile uint32_t SER_RXDET_OUT; volatile uint32_t SER_STATIC_LSB; volatile uint32_t SER_STATIC_MSB; volatile uint32_t SER_TERM_CTRL; volatile uint32_t SER_TEST_BUS; volatile uint32_t SER_DRV_DATA_CTRL; volatile uint32_t SER_DRV_CTRL; volatile uint32_t SER_DRV_CTRL_SEL; volatile uint32_t SER_DRV_CTRL_M0; volatile uint32_t SER_DRV_CTRL_M1; volatile uint32_t SER_DRV_CTRL_M2; volatile uint32_t SER_DRV_CTRL_M3; volatile uint32_t SER_DRV_CTRL_M4; volatile uint32_t SER_DRV_CTRL_M5; volatile uint32_t RESERVED2; volatile uint32_t SERDES_RTL_CTRL; volatile uint32_t RESERVED3[3]; volatile uint32_t DES_DFE_CAL_CTRL_0; volatile uint32_t DES_DFE_CAL_CTRL_1; volatile uint32_t DES_DFE_CAL_CTRL_2; volatile uint32_t DES_DFE_CAL_CMD; volatile uint32_t DES_DFE_CAL_BYPASS; volatile uint32_t DES_DFE_CAL_EYE_DATA; volatile uint32_t DES_DFE_CDRH0_MON; volatile uint32_t DES_DFE_COEFF_MON_0; volatile uint32_t DES_DFE_COEFF_MON_1; volatile uint32_t DES_DFE_CAL_OS_MON; volatile uint32_t DES_DFE_CAL_ST_0; volatile uint32_t DES_DFE_CAL_ST_1; volatile uint32_t DES_DFE_CAL_FLAG; } PMA_LANE_TypeDef; /*------------------------------------------------------------------------------ TXPLL_SSC (PMA Common) Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t TXPLL_CLKBUF; volatile uint32_t TXPLL_CTRL; volatile uint32_t TXPLL_CLK_SEL; volatile uint32_t TXPLL_DIV_1; volatile uint32_t TXPLL_DIV_2; volatile uint32_t TXPLL_JA_1; volatile uint32_t TXPLL_JA_2; volatile uint32_t TXPLL_JA_3; volatile uint32_t TXPLL_JA_4; volatile uint32_t TXPLL_JA_5; volatile uint32_t TXPLL_JA_6; volatile uint32_t TXPLL_JA_7; volatile uint32_t TXPLL_JA_8; volatile uint32_t TXPLL_JA_9; volatile uint32_t TXPLL_JA_10; volatile uint32_t TXPLL_JA_RST; volatile uint32_t SERDES_SSMOD; volatile uint32_t RESERVED[2]; volatile uint32_t SERDES_RTERM; volatile uint32_t SERDES_RTT; } TXPLL_SSC_TypeDef; /*------------------------------------------------------------------------------ TXPLL (QAUD - extpll) Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t EXTPLL_CLKBUF; volatile uint32_t EXTPLL_CTRL; volatile uint32_t EXTPLL_CLK_SEL; volatile uint32_t EXTPLL_DIV_1; volatile uint32_t EXTPLL_DIV_2; volatile uint32_t EXTPLL_JA_1; volatile uint32_t EXTPLL_JA_2; volatile uint32_t EXTPLL_JA_3; volatile uint32_t EXTPLL_JA_4; volatile uint32_t EXTPLL_JA_5; volatile uint32_t EXTPLL_JA_6; volatile uint32_t EXTPLL_JA_7; volatile uint32_t EXTPLL_JA_8; volatile uint32_t EXTPLL_JA_9; volatile uint32_t EXTPLL_JA_10; volatile uint32_t EXTPLL_JA_RST; } TXPLL_TypeDef; /*------------------------------------------------------------------------------ PCIESS main Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t OVRLY; volatile uint32_t MAJOR; volatile uint32_t INT_PIPE_CLK_CTRL; volatile uint32_t EXT_PIPE_CLK_CTRL; volatile uint32_t CLK_CTRL; volatile uint32_t QMUX_R0; volatile uint32_t RESERVED0[57]; volatile uint32_t DLL_CTRL0; volatile uint32_t DLL_CTRL1; volatile uint32_t DLL_STAT0; volatile uint32_t DLL_STAT1; volatile uint32_t DLL_STAT2; volatile uint32_t TEST_DLL; volatile uint32_t RESERVED1[29]; volatile uint32_t SPARE; } PCIESS_MAIN_TypeDef; /*------------------------------------------------------------------------------ PCIE Control Registers. */ typedef struct { volatile uint32_t SOFT_RESET; volatile uint32_t DEV_CONTROL; volatile uint32_t CLOCK_CONTROL; volatile uint32_t RESERVED0; volatile uint32_t SOFT_RESET_DEBUG_INFO; volatile uint32_t SOFT_RESET_CTLR; volatile uint32_t RESERVED1[2]; volatile uint32_t SEC_ERROR_EVENT_CNT; volatile uint32_t DED_ERROR_EVENT_CNT; volatile uint32_t SEC_ERROR_INT; volatile uint32_t SEC_ERROR_INT_MASK; volatile uint32_t DED_ERROR_INT; volatile uint32_t DED_ERROR_INT_MASK; volatile uint32_t ECC_CONTROL; volatile uint32_t ECC_ERR_LOC; volatile uint32_t RAM_MARGIN_1; volatile uint32_t RAM_MARGIN_2; volatile uint32_t RAM_POWER_CONTROL; volatile uint32_t RESERVED2; volatile uint32_t DEBUG_SEL; volatile uint32_t RESERVED3[2]; volatile uint32_t LTSSM_STATE; volatile uint32_t PHY_COMMON_INTERFACE; volatile uint32_t PL_TX_LANEIF_0; volatile uint32_t PL_RX_LANEIF_0; volatile uint32_t PL_WAKECLKREQ; volatile uint32_t RESERVED4[4]; volatile uint32_t PCICONF_PCI_IDS_OVERRIDE; volatile uint32_t PCICONF_PCI_IDS_31_0; volatile uint32_t PCICONF_PCI_IDS_63_32; volatile uint32_t PCICONF_PCI_IDS_95_64; volatile uint32_t RESERVED5[4]; volatile uint32_t PCIE_PEX_DEV_LINK_SPC2; volatile uint32_t PCIE_PEX_SPC; volatile uint32_t RESERVED6[22]; volatile uint32_t PCIE_AXI_MASTER_ATR_CFG0; volatile uint32_t PCIE_AXI_MASTER_ATR_CFG1; volatile uint32_t PCIE_AXI_MASTER_ATR_CFG2; volatile uint32_t RESERVED7[5]; volatile uint32_t AXI_SLAVE_PCIE_ATR_CFG0; volatile uint32_t AXI_SLAVE_PCIE_ATR_CFG1; volatile uint32_t AXI_SLAVE_PCIE_ATR_CFG2; volatile uint32_t RESERVED8[5]; volatile uint32_t PCIE_BAR_01; volatile uint32_t PCIE_BAR_23; volatile uint32_t PCIE_BAR_45; volatile uint32_t PCIE_EVENT_INT; volatile uint32_t RESERVED9[12]; volatile uint32_t PCIE_BAR_WIN; volatile uint32_t RESERVED10[703]; volatile uint32_t TEST_BUS_IN_31_0; volatile uint32_t TEST_BUS_IN_63_32; } PCIE_CTRL_TypeDef; /*------------------------------------------------------------------------------ PCIE Bridge Control Registers. */ typedef struct { volatile uint32_t BRIDGE_VER; volatile uint32_t BRIDGE_BUS; volatile uint32_t BRIDGE_IMPL_IF; volatile uint32_t RESERVED; volatile uint32_t PCIE_IF_CONF; volatile uint32_t PCIE_BASIC_CONF; volatile uint32_t PCIE_BASIC_STATUS; volatile uint32_t RESERVED0[2]; volatile uint32_t AXI_SLVL_CONF; volatile uint32_t RESERVED1[2]; volatile uint32_t AXI_MST0_CONF; volatile uint32_t AXI_SLV0_CONF; volatile uint32_t RESERVED2[18]; volatile uint32_t GEN_SETTINGS; volatile uint32_t PCIE_CFGCTRL; volatile uint32_t PCIE_PIPE_DW0; volatile uint32_t PCIE_PIPE_DW1; volatile uint32_t PCIE_VC_CRED_DW0; volatile uint32_t PCIE_VC_CRED_DW1; volatile uint32_t PCIE_PCI_IDS_DW0; volatile uint32_t PCIE_PCI_IDS_DW1; volatile uint32_t PCIE_PCI_IDS_DW2; volatile uint32_t PCIE_PCI_LPM; volatile uint32_t PCIE_PCI_IRQ_DW0; volatile uint32_t PCIE_PCI_IRQ_DW1; volatile uint32_t PCIE_PCI_IRQ_DW2; volatile uint32_t PCIE_PCI_IOV_DW0; volatile uint32_t PCIE_PCI_IOV_DW1; volatile uint32_t RESERVED3; volatile uint32_t PCIE_PEX_DEV; volatile uint32_t PCIE_PEX_DEV2; volatile uint32_t PCIE_PEX_LINK; volatile uint32_t PCIE_PEX_SLOT; volatile uint32_t PCIE_PEX_ROOT_VC; volatile uint32_t PCIE_PEX_SPC; volatile uint32_t PCIE_PEX_SPC2; volatile uint32_t PCIE_PEX_NFTS; volatile uint32_t PCIE_PEX_L1SS; volatile uint32_t PCIE_BAR_01_DW0; volatile uint32_t PCIE_BAR_01_DW1; volatile uint32_t PCIE_BAR_23_DW0; volatile uint32_t PCIE_BAR_23_DW1; volatile uint32_t PCIE_BAR_45_DW0; volatile uint32_t PCIE_BAR_45_DW1; volatile uint32_t PCIE_BAR_WIN; volatile uint32_t PCIE_EQ_PRESET_DW0; volatile uint32_t PCIE_EQ_PRESET_DW1; volatile uint32_t PCIE_EQ_PRESET_DW2; volatile uint32_t PCIE_EQ_PRESET_DW3; volatile uint32_t PCIE_EQ_PRESET_DW4; volatile uint32_t PCIE_EQ_PRESET_DW5; volatile uint32_t PCIE_EQ_PRESET_DW6; volatile uint32_t PCIE_EQ_PRESET_DW7; volatile uint32_t PCIE_SRIOV_DW0; volatile uint32_t PCIE_SRIOV_DW1; volatile uint32_t PCIE_SRIOV_DW2; volatile uint32_t PCIE_SRIOV_DW3; volatile uint32_t PCIE_SRIOV_DW4; volatile uint32_t PCIE_SRIOV_DW5; volatile uint32_t PCIE_SRIOV_DW6; volatile uint32_t PCIE_SRIOV_DW7; volatile uint32_t PCIE_CFGNUM; volatile uint32_t RESERVED4[12]; volatile uint32_t PM_CONF_DW0; volatile uint32_t PM_CONF_DW1; volatile uint32_t PM_CONF_DW2; volatile uint32_t IMASK_LOCAL; volatile uint32_t ISTATUS_LOCAL; volatile uint32_t IMASK_HOST; volatile uint32_t ISTATUS_HOST; volatile uint32_t IMSI_ADDR; volatile uint32_t ISTATUS_MSI; volatile uint32_t ICMD_PM; volatile uint32_t ISTATUS_PM; volatile uint32_t ATS_PRI_REPORT; volatile uint32_t LTR_VALUES; volatile uint32_t RESERVED5[2]; volatile uint32_t ISTATUS_DMA0; volatile uint32_t ISTATUS_DMA1; volatile uint32_t RESERVED6[8]; volatile uint32_t ISTATUS_P_ADT_WIN0; volatile uint32_t ISTATUS_P_ADT_WIN1; volatile uint32_t ISTATUS_A_ADT_SLV0; volatile uint32_t ISTATUS_A_ADT_SLV1; volatile uint32_t ISTATUS_A_ADT_SLV2; volatile uint32_t ISTATUS_A_ADT_SLV3; volatile uint32_t RESERVED7[4]; volatile uint32_t ROUTING_RULES_R_DW0; volatile uint32_t ROUTING_RULES_R_DW1; volatile uint32_t ROUTING_RULES_R_DW2; volatile uint32_t ROUTING_RULES_R_DW3; volatile uint32_t ROUTING_RULES_R_DW4; volatile uint32_t ROUTING_RULES_R_DW5; volatile uint32_t ROUTING_RULES_R_DW6; volatile uint32_t ROUTING_RULES_R_DW7; volatile uint32_t ROUTING_RULES_R_DW8; volatile uint32_t ROUTING_RULES_R_DW9; volatile uint32_t ROUTING_RULES_R_DW10; volatile uint32_t ROUTING_RULES_R_DW11; volatile uint32_t ROUTING_RULES_R_DW12; volatile uint32_t ROUTING_RULES_R_DW13; volatile uint32_t ROUTING_RULES_R_DW14; volatile uint32_t ROUTING_RULES_R_DW15; volatile uint32_t ROUTING_RULES_W_DW0; volatile uint32_t ROUTING_RULES_W_DW1; volatile uint32_t ROUTING_RULES_W_DW2; volatile uint32_t ROUTING_RULES_W_DW3; volatile uint32_t ROUTING_RULES_W_DW4; volatile uint32_t ROUTING_RULES_W_DW5; volatile uint32_t ROUTING_RULES_W_DW6; volatile uint32_t ROUTING_RULES_W_DW7; volatile uint32_t ROUTING_RULES_W_DW8; volatile uint32_t ROUTING_RULES_W_DW9; volatile uint32_t ROUTING_RULES_W_DW10; volatile uint32_t ROUTING_RULES_W_DW11; volatile uint32_t ROUTING_RULES_W_DW12; volatile uint32_t ROUTING_RULES_W_DW13; volatile uint32_t ROUTING_RULES_W_DW14; volatile uint32_t ROUTING_RULES_W_DW15; volatile uint32_t ARBITRATION_RULES_DW0; volatile uint32_t ARBITRATION_RULES_DW1; volatile uint32_t ARBITRATION_RULES_DW2; volatile uint32_t ARBITRATION_RULES_DW3; volatile uint32_t ARBITRATION_RULES_DW4; volatile uint32_t ARBITRATION_RULES_DW5; volatile uint32_t ARBITRATION_RULES_DW6; volatile uint32_t ARBITRATION_RULES_DW7; volatile uint32_t ARBITRATION_RULES_DW8; volatile uint32_t ARBITRATION_RULES_DW9; volatile uint32_t ARBITRATION_RULES_DW10; volatile uint32_t ARBITRATION_RULES_DW11; volatile uint32_t ARBITRATION_RULES_DW12; volatile uint32_t ARBITRATION_RULES_DW13; volatile uint32_t ARBITRATION_RULES_DW14; volatile uint32_t ARBITRATION_RULES_DW15; volatile uint32_t PRIORITY_RULES_DW0; volatile uint32_t PRIORITY_RULES_DW1; volatile uint32_t PRIORITY_RULES_DW2; volatile uint32_t PRIORITY_RULES_DW3; volatile uint32_t PRIORITY_RULES_DW4; volatile uint32_t PRIORITY_RULES_DW5; volatile uint32_t PRIORITY_RULES_DW6; volatile uint32_t PRIORITY_RULES_DW7; volatile uint32_t PRIORITY_RULES_DW8; volatile uint32_t PRIORITY_RULES_DW9; volatile uint32_t PRIORITY_RULES_DW10; volatile uint32_t PRIORITY_RULES_DW11; volatile uint32_t PRIORITY_RULES_DW12; volatile uint32_t PRIORITY_RULES_DW13; volatile uint32_t PRIORITY_RULES_DW14; volatile uint32_t PRIORITY_RULES_DW15; volatile uint32_t RESERVED8[48]; volatile uint32_t P2A_TC_QOS_CONV; volatile uint32_t P2A_ATTR_CACHE_CONV; volatile uint32_t P2A_NC_BASE_ADDR_DW0; volatile uint32_t P2A_NC_BASE_ADDR_DW1; volatile uint32_t RESERVED9[12]; volatile uint32_t DMA0_SRC_PARAM; volatile uint32_t DMA0_DESTPARAM; volatile uint32_t DMA0_SRCADDR_LDW; volatile uint32_t DMA0_SRCADDR_UDW; volatile uint32_t DMA0_DESTADDR_LDW; volatile uint32_t DMA0_DESTADDR_UDW; volatile uint32_t DMA0_LENGTH; volatile uint32_t DMA0_CONTROL; volatile uint32_t DMA0_STATUS; volatile uint32_t DMA0_PRC_LENGTH; volatile uint32_t DMA0_SHARE_ACCESS; volatile uint32_t RESERVED10[5]; volatile uint32_t DMA1_SRC_PARAM; volatile uint32_t DMA1_DESTPARAM; volatile uint32_t DMA1_SRCADDR_LDW; volatile uint32_t DMA1_SRCADDR_UDW; volatile uint32_t DMA1_DESTADDR_LDW; volatile uint32_t DMA1_DESTADDR_UDW; volatile uint32_t DMA1_LENGTH; volatile uint32_t DMA1_CONTROL; volatile uint32_t DMA1_STATUS; volatile uint32_t DMA1_PRC_LENGTH; volatile uint32_t DMA1_SHARE_ACCESS; volatile uint32_t RESERVED11[101]; volatile uint32_t ATR0_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR0_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR0_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR0_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR0_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED12; volatile uint32_t ATR0_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR0_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR1_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR1_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR1_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR1_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR1_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED13; volatile uint32_t ATR1_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR1_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR2_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR2_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR2_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR2_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR2_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED14; volatile uint32_t ATR2_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR2_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR3_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR3_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR3_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR3_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR3_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED15; volatile uint32_t ATR3_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR3_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR4_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR4_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR4_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR4_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR4_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED16; volatile uint32_t ATR4_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR4_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR5_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR5_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR5_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR5_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR5_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED17; volatile uint32_t ATR5_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR5_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR6_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR6_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR6_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR6_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR6_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED18; volatile uint32_t ATR6_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR6_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR7_PCIE_WIN0_SRCADDR_PARAM; volatile uint32_t ATR7_PCIE_WIN0_SRC_ADDR; volatile uint32_t ATR7_PCIE_WIN0_TRSL_ADDR_LSB; volatile uint32_t ATR7_PCIE_WIN0_TRSL_ADDR_UDW; volatile uint32_t ATR7_PCIE_WIN0_TRSL_PARAM; volatile uint32_t RESERVED19; volatile uint32_t ATR7_PCIE_WIN0_TRSL_MASK_DW0; volatile uint32_t ATR7_PCIE_WIN0_TRSL_MASK_DW1; volatile uint32_t ATR0_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR0_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR0_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR0_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR0_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED20; volatile uint32_t ATR0_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR0_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR1_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR1_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR1_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR1_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR1_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED21; volatile uint32_t ATR1_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR1_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR2_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR2_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR2_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR2_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR2_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED22; volatile uint32_t ATR2_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR2_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR3_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR3_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR3_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR3_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR3_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED23; volatile uint32_t ATR3_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR3_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR4_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR4_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR4_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR4_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR4_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED24; volatile uint32_t ATR4_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR4_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR5_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR5_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR5_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR5_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR5_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED25; volatile uint32_t ATR5_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR5_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR6_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR6_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR6_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR6_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR6_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED26; volatile uint32_t ATR6_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR6_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR7_PCIE_WIN1_SRCADDR_PARAM; volatile uint32_t ATR7_PCIE_WIN1_SRC_ADDR; volatile uint32_t ATR7_PCIE_WIN1_TRSL_ADDR_LSB; volatile uint32_t ATR7_PCIE_WIN1_TRSL_ADDR_UDW; volatile uint32_t ATR7_PCIE_WIN1_TRSL_PARAM; volatile uint32_t RESERVED27; volatile uint32_t ATR7_PCIE_WIN1_TRSL_MASK_DW0; volatile uint32_t ATR7_PCIE_WIN1_TRSL_MASK_DW1; volatile uint32_t ATR0_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR0_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR0_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR0_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR0_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED28; volatile uint32_t ATR0_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR0_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR1_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR1_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR1_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR1_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR1_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED29; volatile uint32_t ATR1_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR1_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR2_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR2_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR2_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR2_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR2_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED30; volatile uint32_t ATR2_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR2_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR3_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR3_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR3_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR3_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR3_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED31; volatile uint32_t ATR3_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR3_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR4_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR4_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR4_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR4_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR4_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED32; volatile uint32_t ATR4_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR4_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR5_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR5_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR5_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR5_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR5_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED33; volatile uint32_t ATR5_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR5_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR6_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR6_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR6_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR6_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR6_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED34; volatile uint32_t ATR6_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR6_AXI4_SLV0_TRSL_MASK_DW1; volatile uint32_t ATR7_AXI4_SLV0_SRCADDR_PARAM; volatile uint32_t ATR7_AXI4_SLV0_SRC_ADDR; volatile uint32_t ATR7_AXI4_SLV0_TRSL_ADDR_LSB; volatile uint32_t ATR7_AXI4_SLV0_TRSL_ADDR_UDW; volatile uint32_t ATR7_AXI4_SLV0_TRSL_PARAM; volatile uint32_t RESERVED35; volatile uint32_t ATR7_AXI4_SLV0_TRSL_MASK_DW0; volatile uint32_t ATR7_AXI4_SLV0_TRSL_MASK_DW1; } PCIE_BRIDGE_TypeDef; /*------------------------------------------------------------------------------ PCIE Configuration Type 0 Space Registers. */ typedef struct { /*======================= Information registers ======================*/ /** Information register: vendor_id & device_id bits [15:0] vendor_id bits [31:16] device_id */ /* 0x000 */ volatile uint32_t VID_DEVID; /** PCI Express Control & Status Register: cfg_prmscr */ /* 0x004 */ volatile uint32_t CFG_PRMSCR; /** Information register: class_code */ /* 0x008 */ volatile uint32_t CLASS_CODE; /** BIST, Header, master latency timer, cache : BIST_HEADER */ /* 0x00C */ volatile uint32_t BIST_HEADER; /** Bridge Configuration Register: bar0 */ /* 0x010 */ volatile uint32_t BAR0; /** Bridge Configuration Register: bar1 */ /* 0x014 */ volatile uint32_t BAR1; /** Bridge Configuration Register: bar2 */ /* 0x018 */ volatile uint32_t BAR2; /** Bridge Configuration Register: bar3 */ /* 0x01C */ volatile uint32_t BAR3; /** Bridge Configuration Register: bar4 */ /* 0x020 */ volatile uint32_t BAR4; /** Bridge Configuration Register: bar5 */ /* 0x024 */ volatile uint32_t BAR5; volatile uint32_t RESERVED1; /** Information register: subsystem_id */ /* 0x02C */ volatile uint32_t SUBSYSTEM_ID; /** Expansion ROM Base Address Register: expansion_rom */ /* 0x030 */ volatile uint32_t EXPAN_ROM; /** Capability pointer register: capab_pointer */ /* 0x034 */ volatile uint32_t CAPAB_POINTER; /** Expansion ROM Base Address register: expansion_rom_base */ /* 0x038 */ volatile uint32_t EXPAN_ROM_BASE; /** Interrupt Line and Pin register: int_line_pin */ /* 0x03C */ volatile uint32_t INT_LINE_PIN; /* 0x40 to 0x7C */ volatile uint32_t RESERVED2[16]; /* PCIe Capability structure register */ /** PCIe Capability list register: CAPAB_LIST */ /* 0x080 */ volatile uint32_t CAPAB_LIST; /** Device Capabilities register: device_capab */ /* 0x084 */ volatile uint32_t DEVICE_CAPAB; /** Device Control and status register: device_ctrl_stat */ /* 0x088 */ volatile uint32_t DEVICE_CTRL_STAT; /** Link Capabilities register: link_capab */ /* 0x08C */ volatile uint32_t LINK_CAPAB; /** Link Control and status register: link_ctrl_stat */ /* 0x090 */ volatile uint32_t LINK_CTRL_STAT; /** Slot capabilities register: slot_capab */ /* 0x094 */ volatile uint32_t SLOT_CAPAB; /** Slot Control and status register: slot_ctrl_stat */ /* 0x098 */ volatile uint32_t SLOT_CTRL_STAT; /** Root control register: root_ctrl */ /* 0x09C */ volatile uint32_t ROOT_CTRL; /** Root status register: root_stat */ /* 0x0A0 */ volatile uint32_t ROOT_STAT; /** Device 2 Capabilities register: device2_capab */ /* 0x0A4 */ volatile uint32_t DEVICE2_CAPAB; /** Device 2 Control and status register: device2_ctrl_stat */ /* 0x0A8 */ volatile uint32_t DEVICE2_CTRL_STAT; /** Link Capabilities 2 register: link2_capab */ /* 0x0AC */ volatile uint32_t LINK2_CAPAB; /** Link Control and status 2register: link2_ctrl_stat */ /* 0x0B0 */ volatile uint32_t LINK2_CTRL_STAT; /** Slot 2 capabilities register: slot2_capab */ /* 0x0B4 */ volatile uint32_t SLOT2_CAPAB; /** Slot 2 Control and status register: slot2_ctrl_stat */ /* 0x0B8 */ volatile uint32_t SLOT2_CTRL_STAT; /* 0xBC to 0xCC */ volatile uint32_t RESERVED3[5]; /* MSI-X Capability (optional)*/ /** MSI-X capability and control register: msi_x_capab_ctrl */ /* 0x0D0 */ volatile uint32_t MSI_X_CAPAB_CTRL; /** MSI-X table register: msi_x_table */ /* 0x0D4 */ volatile uint32_t MSI_X_TABLE; /** MSI-X PBA register: msi_x_pba */ /* 0x0D8 */ volatile uint32_t MSI_X_PBA; /* 0xDC */ volatile uint32_t RESERVED4; /** MSI capability id and message control register: msi_capab_ctrl */ /* 0x0E0 */ volatile uint32_t MSI_CAPAB_CTRL; /** MSI message lower address register: msi_lower address */ /* 0x0E4 */ volatile uint32_t MSI_LOWER_ADDRESS; /** MSI message upper address register: msi_upper address */ /* 0x0E8 */ volatile uint32_t MSI_UPPER_ADDRESS; /* 0xEC */ volatile uint32_t RESERVED5; /** MSI message data register: msi_data */ /* 0x0F0 */ volatile uint32_t MSI_DATA; /* 0xF4 */ volatile uint32_t RESERVED6; /* Power Management Capability Structure */ /** Power Management Capability register: power_mngm_capab */ /* 0x0F8 */ volatile uint32_t POWER_MNGM_CAPAB; /** Power Management control and status register: power_ctrl_stat */ /* 0x0FC */ volatile uint32_t POWER_CTRL_STAT; } PCIE_END_CONF_TypeDef; /*------------------------------------------------------------------------------ PCIE Configuration Type 1 Space Registers. */ typedef struct { /*======================= Information registers ======================*/ /** Information register: vendor_id & device_id bits [15:0] vendor_id bits [31:16] device_id */ /* 0x000 */ volatile uint32_t VID_DEVID; /** PCI Express Control & Status Register: cfg_prmscr */ /* 0x004 */ volatile uint32_t CFG_PRMSCR; /** Information register: class_code */ /* 0x008 */ volatile uint32_t CLASS_CODE; /** BIST, Header, master latency timer, cache : BIST_HEADER */ /* 0x00C */ volatile uint32_t BIST_HEADER; /** Bridge Configuration Register: bar0 */ /* 0x010 */ volatile uint32_t BAR0; /** Bridge Configuration Register: bar1 */ /* 0x014 */ volatile uint32_t BAR1; /** Secondary Latency timer, Subordinate bus number, Secondary bus Number, primary bus number Register: prim_sec_bus_num */ /* 0x018 */ volatile uint32_t PRIM_SEC_BUS_NUM; /** Secondary status, I/O limit, I/O base Register: io_limit_base */ /* 0x01C */ volatile uint32_t IO_LIMIT_BASE; /** memory limit, memory base Register: mem_limit_base */ /* 0x020 */ volatile uint32_t MEM_LIMIT_BASE; /** prefetchable memory limit, memory base Register: pref_mem_limit_base */ /* 0x024 */ volatile uint32_t PREF_MEM_LIMIT_BASE; /** prefetchable base upper Register: pref_base_upper */ /* 0x028 */ volatile uint32_t PREF_BASE_UPPER; /** prefetchable limit upper Register: pref_limit_upper */ /* 0x02C */ volatile uint32_t PREF_LIMIT_UPPER; /** i/o base, limit upper Register: io_limit_base_upper */ /* 0x030 */ volatile uint32_t IO_LIMIT_BASE_UPPER; /** Capability pointer register: capab_pointer */ /* 0x034 */ volatile uint32_t CAPAB_POINTER; /** Expansion ROM Base Address register: expansion_rom_base */ /* 0x038 */ volatile uint32_t EXPAN_ROM_BASE; /** Interrupt Line and Pin register: int_line_pin */ /* 0x03C */ volatile uint32_t INT_LINE_PIN; /* 0x40 to 0x7C */ volatile uint32_t RESERVED2[16]; /* PCIe Capability structure register */ /** PCIe Capability list register: CAPAB_LIST */ /* 0x080 */ volatile uint32_t CAPAB_LIST; /** Device Capabilities register: device_capab */ /* 0x084 */ volatile uint32_t DEVICE_CAPAB; /** Device Control and status register: device_ctrl_stat */ /* 0x088 */ volatile uint32_t DEVICE_CTRL_STAT; /** Link Capabilities register: link_capab */ /* 0x08C */ volatile uint32_t LINK_CAPAB; /** Link Control and status register: link_ctrl_stat */ /* 0x090 */ volatile uint32_t LINK_CTRL_STAT; /** Slot capabilities register: slot_capab */ /* 0x094 */ volatile uint32_t SLOT_CAPAB; /** Slot Control and status register: slot_ctrl_stat */ /* 0x098 */ volatile uint32_t SLOT_CTRL_STAT; /** Root control register: root_ctrl */ /* 0x09C */ volatile uint32_t ROOT_CTRL; /** Root status register: root_stat */ /* 0x0A0 */ volatile uint32_t ROOT_STAT; /** Device 2 Capabilities register: device2_capab */ /* 0x0A4 */ volatile uint32_t DEVICE2_CAPAB; /** Device 2 Control and status register: device2_ctrl_stat */ /* 0x0A8 */ volatile uint32_t DEVICE2_CTRL_STAT; /** Link Capabilities 2 register: link2_capab */ /* 0x0AC */ volatile uint32_t LINK2_CAPAB; /** Link Control and status 2register: link2_ctrl_stat */ /* 0x0B0 */ volatile uint32_t LINK2_CTRL_STAT; /** Slot 2 capabilities register: slot2_capab */ /* 0x0B4 */ volatile uint32_t SLOT2_CAPAB; /** Slot 2 Control and status register: slot2_ctrl_stat */ /* 0x0B8 */ volatile uint32_t SLOT2_CTRL_STAT; /* 0xBC to 0xCC */ volatile uint32_t RESERVED3[5]; /* MSI-X Capability (optional)*/ /** MSI-X capability and control register: msi_x_capab_ctrl */ /* 0x0D0 */ volatile uint32_t MSI_X_CAPAB_CTRL; /** MSI-X table register: msi_x_table */ /* 0x0D4 */ volatile uint32_t MSI_X_TABLE; /** MSI-X PBA register: msi_x_pba */ /* 0x0D8 */ volatile uint32_t MSI_X_PBA; /* 0xDC */ volatile uint32_t RESERVED4; /** MSI capability id and message control register: msi_capab_ctrl */ /* 0x0E0 */ volatile uint32_t MSI_CAPAB_CTRL; /** MSI message lower address register: msi_lower address */ /* 0x0E4 */ volatile uint32_t MSI_LOWER_ADDRESS; /** MSI message upper address register: msi_upper address */ /* 0x0E8 */ volatile uint32_t MSI_UPPER_ADDRESS; /* 0xEC */ volatile uint32_t RESERVED5; /** MSI message data register: msi_data */ /* 0x0F0 */ volatile uint32_t MSI_DATA; /* 0xF4 */ volatile uint32_t RESERVED6; /* Power Management Capability Structure */ /** Power Management Capability register: power_mngm_capab */ /* 0x0F8 */ volatile uint32_t POWER_MNGM_CAPAB; /** Power Management control and status register: power_ctrl_stat */ /* 0x0FC */ volatile uint32_t POWER_CTRL_STAT; } PCIE_ROOT_CONF_TypeDef; /*------------------------------------------------------------------------------ PCIESS sub system registers typedef struct { PCS_LANE_TypeDef pcs_lane[4]; PCS_CMN_TypeDef pcs_cmn; PMA_LANE_TypeDef pma_lane[4]; TXPLL_SSC_TypeDef txpll_ssc; TXPLL_TypeDef txpll[2]; PCIESS_MAIN_TypeDef pciess_main; PCIE_BRIDGE_TypeDef pcie_bridge[2]; PCIE_END_CONF_TypeDef pcie_end_config_space; PCIE_ROOT_CONF_TypeDef pcie_root_config_space; PCIE_CTRL_TypeDef pcie_ctrl[2]; } PCIESS_TypeDef; */ /*----------------------------------------------------------------------------*/ #define PCS_LANE PCS_LANE_TypeDef #define PCS_CMN PCS_CMN_TypeDef #define PMA_LANE PMA_LANE_TypeDef #define TXPLL_SSC TXPLL_SSC_TypeDef #define TXPLL TXPLL_TypeDef #define PCIESS_MAIN PCIESS_MAIN_TypeDef #define PCIE_BRIDGE PCIE_BRIDGE_TypeDef #define PCIE_END_CONF PCIE_END_CONF_TypeDef #define PCIE_ROOT_CONF PCIE_ROOT_CONF_TypeDef #define PCIE_CTRL PCIE_CTRL_TypeDef /*----------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ PCIE Configuration Type 0 Space Registers offset definitions. */ #define DEVICE_VID_DEVID 0x000u #define DEVICE_CFG_PRMSCR 0x004u #define DEVICE_CLASS_CODE 0x008u #define DEVICE_BIST_HEADER 0x00Cu #define DEVICE_BAR0 0x010u #define DEVICE_BAR1 0x014u #define DEVICE_BAR2 0x018u #define DEVICE_BAR3 0x01Cu #define DEVICE_BAR4 0x020u #define DEVICE_BAR5 0x024u #define DEVICE_SUBSYSTEM_ID 0x02Cu #define DEVICE_EXPAN_ROM 0x030u #define DEVICE_CAPAB_POINTER 0x034u #define DEVICE_EXPAN_ROM_BASE 0x038u #define DEVICE_INT_LINE_PIN 0x03Cu #define DEVICE_CAPAB_LIST 0x080u #define DEVICE_DEVICE_CAPAB 0x084u #define DEVICE_DEVICE_CTRL_STAT 0x088u #define DEVICE_LINK_CAPAB 0x08Cu #define DEVICE_LINK_CTRL_STAT 0x090u #define DEVICE_SLOT_CAPAB 0x094u #define DEVICE_SLOT_CTRL_STAT 0x098u #define DEVICE_ROOT_CTRL 0x09Cu #define DEVICE_ROOT_STAT 0x0A0u #define DEVICE_DEVICE2_CAPAB 0x0A4u #define DEVICE_DEVICE2_CTRL_STAT 0x0A8u #define DEVICE_LINK2_CAPAB 0x0ACu #define DEVICE_LINK2_CTRL_STAT 0x0B0u #define DEVICE_SLOT2_CAPAB 0x0B4u #define DEVICE_SLOT2_CTRL_STAT 0x0B8u #define DEVICE_MSI_X_CAPAB_CTRL 0x0D0u #define DEVICE_MSI_X_TABLE 0x0D4u #define DEVICE_MSI_X_PBA 0x0D8u #define DEVICE_MSI_CAPAB_CTRL 0x0E0u #define DEVICE_MSI_LOWER_ADDRESS 0x0E4u #define DEVICE_MSI_UPPER_ADDRESS 0x0E8u #define DEVICE_MSI_DATA 0x0F0u #define DEVICE_POWER_MNGM_CAPAB 0x0F8u #define DEVICE_POWER_CTRL_STAT 0x0FCu /*------------------------------------------------------------------------------ The table below shows the base address and available address space for each of the leaf instances in the pciess system. Instance Name Base Address Range pcs_lane_0 0x004 1000 4 KBytes pcs_lane_1 0x004 2000 4 KBytes pcs_lane_2 0x004 4000 4 KBytes pcs_lane_3 0x004 8000 4 KBytes pcs_cmn 0x005 0000 4 KBytes pma_lane_0 0x104 1000 4 KBytes pma_lane_1 0x104 2000 4 KBytes pma_lane_2 0x104 4000 4 KBytes pma_lane_3 0x104 8000 4 KBytes txpll_ssc(pma_cmn) 0x105 0000 4 KBytes tx(quad)_pll_0 0x204 4000 4 KBytes tx(quad)_pll_1 0x204 8000 4 KBytes pciess_main 0x205 0000 4 KBytes pcie_top_0__g5_xpressrich3_bridge 0x300 4000 8 KBytes pcie_top_0__pcie_ctrl 0x300 6000 4 KBytes pcie_top_1__g5_xpressrich3_bridge 0x300 8000 8 KBytes pcie_top_1__pcie_ctrl 0x300 A000 4 KBytes ------------------------------------------------------------------------------*/ #define PCIESS_PCS_LANE0_PHY_ADDR_OFFSET 0x00041000u #define PCIESS_PCS_LANE1_PHY_ADDR_OFFSET 0x00042000u #define PCIESS_PCS_LANE2_PHY_ADDR_OFFSET 0x00044000u #define PCIESS_PCS_LANE3_PHY_ADDR_OFFSET 0x00048000u #define PCIESS_PCS_CMN_PHY_ADDR_OFFSET 0x00050000u #define PCIESS_PMA_LANE0_PHY_ADDR_OFFSET 0x01041000u #define PCIESS_PMA_LANE1_PHY_ADDR_OFFSET 0x01042000u #define PCIESS_PMA_LANE2_PHY_ADDR_OFFSET 0x01044000u #define PCIESS_PMA_LANE3_PHY_ADDR_OFFSET 0x01048000u #define PCIESS_TXPLL_SSC_PHY_ADDR_OFFSET 0x01050000u #define PCIESS_TXPLL0_PHY_ADDR_OFFSET 0x02044000u #define PCIESS_TXPLL1_PHY_ADDR_OFFSET 0x02048000u #define PCIESS_MAIN_PHY_ADDR_OFFSET 0x02050000u #define PCIE0_BRIDGE_PHY_ADDR_OFFSET 0x03004000u #define PCIE0_CRTL_PHY_ADDR_OFFSET 0x03006000u #define PCIE1_BRIDGE_PHY_ADDR_OFFSET 0x03008000u #define PCIE1_CRTL_PHY_ADDR_OFFSET 0x0300A000u #ifdef __cplusplus } #endif #endif /* PF_PCIESS_REGS_H_ */ pf_pcie_types.h000066400000000000000000000270211432224323300370620ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/pf_pcie/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * PolarFire and PolarFire SoC PCIe subsystem software driver public * data structures. * * SVN $Revision$ * SVN $Date$ */ #ifndef PF_PCIESS_TYPES_H_ #define PF_PCIESS_TYPES_H_ #include #ifdef __cplusplus extern "C" { #endif /***************************************************************************** PCIe AXI master and slave table size enum i.e PCIe ATR_SIZE PCIe ATR_SIZE is 6 bits long and defines the Address Translation Space Size. This space size in bytes is equal to 2^(ATR_SIZE +1). The pf_pcie_atr_size_t type specifies the table sizes supported by the PolarFire PCIe driver for the initialization of the PCIe AXI4 master and slave address translation tables. */ typedef enum { PF_PCIE_SIZE_4KB = 11, PF_PCIE_SIZE_8KB, PF_PCIE_SIZE_16KB, PF_PCIE_SIZE_32KB, PF_PCIE_SIZE_64KB, PF_PCIE_SIZE_128KB, PF_PCIE_SIZE_256KB, PF_PCIE_SIZE_512KB, PF_PCIE_SIZE_1MB, PF_PCIE_SIZE_2MB, PF_PCIE_SIZE_4MB, PF_PCIE_SIZE_8MB, PF_PCIE_SIZE_16MB, PF_PCIE_SIZE_32MB, PF_PCIE_SIZE_64MB, PF_PCIE_SIZE_128MB, PF_PCIE_SIZE_256MB, PF_PCIE_SIZE_512MB, PF_PCIE_SIZE_1GB, PF_PCIE_SIZE_2GB, PF_PCIE_SIZE_4GB, PF_PCIE_SIZE_8GB, PF_PCIE_SIZE_16GB, PF_PCIE_SIZE_32GB, PF_PCIE_SIZE_64GB, PF_PCIE_SIZE_128GB, PF_PCIE_SIZE_256GB, PF_PCIE_SIZE_512GB, PF_PCIE_SIZE_1TB, PF_PCIE_SIZE_2TB, PF_PCIE_SIZE_4TB, PF_PCIE_SIZE_8TB, PF_PCIE_SIZE_16TB, PF_PCIE_SIZE_32TB, PF_PCIE_SIZE_64TB, PF_PCIE_SIZE_128TB, PF_PCIE_SIZE_256TB, PF_PCIE_SIZE_512TB } pf_pcie_atr_size_t; /***************************************************************************** The pf_pcie_bar_type_t type specifies the bar types supported by the driver for the initialization of the PCIe AXI4 master address translation table. PCIe BAR type enum for 32-bit and 64-bit memory. */ typedef enum { PF_PCIE_BAR_TYPE_32BIT_MEM = 0x0, PF_PCIE_BAR_TYPE_32BIT_PREFET_MEM = 0x8, PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM = 0xC } pf_pcie_bar_type_t; /***************************************************************************** The pf_pcie_tlp_type_t type specifies the transaction layer packet types supported by the driver for the initialization of the PCIe AXI4 master and slave address translation tables. */ typedef enum { PF_PCIE_TLP_MEM = 0, PF_PCIE_TLP_MEM_LOCKED = 1, PF_PCIE_TLP_IO = 2, PF_PCIE_TLP_TRSNL_REQUEST = 3, PF_PCIE_TLP_MESSAGE = 4, PF_PCIE_TLP_MEM_TRSNL_REQUEST = 5 } pf_pcie_tlp_type_t; /***************************************************************************** The pf_pcie_ep_dma_status_t type communicates the status of the DMA transfer initiated by the most recent call to the PF_PCIE_dma_write() or PF_PCIE_dma_read() function. It indicates if a transfer is in progress, and if this is not the case, indicates the outcome of the latest transfer. This type is returned by the PF_PCIE_dma_get_transfer_status() function and used as a parameter for the handler functions registered with the PCIe driver. The following table shows the different statuses of an endpoint DMA transfer indicated by the pf_pcie_ep_dma_status_t type. - PF_PCIE_EP_DMA_NOT_INITIALIZED - The DMA controller is not initialized - PF_PCIE_EP_DMA_IN_PROGRESS - A DMA transfer is in progress. - PF_PCIE_EP_DMA_COMPLETED - The most recent DMA transfer initiated by a call to PF_PCIE_dma_write() or PF_PCIE_dma_read() has completed successfully. - PF_PCIE_EP_DMA_ERROR - An error is detected in a DMA controller transfer, source, or destination completion. */ typedef enum { PF_PCIE_EP_DMA_NOT_INITIALIZED = 0, PF_PCIE_EP_DMA_IN_PROGRESS, PF_PCIE_EP_DMA_COMPLETED, PF_PCIE_EP_DMA_ERROR }pf_pcie_ep_dma_status_t; /***************************************************************************//** The pf_pcie_write_callback_t type defines the function prototype that must be followed by PolarFire PCIe End Point DMA write completion handler function. Declaring and Implementing the write call-back function: The write call-back function should follow the following prototype: void transmit_callback(pf_pcie_ep_dma_status_t status); The actual name of the call-back function is unimportant. You can use any name of your choice for the write call-back function. */ typedef void (*pf_pcie_write_callback_t)(pf_pcie_ep_dma_status_t status); /***************************************************************************//** The pf_pcie_read_callback_t type defines the function prototype that must be followed by PolarFire PCIe End Point DMA read completion handler function. Declaring and Implementing the read call-back function: The read call-back function should follow the following prototype: void receive_callback(pf_pcie_ep_dma_status_t status); The actual name of the call-back function is unimportant. You can use any name of your choice for the read call-back function. */ typedef void (*pf_pcie_read_callback_t)(pf_pcie_ep_dma_status_t status); /***************************************************************************** The pf_pcie_info_t structure contains the PCIe system(device or bridge) vendor id, bus, device and function number. bus_num Specifies the bus number of the PCIe system. device_num Specifies the device number of the PCIe system. fun_num Specifies the function number of the PCIe system. vendor_id Specifies the vendor id of PCIe endpoint or bridge or switch. */ typedef struct { uint16_t bus_num; uint8_t dev_num; uint8_t fun_num; uint16_t vendor_id; } pf_pcie_info_t; /***************************************************************************** The pf_pcie_bar_info_t structure contains information about the memory allocated on the host processor for the PCIe endpoint. It is used in the PF_PCIE_allocate_memory() function. bar_address Specifies the memory address allocated on the host processor for the PCIe endpoint BAR. bar_size Specifies the size of the memory allocated on the host processor for the PCIe endpoint BAR. */ typedef struct { uint32_t bar0_address; uint32_t bar0_size; uint32_t bar1_address; uint32_t bar1_size; uint32_t bar2_address; uint32_t bar2_size; uint32_t bar3_address; uint32_t bar3_size; uint32_t bar4_address; uint32_t bar4_size; uint32_t bar5_address; uint32_t bar5_size; }pf_pcie_bar_info_t; /****************************************************************************** The pf_pcie_ebuff_t structure is used in PCIe enumeration process to store the number of bridges and devices attached to the PCIe root port. The PF_PCIE_enumeration() function returns this structure to the application during PCIe enumeration. bridges Contains information about the attached PCIe bridge or switch, such as the bus number, device number, function number, and vendor ID. devices Contains information about the attached PCIe devices, such as the bus number, device number, function number, and vendor ID. no_of_bridges_attached Specifies the numbers of PCIe bridges attached to the PCIe system. no_of_devices_attached Specifies the numbers of PCIe endpoints attached on the PCIe system. */ typedef struct { pf_pcie_info_t bridges[8u]; pf_pcie_info_t devices[8u]; uint8_t no_of_bridges_attached; uint8_t no_of_devices_attached; } pf_pcie_ebuff_t; /***************************************************************************** PCIe AXI4 Master ATR table configuration structure. The user must create a record of the pf_pcie_master_atr_cfg_t type to hold the configuration of the PCIe AXI4 master ATR table. The PF_PCIE_master_atr_table_init() function is used to create this configuration record by entering the desired values. state Enables and disables the translation address table implementation. * PF_PCIE_ATR_TABLE_ENABLE * PF_PCIE_ATR_TABLE_DISABLE bar_type Sets the PCIe BAR type memory on AXI4 master ATR table to 32-bit or 64-bit memory. * PF_PCIE_BAR_TYPE_32BIT_MEM * PF_PCIE_BAR_TYPE_32BIT_PREFET_MEM * PF_PCIE_BAR_TYPE_64BIT_PREFET_MEM bar_size Specifies the size of the PCIe BAR space. The pf_pcie_atr_size_t type is used assign the bar size. * PF_PCIE_SIZE_4KB * PF_PCIE_SIZE_8KB * PF_PCIE_SIZE_16KB * PF_PCIE_SIZE_32KB * PF_PCIE_SIZE_64KB * PF_PCIE_SIZE_128KB ............ ............ * PF_PCIE_SIZE_512TB table_size Specifies the size of the PCIe AXI4 master address translation table. The pf_pcie_atr_size_t type is used to assign the table size. * PF_PCIE_SIZE_4KB * PF_PCIE_SIZE_8KB * PF_PCIE_SIZE_16KB * PF_PCIE_SIZE_32KB * PF_PCIE_SIZE_64KB * PF_PCIE_SIZE_128KB ............ ............ * PF_PCIE_SIZE_512TB src_addr Specifies the lower 32-bit source address of the PCIe AXI4 master address translation space. src_addr_msb Specifies the upper 32-bit (63:32-bit) source address of the PCIe AXI4 master address translation space. trns_addr Specifies the translated lower 32-bit address of the PCIe AXI4 master address translation space. trns_addr_msb Specifies the translated upper 32-bit(63:32-bit) address of the PCIe AXI4 master address translation space. */ typedef struct { uint32_t state; pf_pcie_bar_type_t bar_type; pf_pcie_atr_size_t bar_size; pf_pcie_atr_size_t table_size; uint32_t src_addr; uint32_t src_addr_msb; uint32_t trns_addr; uint32_t trns_addr_msb; } pf_pcie_master_atr_cfg_t; /***************************************************************************** PCIe AXI4 Slave ATR table configuration structure. The user must create a record of the pf_pcie_slave_atr_cfg_t type to hold the configuration of the PCIe AXI4 slave ATR table. The PF_PCIE_slave_atr_table_init() function is used to craete this configuration record by entering the desired values. state Enables and disables the translation address table implementation. * PF_PCIE_ATR_TABLE_ENABLE * PF_PCIE_ATR_TABLE_DISABLE size Specifies the size of the PCIe AXI4 slave address translation table. The pf_pcie_atr_size_t type is used to assign the table size. * PF_PCIE_SIZE_4KB * PF_PCIE_SIZE_8KB * PF_PCIE_SIZE_16KB * PF_PCIE_SIZE_32KB * PF_PCIE_SIZE_64KB * PF_PCIE_SIZE_128KB ............ ............ * PF_PCIE_SIZE_512TB src_addr Specifies the lower 32-bit source address of the PCIe AXI4 slave address translation space. src_addr_msb Specifies the upper 32-bit (63:32-bit) source address of the PCIe AXI4 slave address translation space. trns_addr Specifies the translated lower 32-bit address of the PCIe AXI4 slave address translation space. trns_addr_msb Specifies the translated upper 32-bit (63:32-bit) address of the PCIe AXI4 slave address translation space. */ typedef struct { uint32_t state; pf_pcie_atr_size_t size; uint32_t src_addr; uint32_t src_addr_msb; uint32_t trns_addr; uint32_t trns_addr_msb; } pf_pcie_slave_atr_cfg_t; #ifdef __cplusplus } #endif #endif /* PF_PCIESS_H_ */ hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/000077500000000000000000000000001432224323300316165ustar00rootroot00000000000000cpu_types.h000066400000000000000000000016101432224323300337210ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ #ifndef CPU_TYPES_H #define CPU_TYPES_H #ifdef __cplusplus extern "C" { #endif #include /*------------------------------------------------------------------------------ * addr_t: address type. * Used to specify the address of peripherals present in the processor's memory * map. */ typedef unsigned long addr_t; /*------------------------------------------------------------------------------ * psr_t: processor state register. * Used by HAL_disable_interrupts() and HAL_restore_interrupts() to store the * processor's state between disabling and restoring interrupts. */ typedef unsigned long psr_t; #ifdef __cplusplus } #endif #endif /* CPU_TYPES_H */ hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/hal.h000066400000000000000000000257041432224323300325430ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * MPFS HAL Embedded Software * */ /***************************************************************************//** * * Hardware abstraction layer functions. * * Legacy register interrupt functions * Pointers are now recommended for use in drivers * */ #ifndef HAL_H #define HAL_H #ifdef __cplusplus extern "C" { #endif #include "cpu_types.h" #include "hw_reg_access.h" /***************************************************************************//** * Enable all interrupts at the processor level. */ void HAL_enable_interrupts( void ); /***************************************************************************//** * Disable all interrupts at the processor core level. * Return the interrupts enable state before disabling occured so that it can * later be restored. */ psr_t HAL_disable_interrupts( void ); /***************************************************************************//** * Restore the interrupts enable state at the processor core level. * This function is normally passed the value returned from a previous call to * HAL_disable_interrupts(). */ void HAL_restore_interrupts( psr_t saved_psr ); /***************************************************************************//** */ #define FIELD_OFFSET(FIELD_NAME) (FIELD_NAME##_OFFSET) #define FIELD_SHIFT(FIELD_NAME) (FIELD_NAME##_SHIFT) #define FIELD_MASK(FIELD_NAME) (FIELD_NAME##_MASK) /***************************************************************************//** * The macro HAL_set_32bit_reg() allows writing a 32 bits wide register. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * REG_NAME: A string identifying the register to write. These strings are * specified in a header file associated with the peripheral. * VALUE: A variable of type uint32_t containing the value to write. */ #define HAL_set_32bit_reg(BASE_ADDR, REG_NAME, VALUE) \ (HW_set_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) /***************************************************************************//** * The macro HAL_get_32bit_reg() is used to read the value of a 32 bits wide * register. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * REG_NAME: A string identifying the register to read. These strings are * specified in a header file associated with the peripheral. * RETURN: This function-like macro returns a uint32_t value. */ #define HAL_get_32bit_reg(BASE_ADDR, REG_NAME) \ (HW_get_32bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)) )) /***************************************************************************//** * The macro HAL_set_32bit_reg_field() is used to write a field within a * 32 bits wide register. The field written can be one or more bits. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * FIELD_NAME: A string identifying the register field to write. These strings * are specified in a header file associated with the peripheral. * VALUE: A variable of type uint32_t containing the field value to write. */ #define HAL_set_32bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ (HW_set_32bit_reg_field(\ (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ FIELD_SHIFT(FIELD_NAME),\ FIELD_MASK(FIELD_NAME),\ (VALUE))) /***************************************************************************//** * The macro HAL_get_32bit_reg_field() is used to read a register field from * within a 32 bit wide peripheral register. The field can be one or more bits. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * FIELD_NAME: A string identifying the register field to write. These strings * are specified in a header file associated with the peripheral. * RETURN: This function-like macro returns a uint32_t value. */ #define HAL_get_32bit_reg_field(BASE_ADDR, FIELD_NAME) \ (HW_get_32bit_reg_field(\ (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ FIELD_SHIFT(FIELD_NAME),\ FIELD_MASK(FIELD_NAME))) /***************************************************************************//** * The macro HAL_set_16bit_reg() allows writing a 16 bits wide register. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * REG_NAME: A string identifying the register to write. These strings are * specified in a header file associated with the peripheral. * VALUE: A variable of type uint_fast16_t containing the value to write. */ #define HAL_set_16bit_reg(BASE_ADDR, REG_NAME, VALUE) \ (HW_set_16bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) /***************************************************************************//** * The macro HAL_get_16bit_reg() is used to read the value of a 16 bits wide * register. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * REG_NAME: A string identifying the register to read. These strings are * specified in a header file associated with the peripheral. * RETURN: This function-like macro returns a uint16_t value. */ #define HAL_get_16bit_reg(BASE_ADDR, REG_NAME) \ (HW_get_16bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) /***************************************************************************//** * The macro HAL_set_16bit_reg_field() is used to write a field within a * 16 bits wide register. The field written can be one or more bits. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * FIELD_NAME: A string identifying the register field to write. These strings * are specified in a header file associated with the peripheral. * VALUE: A variable of type uint16_t containing the field value to write. */ #define HAL_set_16bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ (HW_set_16bit_reg_field(\ (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ FIELD_SHIFT(FIELD_NAME),\ FIELD_MASK(FIELD_NAME),\ (VALUE))) /***************************************************************************//** * The macro HAL_get_16bit_reg_field() is used to read a register field from * within a 8 bit wide peripheral register. The field can be one or more bits. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * FIELD_NAME: A string identifying the register field to write. These strings * are specified in a header file associated with the peripheral. * RETURN: This function-like macro returns a uint16_t value. */ #define HAL_get_16bit_reg_field(BASE_ADDR, FIELD_NAME) \ (HW_get_16bit_reg_field(\ (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ FIELD_SHIFT(FIELD_NAME),\ FIELD_MASK(FIELD_NAME))) /***************************************************************************//** * The macro HAL_set_8bit_reg() allows writing a 8 bits wide register. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * REG_NAME: A string identifying the register to write. These strings are * specified in a header file associated with the peripheral. * VALUE: A variable of type uint_fast8_t containing the value to write. */ #define HAL_set_8bit_reg(BASE_ADDR, REG_NAME, VALUE) \ (HW_set_8bit_reg( ((BASE_ADDR) + (REG_NAME##_REG_OFFSET)), (VALUE) )) /***************************************************************************//** * The macro HAL_get_8bit_reg() is used to read the value of a 8 bits wide * register. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * REG_NAME: A string identifying the register to read. These strings are * specified in a header file associated with the peripheral. * RETURN: This function-like macro returns a uint8_t value. */ #define HAL_get_8bit_reg(BASE_ADDR, REG_NAME) \ (HW_get_8bit_reg( (BASE_ADDR) + (REG_NAME##_REG_OFFSET) )) /***************************************************************************//** */ #define HAL_set_8bit_reg_field(BASE_ADDR, FIELD_NAME, VALUE) \ (HW_set_8bit_reg_field(\ (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ FIELD_SHIFT(FIELD_NAME),\ FIELD_MASK(FIELD_NAME),\ (VALUE))) /***************************************************************************//** * The macro HAL_get_8bit_reg_field() is used to read a register field from * within a 8 bit wide peripheral register. The field can be one or more bits. * * BASE_ADDR: A variable of type addr_t specifying the base address of the * peripheral containing the register. * FIELD_NAME: A string identifying the register field to write. These strings * are specified in a header file associated with the peripheral. * RETURN: This function-like macro returns a uint8_t value. */ #define HAL_get_8bit_reg_field(BASE_ADDR, FIELD_NAME) \ (HW_get_8bit_reg_field(\ (BASE_ADDR) + FIELD_OFFSET(FIELD_NAME),\ FIELD_SHIFT(FIELD_NAME),\ FIELD_MASK(FIELD_NAME))) #ifdef __cplusplus } #endif #endif /*HAL_H*/ hal_assert.h000066400000000000000000000030411432224323300340330ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ #ifndef ASSERT_HEADER #define ASSERT_HEADER #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * ASSERT() implementation. ******************************************************************************/ /* Disable assertions if we do not recognize the compiler. */ #if defined ( __GNUC__ ) #if defined(NDEBUG) #define ASSERT(CHECK) #else #define ASSERT(CHECK)\ do { \ if (!(CHECK)) \ { \ __asm volatile ("ebreak"); \ }\ } while(0); #endif /* NDEBUG check */ #endif /* compiler check */ #if defined(NDEBUG) /***************************************************************************//** * ASSERT() is defined out when the NDEBUG symbol is used. ******************************************************************************/ #define ASSERT(CHECK) #else /***************************************************************************//** * Default behaviour for ASSERT() macro: *------------------------------------------------------------------------------ The behaviour is toolchain specific and project setting specific. ******************************************************************************/ #define ASSERT(CHECK) ASSERT(CHECK); #endif /* NDEBUG */ #ifdef __cplusplus } #endif #endif /* ASSERT_HEADER */ hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/hal_irq.c000066400000000000000000000022231432224323300334000ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /***************************************************************************//** * * Legacy interrupt control functions for the Microchip driver library hardware * abstraction layer. * */ #include #include "hal/hal.h" #include "atomic.h" #include "encoding.h" //#include "mpfs_hal/mcall.h" #include "mss_util.h" #include "mss_mtrap.h" #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------------ * */ void HAL_enable_interrupts(void) { __enable_irq(); } /*------------------------------------------------------------------------------ * */ psr_t HAL_disable_interrupts(void) { psr_t psr; psr = read_csr(mstatus); __disable_irq(); return(psr); } /*------------------------------------------------------------------------------ * */ void HAL_restore_interrupts(psr_t saved_psr) { write_csr(mstatus, saved_psr); } #ifdef __cplusplus } #endif hw_macros.h000066400000000000000000000102421432224323300336710ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * Hardware registers access macros. * * THE MACROS DEFINED IN THIS FILE ARE DEPRECATED. DO NOT USE FOR NEW * DEVELOPMENT. * * These macros are used to access peripheral registers. They allow access to * 8, 16 and 32 bit wide registers. All accesses to peripheral registers should * be done through these macros in order to ease porting across different * processors/bus architectures. * * Some of these macros also allow access to a specific register field. * */ #ifndef HW_MACROS_H #define HW_MACROS_H #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------------ * 32 bits registers access: */ #define HW_get_uint32_reg(BASE_ADDR, REG_OFFSET) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) #define HW_set_uint32_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint32_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) #define HW_set_uint32_reg_field(BASE_ADDR, FIELD, VALUE) \ (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ ( \ (uint32_t) \ ( \ (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ (uint32_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ ) \ ) #define HW_get_uint32_reg_field( BASE_ADDR, FIELD ) \ (( (*((uint32_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) /*------------------------------------------------------------------------------ * 32 bits memory access: */ #define HW_get_uint32(BASE_ADDR) (*((uint32_t volatile *)(BASE_ADDR))) #define HW_set_uint32(BASE_ADDR, VALUE) (*((uint32_t volatile *)(BASE_ADDR)) = (VALUE)) /*------------------------------------------------------------------------------ * 16 bits registers access: */ #define HW_get_uint16_reg(BASE_ADDR, REG_OFFSET) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) #define HW_set_uint16_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint16_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) #define HW_set_uint16_reg_field(BASE_ADDR, FIELD, VALUE) \ (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ ( \ (uint16_t) \ ( \ (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ (uint16_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ ) \ ) #define HW_get_uint16_reg_field( BASE_ADDR, FIELD ) \ (( (*((uint16_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) /*------------------------------------------------------------------------------ * 8 bits registers access: */ #define HW_get_uint8_reg(BASE_ADDR, REG_OFFSET) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET))) #define HW_set_uint8_reg(BASE_ADDR, REG_OFFSET, VALUE) (*((uint8_t volatile *)(BASE_ADDR + REG_OFFSET##_REG_OFFSET)) = (VALUE)) #define HW_set_uint8_reg_field(BASE_ADDR, FIELD, VALUE) \ (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET)) = \ ( \ (uint8_t) \ ( \ (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & ~FIELD##_MASK) | \ (uint8_t)(((VALUE) << FIELD##_SHIFT) & FIELD##_MASK) \ ) \ ) #define HW_get_uint8_reg_field( BASE_ADDR, FIELD ) \ (( (*((uint8_t volatile *)(BASE_ADDR + FIELD##_OFFSET))) & FIELD##_MASK) >> FIELD##_SHIFT) /*------------------------------------------------------------------------------ * 8 bits memory access: */ #define HW_get_uint8(BASE_ADDR) (*((uint8_t volatile *)(BASE_ADDR))) #define HW_set_uint8(BASE_ADDR, VALUE) (*((uint8_t volatile *)(BASE_ADDR)) = (VALUE)) #ifdef __cplusplus extern "C" { #endif #endif /* HW_MACROS_ */ hw_reg_access.S000066400000000000000000000130271432224323300344620ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /***************************************************************************//** * * Hardware registers access functions. * The implementation of these function is platform and toolchain specific. * The functions declared here are implemented using assembler as part of the * processor/toolchain specific HAL. * */ .section .text .globl HW_set_32bit_reg .globl HW_get_32bit_reg .globl HW_set_32bit_reg_field .globl HW_get_32bit_reg_field .globl HW_set_16bit_reg .globl HW_get_16bit_reg .globl HW_set_16bit_reg_field .globl HW_get_16bit_reg_field .globl HW_set_8bit_reg .globl HW_get_8bit_reg .globl HW_set_8bit_reg_field .globl HW_get_8bit_reg_field /***************************************************************************//** * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral * register. * * a0: addr_t reg_addr * a1: uint32_t value */ HW_set_32bit_reg: sw a1, 0(a0) ret /***************************************************************************//** * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral * register. * * a0: addr_t reg_addr * @return 32 bits value read from the peripheral register. */ HW_get_32bit_reg: lw a0, 0(a0) ret /***************************************************************************//** * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits * wide peripheral register. * * a0: addr_t reg_addr * a1: int_fast8_t shift * a2: uint32_t mask * a3: uint32_t value */ HW_set_32bit_reg_field: mv t3, a3 sll t3, t3, a1 and t3, t3, a2 lw t1, 0(a0) mv t2, a2 not t2, t2 and t1, t1, t2 or t1, t1, t3 sw t1, 0(a0) ret /***************************************************************************//** * HW_get_32bit_reg_field is used to read the content of a field out of a * 32 bits wide peripheral register. * * a0: addr_t reg_addr * a1: int_fast8_t shift * a2: uint32_t mask * * @return 32 bits value containing the register field value specified * as parameter. */ HW_get_32bit_reg_field: lw a0, 0(a0) and a0, a0, a2 srl a0, a0, a1 ret /***************************************************************************//** * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral * register. * * a0: addr_t reg_addr * a1: uint_fast16_t value */ HW_set_16bit_reg: sh a1, 0(a0) ret /***************************************************************************//** * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral * register. * * a0: addr_t reg_addr * @return 16 bits value read from the peripheral register. */ HW_get_16bit_reg: lh a0, (a0) ret /***************************************************************************//** * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits * wide peripheral register. * * a0: addr_t reg_addr * a1: int_fast8_t shift * a2: uint_fast16_t mask * a3: uint_fast16_t value * @param value Value to be written in the specified field. */ HW_set_16bit_reg_field: mv t3, a3 sll t3, t3, a1 and t3, t3, a2 lh t1, 0(a0) mv t2, a2 not t2, t2 and t1, t1, t2 or t1, t1, t3 sh t1, 0(a0) ret /***************************************************************************//** * HW_get_16bit_reg_field is used to read the content of a field from a * 16 bits wide peripheral register. * * a0: addr_t reg_addr * a1: int_fast8_t shift * a2: uint_fast16_t mask * * @return 16 bits value containing the register field value specified * as parameter. */ HW_get_16bit_reg_field: lh a0, 0(a0) and a0, a0, a2 srl a0, a0, a1 ret /***************************************************************************//** * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral * register. * * a0: addr_t reg_addr * a1: uint_fast8_t value */ HW_set_8bit_reg: sb a1, 0(a0) ret /***************************************************************************//** * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral * register. * * a0: addr_t reg_addr * @return 8 bits value read from the peripheral register. */ HW_get_8bit_reg: lb a0, 0(a0) ret /***************************************************************************//** * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits * wide peripheral register. * * a0: addr_t reg_addr, * a1: int_fast8_t shift * a2: uint_fast8_t mask * a3: uint_fast8_t value */ HW_set_8bit_reg_field: mv t3, a3 sll t3, t3, a1 and t3, t3, a2 lb t1, 0(a0) mv t2, a2 not t2, t2 and t1, t1, t2 or t1, t1, t3 sb t1, 0(a0) ret /***************************************************************************//** * HW_get_8bit_reg_field is used to read the content of a field from a * 8 bits wide peripheral register. * * a0: addr_t reg_addr * a1: int_fast8_t shift * a2: uint_fast8_t mask * * @return 8 bits value containing the register field value specified * as parameter. */ HW_get_8bit_reg_field: lb a0, 0(a0) and a0, a0, a2 srl a0, a0, a1 ret .end hw_reg_access.h000066400000000000000000000167621432224323300345200ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /***************************************************************************//** * * Hardware registers access functions. * The implementation of these function is platform and toolchain specific. * The functions declared here are implemented using assembler as part of the * processor/toolchain specific HAL. * */ #ifndef HW_REG_ACCESS #define HW_REG_ACCESS #ifdef __cplusplus extern "C" { #endif #include "cpu_types.h" /***************************************************************************//** * HW_set_32bit_reg is used to write the content of a 32 bits wide peripheral * register. * * @param reg_addr Address in the processor's memory map of the register to * write. * @param value Value to be written into the peripheral register. */ void HW_set_32bit_reg ( addr_t reg_addr, uint32_t value ); /***************************************************************************//** * HW_get_32bit_reg is used to read the content of a 32 bits wide peripheral * register. * * @param reg_addr Address in the processor's memory map of the register to * read. * @return 32 bits value read from the peripheral register. */ uint32_t HW_get_32bit_reg ( addr_t reg_addr ); /***************************************************************************//** * HW_set_32bit_reg_field is used to set the content of a field in a 32 bits * wide peripheral register. * * @param reg_addr Address in the processor's memory map of the register to * be written. * @param shift Bit offset of the register field to be read within the * register. * @param mask Bit mask to be applied to the raw register value to filter * out the other register fields values. * @param value Value to be written in the specified field. */ void HW_set_32bit_reg_field ( addr_t reg_addr, int_fast8_t shift, uint32_t mask, uint32_t value ); /***************************************************************************//** * HW_get_32bit_reg_field is used to read the content of a field out of a * 32 bits wide peripheral register. * * @param reg_addr Address in the processor's memory map of the register to * read. * @param shift Bit offset of the register field to be written within the * register. * @param mask Bit mask to be applied to the raw register value to filter * out the other register fields values. * * @return 32 bits value containing the register field value specified * as parameter. */ uint32_t HW_get_32bit_reg_field ( addr_t reg_addr, int_fast8_t shift, uint32_t mask ); /***************************************************************************//** * HW_set_16bit_reg is used to write the content of a 16 bits wide peripheral * register. * * @param reg_addr Address in the processor's memory map of the register to * write. * @param value Value to be written into the peripheral register. */ void HW_set_16bit_reg ( addr_t reg_addr, uint_fast16_t value ); /***************************************************************************//** * HW_get_16bit_reg is used to read the content of a 16 bits wide peripheral * register. * * @param reg_addr Address in the processor's memory map of the register to * read. * @return 16 bits value read from the peripheral register. */ uint16_t HW_get_16bit_reg ( addr_t reg_addr ); /***************************************************************************//** * HW_set_16bit_reg_field is used to set the content of a field in a 16 bits * wide peripheral register. * * @param reg_addr Address in the processor's memory map of the register to * be written. * @param shift Bit offset of the register field to be read within the * register. * @param mask Bit mask to be applied to the raw register value to filter * out the other register fields values. * @param value Value to be written in the specified field. */ void HW_set_16bit_reg_field ( addr_t reg_addr, int_fast8_t shift, uint_fast16_t mask, uint_fast16_t value ); /***************************************************************************//** * HW_get_16bit_reg_field is used to read the content of a field from a * 16 bits wide peripheral register. * * @param reg_addr Address in the processor's memory map of the register to * read. * @param shift Bit offset of the register field to be written within the * register. * @param mask Bit mask to be applied to the raw register value to filter * out the other register fields values. * * @return 16 bits value containing the register field value specified * as parameter. */ uint16_t HW_get_16bit_reg_field ( addr_t reg_addr, int_fast8_t shift, uint_fast16_t mask ); /***************************************************************************//** * HW_set_8bit_reg is used to write the content of a 8 bits wide peripheral * register. * * @param reg_addr Address in the processor's memory map of the register to * write. * @param value Value to be written into the peripheral register. */ void HW_set_8bit_reg ( addr_t reg_addr, uint_fast8_t value ); /***************************************************************************//** * HW_get_8bit_reg is used to read the content of a 8 bits wide peripheral * register. * * @param reg_addr Address in the processor's memory map of the register to * read. * @return 8 bits value read from the peripheral register. */ uint8_t HW_get_8bit_reg ( addr_t reg_addr ); /***************************************************************************//** * HW_set_8bit_reg_field is used to set the content of a field in a 8 bits * wide peripheral register. * * @param reg_addr Address in the processor's memory map of the register to * be written. * @param shift Bit offset of the register field to be read within the * register. * @param mask Bit mask to be applied to the raw register value to filter * out the other register fields values. * @param value Value to be written in the specified field. */ void HW_set_8bit_reg_field ( addr_t reg_addr, int_fast8_t shift, uint_fast8_t mask, uint_fast8_t value ); /***************************************************************************//** * HW_get_8bit_reg_field is used to read the content of a field from a * 8 bits wide peripheral register. * * @param reg_addr Address in the processor's memory map of the register to * read. * @param shift Bit offset of the register field to be written within the * register. * @param mask Bit mask to be applied to the raw register value to filter * out the other register fields values. * * @return 8 bits value containing the register field value specified * as parameter. */ uint8_t HW_get_8bit_reg_field ( addr_t reg_addr, int_fast8_t shift, uint_fast8_t mask ); #ifdef __cplusplus } #endif #endif /* HW_REG_ACCESS */ hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/hal/readme.md000066400000000000000000000030471432224323300334010ustar00rootroot00000000000000=============================================================================== # hal folder =============================================================================== The HAL folder provides support code for use by the bare metal drivers for the fabric IP cores. The HAL folder contains files using a combination of C and assembly source code. The hal folder should be included in a PolarFire SoC Embedded project under the platform directory. See location in the drawing below. The hal folder contains: * register access functions * assert macros ### Project directory strucutre, showing where hal folder sits. +---------+ +-----------+ | src +----->|application| +---------+ | +-----------+ | | +-----------+ +-->|modules | | +-----------+ | | +-----------+ +---------+ +-->|platform +---->|config | +-----------+ | +---------+ | | +---------+ +->|drivers | | +---------+ | | +---------+ +->|hal | | +---------+ | | +---------+ +->|mpfs_hal | +---------+hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/000077500000000000000000000000001432224323300326435ustar00rootroot00000000000000Jenkinsfile000066400000000000000000000001421432224323300347450ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal@Library('automated-testing-library') _ pipelineBareMetalDriverSrc(examplesRepoBranch: 'develop') common/000077500000000000000000000000001432224323300340545ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_halatomic.h000066400000000000000000000045421432224323300355060ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/* Copyright (c) 2013, The Regents of the University of California (Regents). All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Regents nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*********************************************************************************** * Record of Microchip changes */ #ifndef RISCV_ATOMIC_H #define RISCV_ATOMIC_H #ifdef __cplusplus extern "C" { #endif #define mb() asm volatile ("fence" ::: "memory") #define atomic_set(ptr, val) (*(volatile typeof(*(ptr)) *)(ptr) = val) #define atomic_read(ptr) (*(volatile typeof(*(ptr)) *)(ptr)) #ifdef __riscv_atomic # define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp) # define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc) #else #define atomic_binop(ptr, inc, op) ({ \ long flags = disable_irqsave(); \ typeof(*(ptr)) res = atomic_read(ptr); \ atomic_set(ptr, op); \ enable_irqrestore(flags); \ res; }) #define atomic_or(ptr, inc) atomic_binop(ptr, inc, res | (inc)) #define atomic_swap(ptr, swp) atomic_binop(ptr, swp, (swp)) #endif #ifdef __cplusplus } #endif #endif //RISCV_ATOMIC_H bits.h000066400000000000000000000051021432224323300351640ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/* Copyright (c) 2013, The Regents of the University of California (Regents). All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Regents nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*********************************************************************************** * Record of Microchip changes */ #ifndef RISCV_BITS_H #define RISCV_BITS_H #ifdef __cplusplus extern "C" { #endif #define likely(x) __builtin_expect((x), 1) #define unlikely(x) __builtin_expect((x), 0) #ifndef ROUNDUP # define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b)) #endif #ifndef ROUNDDOWN # define ROUNDDOWN(a, b) ((a)/(b)*(b)) #endif #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi) #define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1))) #define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1)))) #define STR(x) XSTR(x) #define XSTR(x) #x #if __riscv_xlen == 64 # define SLL32 sllw # define STORE sd # define LOAD ld # define LWU lwu # define LOG_REGBYTES 3 #else # define SLL32 sll # define STORE sw # define LOAD lw # define LWU lw # define LOG_REGBYTES 2 #endif #define REGBYTES (1 << LOG_REGBYTES) #ifdef __cplusplus } #endif #endif //RISCV_BITS_H encoding.h000066400000000000000000001525251432224323300360250ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/* Copyright (c) 2013, The Regents of the University of California (Regents). All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Regents nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*********************************************************************************** * Record of Microchip changes */ #ifndef RISCV_CSR_ENCODING_H #define RISCV_CSR_ENCODING_H #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 #define MSTATUS_HIE 0x00000004 #define MSTATUS_MIE 0x00000008 #define MSTATUS_UPIE 0x00000010 #define MSTATUS_SPIE 0x00000020 #define MSTATUS_HPIE 0x00000040 #define MSTATUS_MPIE 0x00000080 #define MSTATUS_SPP 0x00000100 #define MSTATUS_HPP 0x00000600 #define MSTATUS_MPP 0x00001800 #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 #define MSTATUS_MPRV 0x00020000 #define MSTATUS_SUM 0x00040000 #define MSTATUS_MXR 0x00080000 #define MSTATUS_TVM 0x00100000 #define MSTATUS_TW 0x00200000 #define MSTATUS_TSR 0x00400000 #define MSTATUS32_SD 0x80000000 #define MSTATUS64_SD 0x8000000000000000 #define MCAUSE32_CAUSE 0x7FFFFFFF #define MCAUSE64_CAUSE 0x7FFFFFFFFFFFFFFF #define MCAUSE32_INT 0x80000000 #define MCAUSE64_INT 0x8000000000000000 #define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE 0x00000002 #define SSTATUS_UPIE 0x00000010 #define SSTATUS_SPIE 0x00000020 #define SSTATUS_SPP 0x00000100 #define SSTATUS_FS 0x00006000 #define SSTATUS_XS 0x00018000 #define SSTATUS_SUM 0x00040000 #define SSTATUS_MXR 0x00080000 #define SSTATUS32_SD 0x80000000 #define SSTATUS64_SD 0x8000000000000000 #define DCSR_XDEBUGVER (3U<<30) #define DCSR_NDRESET (1<<29) #define DCSR_FULLRESET (1<<28) #define DCSR_EBREAKM (1<<15) #define DCSR_EBREAKH (1<<14) #define DCSR_EBREAKS (1<<13) #define DCSR_EBREAKU (1<<12) #define DCSR_STOPCYCLE (1<<10) #define DCSR_STOPTIME (1<<9) #define DCSR_CAUSE (7<<6) #define DCSR_DEBUGINT (1<<5) #define DCSR_HALT (1<<3) #define DCSR_STEP (1<<2) #define DCSR_PRV (3<<0) #define DCSR_CAUSE_NONE 0 #define DCSR_CAUSE_SWBP 1 #define DCSR_CAUSE_HWBP 2 #define DCSR_CAUSE_DEBUGINT 3 #define DCSR_CAUSE_STEP 4 #define DCSR_CAUSE_HALT 5 #define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) #define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) #define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) #define MCONTROL_SELECT (1U<<19) #define MCONTROL_TIMING (1U<<18) #define MCONTROL_ACTION (0x3fU<<12) #define MCONTROL_CHAIN (1U<<11) #define MCONTROL_MATCH (0xfU<<7) #define MCONTROL_M (1U<<6) #define MCONTROL_H (1U<<5) #define MCONTROL_S (1U<<4) #define MCONTROL_U (1U<<3) #define MCONTROL_EXECUTE (1U<<2) #define MCONTROL_STORE (1U<<1) #define MCONTROL_LOAD (1U<<0) #define MCONTROL_TYPE_NONE 0 #define MCONTROL_TYPE_MATCH 2 #define MCONTROL_ACTION_DEBUG_EXCEPTION 0 #define MCONTROL_ACTION_DEBUG_MODE 1 #define MCONTROL_ACTION_TRACE_START 2 #define MCONTROL_ACTION_TRACE_STOP 3 #define MCONTROL_ACTION_TRACE_EMIT 4 #define MCONTROL_MATCH_EQUAL 0 #define MCONTROL_MATCH_NAPOT 1 #define MCONTROL_MATCH_GE 2 #define MCONTROL_MATCH_LT 3 #define MCONTROL_MATCH_MASK_LOW 4 #define MCONTROL_MATCH_MASK_HIGH 5 #define MIP_SSIP (1U << IRQ_S_SOFT) #define MIP_HSIP (1U << IRQ_H_SOFT) #define MIP_MSIP (1U << IRQ_M_SOFT) #define MIP_STIP (1U << IRQ_S_TIMER) #define MIP_HTIP (1U << IRQ_H_TIMER) #define MIP_MTIP (1U << IRQ_M_TIMER) #define MIP_SEIP (1U << IRQ_S_EXT) #define MIP_HEIP (1U << IRQ_H_EXT) #define MIP_MEIP (1U << IRQ_M_EXT) #define SIP_SSIP MIP_SSIP #define SIP_STIP MIP_STIP #define PRV_U 0 #define PRV_S 1 #define PRV_H 2 #define PRV_M 3 #define SPTBR32_MODE 0x80000000 #define SPTBR32_ASID 0x7FC00000 #define SPTBR32_PPN 0x003FFFFF #define SPTBR64_MODE 0xF000000000000000 #define SPTBR64_ASID 0x0FFFF00000000000 #define SPTBR64_PPN 0x00000FFFFFFFFFFF #define SPTBR_MODE_OFF 0 #define SPTBR_MODE_SV32 1 #define SPTBR_MODE_SV39 8 #define SPTBR_MODE_SV48 9 #define SPTBR_MODE_SV57 10 #define SPTBR_MODE_SV64 11 #define PMP_R 0x01 #define PMP_W 0x02 #define PMP_X 0x04 #define PMP_A 0x18 #define PMP_L 0x80 #define PMP_SHIFT 2 #define PMP_TOR 0x08 #define PMP_NA4 0x10 #define PMP_NAPOT 0x18 #define IRQ_S_SOFT 1 #define IRQ_H_SOFT 2 #define IRQ_M_SOFT 3 #define IRQ_S_TIMER 5 #define IRQ_H_TIMER 6 #define IRQ_M_TIMER 7 #define IRQ_S_EXT 9 #define IRQ_H_EXT 10 #define IRQ_M_EXT 11 #define IRQ_COP 12 #define IRQ_HOST 13 #define DEFAULT_RSTVEC 0x00001000 #define CLINT_BASE 0x02000000 #define CLINT_SIZE 0x000c0000 #define EXT_IO_BASE 0x40000000 #define DRAM_BASE 0x80000000 // page table entry (PTE) fields #define PTE_V 0x001 // Valid #define PTE_R 0x002 // Read #define PTE_W 0x004 // Write #define PTE_X 0x008 // Execute #define PTE_U 0x010 // User #define PTE_G 0x020 // Global #define PTE_A 0x040 // Accessed #define PTE_D 0x080 // Dirty #define PTE_SOFT 0x300 // Reserved for Software #define PTE_PPN_SHIFT 10 #define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) #ifdef __riscv #if __riscv_xlen == 64 # define MSTATUS_SD MSTATUS64_SD # define SSTATUS_SD SSTATUS64_SD # define RISCV_PGLEVEL_BITS 9 # define SPTBR_MODE SPTBR64_MODE # define MCAUSE_INT MCAUSE64_INT //ML added- should we be using later encoding.h? # define MCAUSE_CAUSE MCAUSE64_CAUSE //ML added- should we be using later encoding.h? #else # define MSTATUS_SD MSTATUS32_SD # define SSTATUS_SD SSTATUS32_SD # define RISCV_PGLEVEL_BITS 10 # define SPTBR_MODE SPTBR32_MODE # define MCAUSE_INT MCAUSE32_INT //ML added- should we be using later encoding.h? # define MCAUSE_CAUSE MCAUSE32_CAUSE //ML added- should we be using later encoding.h? #endif #define RISCV_PGSHIFT 12 #define RISCV_PGSIZE (1 << RISCV_PGSHIFT) #ifndef __ASSEMBLER__ #ifdef __GNUC__ #define read_reg(reg) ({ unsigned long __tmp; \ asm volatile ("mv %0, " #reg : "=r"(__tmp)); \ __tmp; }) #define read_csr(reg) __extension__({ unsigned long __tmp; \ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ __tmp; }) #define write_csr(reg, val) __extension__({ \ asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) #define swap_csr(reg, val) ({ unsigned long __tmp; \ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ __tmp; }) #define set_csr(reg, bit) __extension__({ unsigned long __tmp; \ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) #define clear_csr(reg, bit) __extension__({ unsigned long __tmp; \ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) #if 0 #define csr_write(csr, val) \ ({ \ unsigned long __v = (unsigned long)(val); \ asm volatile ("csrw " __ASM_STR(csr) ", %0" \ : : "rK" (__v) \ : "memory"); \ }) #define csr_write(csr, val) \ ({ \ unsigned long __v = (unsigned long)(val); \ __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ : : "rK" (__v) \ : "memory"); \ }) #endif #define rdtime() read_csr(time) #define rdcycle() read_csr(cycle) #define rdinstret() read_csr(instret) #endif #endif #endif #endif /* Automatically generated by parse-opcodes. */ #ifndef RISCV_ENCODING_H #define RISCV_ENCODING_H #define MATCH_BEQ 0x63 #define MASK_BEQ 0x707f #define MATCH_BNE 0x1063 #define MASK_BNE 0x707f #define MATCH_BLT 0x4063 #define MASK_BLT 0x707f #define MATCH_BGE 0x5063 #define MASK_BGE 0x707f #define MATCH_BLTU 0x6063 #define MASK_BLTU 0x707f #define MATCH_BGEU 0x7063 #define MASK_BGEU 0x707f #define MATCH_JALR 0x67 #define MASK_JALR 0x707f #define MATCH_JAL 0x6f #define MASK_JAL 0x7f #define MATCH_LUI 0x37 #define MASK_LUI 0x7f #define MATCH_AUIPC 0x17 #define MASK_AUIPC 0x7f #define MATCH_ADDI 0x13 #define MASK_ADDI 0x707f #define MATCH_SLLI 0x1013 #define MASK_SLLI 0xfc00707f #define MATCH_SLTI 0x2013 #define MASK_SLTI 0x707f #define MATCH_SLTIU 0x3013 #define MASK_SLTIU 0x707f #define MATCH_XORI 0x4013 #define MASK_XORI 0x707f #define MATCH_SRLI 0x5013 #define MASK_SRLI 0xfc00707f #define MATCH_SRAI 0x40005013 #define MASK_SRAI 0xfc00707f #define MATCH_ORI 0x6013 #define MASK_ORI 0x707f #define MATCH_ANDI 0x7013 #define MASK_ANDI 0x707f #define MATCH_ADD 0x33 #define MASK_ADD 0xfe00707f #define MATCH_SUB 0x40000033 #define MASK_SUB 0xfe00707f #define MATCH_SLL 0x1033 #define MASK_SLL 0xfe00707f #define MATCH_SLT 0x2033 #define MASK_SLT 0xfe00707f #define MATCH_SLTU 0x3033 #define MASK_SLTU 0xfe00707f #define MATCH_XOR 0x4033 #define MASK_XOR 0xfe00707f #define MATCH_SRL 0x5033 #define MASK_SRL 0xfe00707f #define MATCH_SRA 0x40005033 #define MASK_SRA 0xfe00707f #define MATCH_OR 0x6033 #define MASK_OR 0xfe00707f #define MATCH_AND 0x7033 #define MASK_AND 0xfe00707f #define MATCH_ADDIW 0x1b #define MASK_ADDIW 0x707f #define MATCH_SLLIW 0x101b #define MASK_SLLIW 0xfe00707f #define MATCH_SRLIW 0x501b #define MASK_SRLIW 0xfe00707f #define MATCH_SRAIW 0x4000501b #define MASK_SRAIW 0xfe00707f #define MATCH_ADDW 0x3b #define MASK_ADDW 0xfe00707f #define MATCH_SUBW 0x4000003b #define MASK_SUBW 0xfe00707f #define MATCH_SLLW 0x103b #define MASK_SLLW 0xfe00707f #define MATCH_SRLW 0x503b #define MASK_SRLW 0xfe00707f #define MATCH_SRAW 0x4000503b #define MASK_SRAW 0xfe00707f #define MATCH_LB 0x3 #define MASK_LB 0x707f #define MATCH_LH 0x1003 #define MASK_LH 0x707f #define MATCH_LW 0x2003 #define MASK_LW 0x707f #define MATCH_LD 0x3003 #define MASK_LD 0x707f #define MATCH_LBU 0x4003 #define MASK_LBU 0x707f #define MATCH_LHU 0x5003 #define MASK_LHU 0x707f #define MATCH_LWU 0x6003 #define MASK_LWU 0x707f #define MATCH_SB 0x23 #define MASK_SB 0x707f #define MATCH_SH 0x1023 #define MASK_SH 0x707f #define MATCH_SW 0x2023 #define MASK_SW 0x707f #define MATCH_SD 0x3023 #define MASK_SD 0x707f #define MATCH_FENCE 0xf #define MASK_FENCE 0x707f #define MATCH_FENCE_I 0x100f #define MASK_FENCE_I 0x707f #define MATCH_MUL 0x2000033 #define MASK_MUL 0xfe00707f #define MATCH_MULH 0x2001033 #define MASK_MULH 0xfe00707f #define MATCH_MULHSU 0x2002033 #define MASK_MULHSU 0xfe00707f #define MATCH_MULHU 0x2003033 #define MASK_MULHU 0xfe00707f #define MATCH_DIV 0x2004033 #define MASK_DIV 0xfe00707f #define MATCH_DIVU 0x2005033 #define MASK_DIVU 0xfe00707f #define MATCH_REM 0x2006033 #define MASK_REM 0xfe00707f #define MATCH_REMU 0x2007033 #define MASK_REMU 0xfe00707f #define MATCH_MULW 0x200003b #define MASK_MULW 0xfe00707f #define MATCH_DIVW 0x200403b #define MASK_DIVW 0xfe00707f #define MATCH_DIVUW 0x200503b #define MASK_DIVUW 0xfe00707f #define MATCH_REMW 0x200603b #define MASK_REMW 0xfe00707f #define MATCH_REMUW 0x200703b #define MASK_REMUW 0xfe00707f #define MATCH_AMOADD_W 0x202f #define MASK_AMOADD_W 0xf800707f #define MATCH_AMOXOR_W 0x2000202f #define MASK_AMOXOR_W 0xf800707f #define MATCH_AMOOR_W 0x4000202f #define MASK_AMOOR_W 0xf800707f #define MATCH_AMOAND_W 0x6000202f #define MASK_AMOAND_W 0xf800707f #define MATCH_AMOMIN_W 0x8000202f #define MASK_AMOMIN_W 0xf800707f #define MATCH_AMOMAX_W 0xa000202f #define MASK_AMOMAX_W 0xf800707f #define MATCH_AMOMINU_W 0xc000202f #define MASK_AMOMINU_W 0xf800707f #define MATCH_AMOMAXU_W 0xe000202f #define MASK_AMOMAXU_W 0xf800707f #define MATCH_AMOSWAP_W 0x800202f #define MASK_AMOSWAP_W 0xf800707f #define MATCH_LR_W 0x1000202f #define MASK_LR_W 0xf9f0707f #define MATCH_SC_W 0x1800202f #define MASK_SC_W 0xf800707f #define MATCH_AMOADD_D 0x302f #define MASK_AMOADD_D 0xf800707f #define MATCH_AMOXOR_D 0x2000302f #define MASK_AMOXOR_D 0xf800707f #define MATCH_AMOOR_D 0x4000302f #define MASK_AMOOR_D 0xf800707f #define MATCH_AMOAND_D 0x6000302f #define MASK_AMOAND_D 0xf800707f #define MATCH_AMOMIN_D 0x8000302f #define MASK_AMOMIN_D 0xf800707f #define MATCH_AMOMAX_D 0xa000302f #define MASK_AMOMAX_D 0xf800707f #define MATCH_AMOMINU_D 0xc000302f #define MASK_AMOMINU_D 0xf800707f #define MATCH_AMOMAXU_D 0xe000302f #define MASK_AMOMAXU_D 0xf800707f #define MATCH_AMOSWAP_D 0x800302f #define MASK_AMOSWAP_D 0xf800707f #define MATCH_LR_D 0x1000302f #define MASK_LR_D 0xf9f0707f #define MATCH_SC_D 0x1800302f #define MASK_SC_D 0xf800707f #define MATCH_ECALL 0x73 #define MASK_ECALL 0xffffffff #define MATCH_EBREAK 0x100073 #define MASK_EBREAK 0xffffffff #define MATCH_URET 0x200073 #define MASK_URET 0xffffffff #define MATCH_SRET 0x10200073 #define MASK_SRET 0xffffffff #define MATCH_HRET 0x20200073 #define MASK_HRET 0xffffffff #define MATCH_MRET 0x30200073 #define MASK_MRET 0xffffffff #define MATCH_DRET 0x7b200073 #define MASK_DRET 0xffffffff #define MATCH_SFENCE_VMA 0x12000073 #define MASK_SFENCE_VMA 0xfe007fff #define MATCH_WFI 0x10500073 #define MASK_WFI 0xffffffff #define MATCH_CSRRW 0x1073 #define MASK_CSRRW 0x707f #define MATCH_CSRRS 0x2073 #define MASK_CSRRS 0x707f #define MATCH_CSRRC 0x3073 #define MASK_CSRRC 0x707f #define MATCH_CSRRWI 0x5073 #define MASK_CSRRWI 0x707f #define MATCH_CSRRSI 0x6073 #define MASK_CSRRSI 0x707f #define MATCH_CSRRCI 0x7073 #define MASK_CSRRCI 0x707f #define MATCH_FADD_S 0x53 #define MASK_FADD_S 0xfe00007f #define MATCH_FSUB_S 0x8000053 #define MASK_FSUB_S 0xfe00007f #define MATCH_FMUL_S 0x10000053 #define MASK_FMUL_S 0xfe00007f #define MATCH_FDIV_S 0x18000053 #define MASK_FDIV_S 0xfe00007f #define MATCH_FSGNJ_S 0x20000053 #define MASK_FSGNJ_S 0xfe00707f #define MATCH_FSGNJN_S 0x20001053 #define MASK_FSGNJN_S 0xfe00707f #define MATCH_FSGNJX_S 0x20002053 #define MASK_FSGNJX_S 0xfe00707f #define MATCH_FMIN_S 0x28000053 #define MASK_FMIN_S 0xfe00707f #define MATCH_FMAX_S 0x28001053 #define MASK_FMAX_S 0xfe00707f #define MATCH_FSQRT_S 0x58000053 #define MASK_FSQRT_S 0xfff0007f #define MATCH_FADD_D 0x2000053 #define MASK_FADD_D 0xfe00007f #define MATCH_FSUB_D 0xa000053 #define MASK_FSUB_D 0xfe00007f #define MATCH_FMUL_D 0x12000053 #define MASK_FMUL_D 0xfe00007f #define MATCH_FDIV_D 0x1a000053 #define MASK_FDIV_D 0xfe00007f #define MATCH_FSGNJ_D 0x22000053 #define MASK_FSGNJ_D 0xfe00707f #define MATCH_FSGNJN_D 0x22001053 #define MASK_FSGNJN_D 0xfe00707f #define MATCH_FSGNJX_D 0x22002053 #define MASK_FSGNJX_D 0xfe00707f #define MATCH_FMIN_D 0x2a000053 #define MASK_FMIN_D 0xfe00707f #define MATCH_FMAX_D 0x2a001053 #define MASK_FMAX_D 0xfe00707f #define MATCH_FCVT_S_D 0x40100053 #define MASK_FCVT_S_D 0xfff0007f #define MATCH_FCVT_D_S 0x42000053 #define MASK_FCVT_D_S 0xfff0007f #define MATCH_FSQRT_D 0x5a000053 #define MASK_FSQRT_D 0xfff0007f #define MATCH_FADD_Q 0x6000053 #define MASK_FADD_Q 0xfe00007f #define MATCH_FSUB_Q 0xe000053 #define MASK_FSUB_Q 0xfe00007f #define MATCH_FMUL_Q 0x16000053 #define MASK_FMUL_Q 0xfe00007f #define MATCH_FDIV_Q 0x1e000053 #define MASK_FDIV_Q 0xfe00007f #define MATCH_FSGNJ_Q 0x26000053 #define MASK_FSGNJ_Q 0xfe00707f #define MATCH_FSGNJN_Q 0x26001053 #define MASK_FSGNJN_Q 0xfe00707f #define MATCH_FSGNJX_Q 0x26002053 #define MASK_FSGNJX_Q 0xfe00707f #define MATCH_FMIN_Q 0x2e000053 #define MASK_FMIN_Q 0xfe00707f #define MATCH_FMAX_Q 0x2e001053 #define MASK_FMAX_Q 0xfe00707f #define MATCH_FCVT_S_Q 0x40300053 #define MASK_FCVT_S_Q 0xfff0007f #define MATCH_FCVT_Q_S 0x46000053 #define MASK_FCVT_Q_S 0xfff0007f #define MATCH_FCVT_D_Q 0x42300053 #define MASK_FCVT_D_Q 0xfff0007f #define MATCH_FCVT_Q_D 0x46100053 #define MASK_FCVT_Q_D 0xfff0007f #define MATCH_FSQRT_Q 0x5e000053 #define MASK_FSQRT_Q 0xfff0007f #define MATCH_FLE_S 0xa0000053 #define MASK_FLE_S 0xfe00707f #define MATCH_FLT_S 0xa0001053 #define MASK_FLT_S 0xfe00707f #define MATCH_FEQ_S 0xa0002053 #define MASK_FEQ_S 0xfe00707f #define MATCH_FLE_D 0xa2000053 #define MASK_FLE_D 0xfe00707f #define MATCH_FLT_D 0xa2001053 #define MASK_FLT_D 0xfe00707f #define MATCH_FEQ_D 0xa2002053 #define MASK_FEQ_D 0xfe00707f #define MATCH_FLE_Q 0xa6000053 #define MASK_FLE_Q 0xfe00707f #define MATCH_FLT_Q 0xa6001053 #define MASK_FLT_Q 0xfe00707f #define MATCH_FEQ_Q 0xa6002053 #define MASK_FEQ_Q 0xfe00707f #define MATCH_FCVT_W_S 0xc0000053 #define MASK_FCVT_W_S 0xfff0007f #define MATCH_FCVT_WU_S 0xc0100053 #define MASK_FCVT_WU_S 0xfff0007f #define MATCH_FCVT_L_S 0xc0200053 #define MASK_FCVT_L_S 0xfff0007f #define MATCH_FCVT_LU_S 0xc0300053 #define MASK_FCVT_LU_S 0xfff0007f #define MATCH_FMV_X_S 0xe0000053 #define MASK_FMV_X_S 0xfff0707f #define MATCH_FCLASS_S 0xe0001053 #define MASK_FCLASS_S 0xfff0707f #define MATCH_FCVT_W_D 0xc2000053 #define MASK_FCVT_W_D 0xfff0007f #define MATCH_FCVT_WU_D 0xc2100053 #define MASK_FCVT_WU_D 0xfff0007f #define MATCH_FCVT_L_D 0xc2200053 #define MASK_FCVT_L_D 0xfff0007f #define MATCH_FCVT_LU_D 0xc2300053 #define MASK_FCVT_LU_D 0xfff0007f #define MATCH_FMV_X_D 0xe2000053 #define MASK_FMV_X_D 0xfff0707f #define MATCH_FCLASS_D 0xe2001053 #define MASK_FCLASS_D 0xfff0707f #define MATCH_FCVT_W_Q 0xc6000053 #define MASK_FCVT_W_Q 0xfff0007f #define MATCH_FCVT_WU_Q 0xc6100053 #define MASK_FCVT_WU_Q 0xfff0007f #define MATCH_FCVT_L_Q 0xc6200053 #define MASK_FCVT_L_Q 0xfff0007f #define MATCH_FCVT_LU_Q 0xc6300053 #define MASK_FCVT_LU_Q 0xfff0007f #define MATCH_FMV_X_Q 0xe6000053 #define MASK_FMV_X_Q 0xfff0707f #define MATCH_FCLASS_Q 0xe6001053 #define MASK_FCLASS_Q 0xfff0707f #define MATCH_FCVT_S_W 0xd0000053 #define MASK_FCVT_S_W 0xfff0007f #define MATCH_FCVT_S_WU 0xd0100053 #define MASK_FCVT_S_WU 0xfff0007f #define MATCH_FCVT_S_L 0xd0200053 #define MASK_FCVT_S_L 0xfff0007f #define MATCH_FCVT_S_LU 0xd0300053 #define MASK_FCVT_S_LU 0xfff0007f #define MATCH_FMV_S_X 0xf0000053 #define MASK_FMV_S_X 0xfff0707f #define MATCH_FCVT_D_W 0xd2000053 #define MASK_FCVT_D_W 0xfff0007f #define MATCH_FCVT_D_WU 0xd2100053 #define MASK_FCVT_D_WU 0xfff0007f #define MATCH_FCVT_D_L 0xd2200053 #define MASK_FCVT_D_L 0xfff0007f #define MATCH_FCVT_D_LU 0xd2300053 #define MASK_FCVT_D_LU 0xfff0007f #define MATCH_FMV_D_X 0xf2000053 #define MASK_FMV_D_X 0xfff0707f #define MATCH_FCVT_Q_W 0xd6000053 #define MASK_FCVT_Q_W 0xfff0007f #define MATCH_FCVT_Q_WU 0xd6100053 #define MASK_FCVT_Q_WU 0xfff0007f #define MATCH_FCVT_Q_L 0xd6200053 #define MASK_FCVT_Q_L 0xfff0007f #define MATCH_FCVT_Q_LU 0xd6300053 #define MASK_FCVT_Q_LU 0xfff0007f #define MATCH_FMV_Q_X 0xf6000053 #define MASK_FMV_Q_X 0xfff0707f #define MATCH_FLW 0x2007 #define MASK_FLW 0x707f #define MATCH_FLD 0x3007 #define MASK_FLD 0x707f #define MATCH_FLQ 0x4007 #define MASK_FLQ 0x707f #define MATCH_FSW 0x2027 #define MASK_FSW 0x707f #define MATCH_FSD 0x3027 #define MASK_FSD 0x707f #define MATCH_FSQ 0x4027 #define MASK_FSQ 0x707f #define MATCH_FMADD_S 0x43 #define MASK_FMADD_S 0x600007f #define MATCH_FMSUB_S 0x47 #define MASK_FMSUB_S 0x600007f #define MATCH_FNMSUB_S 0x4b #define MASK_FNMSUB_S 0x600007f #define MATCH_FNMADD_S 0x4f #define MASK_FNMADD_S 0x600007f #define MATCH_FMADD_D 0x2000043 #define MASK_FMADD_D 0x600007f #define MATCH_FMSUB_D 0x2000047 #define MASK_FMSUB_D 0x600007f #define MATCH_FNMSUB_D 0x200004b #define MASK_FNMSUB_D 0x600007f #define MATCH_FNMADD_D 0x200004f #define MASK_FNMADD_D 0x600007f #define MATCH_FMADD_Q 0x6000043 #define MASK_FMADD_Q 0x600007f #define MATCH_FMSUB_Q 0x6000047 #define MASK_FMSUB_Q 0x600007f #define MATCH_FNMSUB_Q 0x600004b #define MASK_FNMSUB_Q 0x600007f #define MATCH_FNMADD_Q 0x600004f #define MASK_FNMADD_Q 0x600007f #define MATCH_C_NOP 0x1 #define MASK_C_NOP 0xffff #define MATCH_C_ADDI16SP 0x6101 #define MASK_C_ADDI16SP 0xef83 #define MATCH_C_JR 0x8002 #define MASK_C_JR 0xf07f #define MATCH_C_JALR 0x9002 #define MASK_C_JALR 0xf07f #define MATCH_C_EBREAK 0x9002 #define MASK_C_EBREAK 0xffff #define MATCH_C_LD 0x6000 #define MASK_C_LD 0xe003 #define MATCH_C_SD 0xe000 #define MASK_C_SD 0xe003 #define MATCH_C_ADDIW 0x2001 #define MASK_C_ADDIW 0xe003 #define MATCH_C_LDSP 0x6002 #define MASK_C_LDSP 0xe003 #define MATCH_C_SDSP 0xe002 #define MASK_C_SDSP 0xe003 #define MATCH_C_ADDI4SPN 0x0 #define MASK_C_ADDI4SPN 0xe003 #define MATCH_C_FLD 0x2000 #define MASK_C_FLD 0xe003 #define MATCH_C_LW 0x4000 #define MASK_C_LW 0xe003 #define MATCH_C_FLW 0x6000 #define MASK_C_FLW 0xe003 #define MATCH_C_FSD 0xa000 #define MASK_C_FSD 0xe003 #define MATCH_C_SW 0xc000 #define MASK_C_SW 0xe003 #define MATCH_C_FSW 0xe000 #define MASK_C_FSW 0xe003 #define MATCH_C_ADDI 0x1 #define MASK_C_ADDI 0xe003 #define MATCH_C_JAL 0x2001 #define MASK_C_JAL 0xe003 #define MATCH_C_LI 0x4001 #define MASK_C_LI 0xe003 #define MATCH_C_LUI 0x6001 #define MASK_C_LUI 0xe003 #define MATCH_C_SRLI 0x8001 #define MASK_C_SRLI 0xec03 #define MATCH_C_SRAI 0x8401 #define MASK_C_SRAI 0xec03 #define MATCH_C_ANDI 0x8801 #define MASK_C_ANDI 0xec03 #define MATCH_C_SUB 0x8c01 #define MASK_C_SUB 0xfc63 #define MATCH_C_XOR 0x8c21 #define MASK_C_XOR 0xfc63 #define MATCH_C_OR 0x8c41 #define MASK_C_OR 0xfc63 #define MATCH_C_AND 0x8c61 #define MASK_C_AND 0xfc63 #define MATCH_C_SUBW 0x9c01 #define MASK_C_SUBW 0xfc63 #define MATCH_C_ADDW 0x9c21 #define MASK_C_ADDW 0xfc63 #define MATCH_C_J 0xa001 #define MASK_C_J 0xe003 #define MATCH_C_BEQZ 0xc001 #define MASK_C_BEQZ 0xe003 #define MATCH_C_BNEZ 0xe001 #define MASK_C_BNEZ 0xe003 #define MATCH_C_SLLI 0x2 #define MASK_C_SLLI 0xe003 #define MATCH_C_FLDSP 0x2002 #define MASK_C_FLDSP 0xe003 #define MATCH_C_LWSP 0x4002 #define MASK_C_LWSP 0xe003 #define MATCH_C_FLWSP 0x6002 #define MASK_C_FLWSP 0xe003 #define MATCH_C_MV 0x8002 #define MASK_C_MV 0xf003 #define MATCH_C_ADD 0x9002 #define MASK_C_ADD 0xf003 #define MATCH_C_FSDSP 0xa002 #define MASK_C_FSDSP 0xe003 #define MATCH_C_SWSP 0xc002 #define MASK_C_SWSP 0xe003 #define MATCH_C_FSWSP 0xe002 #define MASK_C_FSWSP 0xe003 #define MATCH_CUSTOM0 0xb #define MASK_CUSTOM0 0x707f #define MATCH_CUSTOM0_RS1 0x200b #define MASK_CUSTOM0_RS1 0x707f #define MATCH_CUSTOM0_RS1_RS2 0x300b #define MASK_CUSTOM0_RS1_RS2 0x707f #define MATCH_CUSTOM0_RD 0x400b #define MASK_CUSTOM0_RD 0x707f #define MATCH_CUSTOM0_RD_RS1 0x600b #define MASK_CUSTOM0_RD_RS1 0x707f #define MATCH_CUSTOM0_RD_RS1_RS2 0x700b #define MASK_CUSTOM0_RD_RS1_RS2 0x707f #define MATCH_CUSTOM1 0x2b #define MASK_CUSTOM1 0x707f #define MATCH_CUSTOM1_RS1 0x202b #define MASK_CUSTOM1_RS1 0x707f #define MATCH_CUSTOM1_RS1_RS2 0x302b #define MASK_CUSTOM1_RS1_RS2 0x707f #define MATCH_CUSTOM1_RD 0x402b #define MASK_CUSTOM1_RD 0x707f #define MATCH_CUSTOM1_RD_RS1 0x602b #define MASK_CUSTOM1_RD_RS1 0x707f #define MATCH_CUSTOM1_RD_RS1_RS2 0x702b #define MASK_CUSTOM1_RD_RS1_RS2 0x707f #define MATCH_CUSTOM2 0x5b #define MASK_CUSTOM2 0x707f #define MATCH_CUSTOM2_RS1 0x205b #define MASK_CUSTOM2_RS1 0x707f #define MATCH_CUSTOM2_RS1_RS2 0x305b #define MASK_CUSTOM2_RS1_RS2 0x707f #define MATCH_CUSTOM2_RD 0x405b #define MASK_CUSTOM2_RD 0x707f #define MATCH_CUSTOM2_RD_RS1 0x605b #define MASK_CUSTOM2_RD_RS1 0x707f #define MATCH_CUSTOM2_RD_RS1_RS2 0x705b #define MASK_CUSTOM2_RD_RS1_RS2 0x707f #define MATCH_CUSTOM3 0x7b #define MASK_CUSTOM3 0x707f #define MATCH_CUSTOM3_RS1 0x207b #define MASK_CUSTOM3_RS1 0x707f #define MATCH_CUSTOM3_RS1_RS2 0x307b #define MASK_CUSTOM3_RS1_RS2 0x707f #define MATCH_CUSTOM3_RD 0x407b #define MASK_CUSTOM3_RD 0x707f #define MATCH_CUSTOM3_RD_RS1 0x607b #define MASK_CUSTOM3_RD_RS1 0x707f #define MATCH_CUSTOM3_RD_RS1_RS2 0x707b #define MASK_CUSTOM3_RD_RS1_RS2 0x707f #define CSR_FFLAGS 0x1 #define CSR_FRM 0x2 #define CSR_FCSR 0x3 #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 #define CSR_INSTRET 0xc02 #define CSR_HPMCOUNTER3 0xc03 #define CSR_HPMCOUNTER4 0xc04 #define CSR_HPMCOUNTER5 0xc05 #define CSR_HPMCOUNTER6 0xc06 #define CSR_HPMCOUNTER7 0xc07 #define CSR_HPMCOUNTER8 0xc08 #define CSR_HPMCOUNTER9 0xc09 #define CSR_HPMCOUNTER10 0xc0a #define CSR_HPMCOUNTER11 0xc0b #define CSR_HPMCOUNTER12 0xc0c #define CSR_HPMCOUNTER13 0xc0d #define CSR_HPMCOUNTER14 0xc0e #define CSR_HPMCOUNTER15 0xc0f #define CSR_HPMCOUNTER16 0xc10 #define CSR_HPMCOUNTER17 0xc11 #define CSR_HPMCOUNTER18 0xc12 #define CSR_HPMCOUNTER19 0xc13 #define CSR_HPMCOUNTER20 0xc14 #define CSR_HPMCOUNTER21 0xc15 #define CSR_HPMCOUNTER22 0xc16 #define CSR_HPMCOUNTER23 0xc17 #define CSR_HPMCOUNTER24 0xc18 #define CSR_HPMCOUNTER25 0xc19 #define CSR_HPMCOUNTER26 0xc1a #define CSR_HPMCOUNTER27 0xc1b #define CSR_HPMCOUNTER28 0xc1c #define CSR_HPMCOUNTER29 0xc1d #define CSR_HPMCOUNTER30 0xc1e #define CSR_HPMCOUNTER31 0xc1f #define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 #define CSR_SBADADDR 0x143 #define CSR_SIP 0x144 #define CSR_SPTBR 0x180 #define CSR_MSTATUS 0x300 #define CSR_MISA 0x301 #define CSR_MEDELEG 0x302 #define CSR_MIDELEG 0x303 #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 #define CSR_MCOUNTEREN 0x306 #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 #define CSR_MBADADDR 0x343 #define CSR_MIP 0x344 #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 #define CSR_PMPCFG2 0x3a2 #define CSR_PMPCFG3 0x3a3 #define CSR_PMPADDR0 0x3b0 #define CSR_PMPADDR1 0x3b1 #define CSR_PMPADDR2 0x3b2 #define CSR_PMPADDR3 0x3b3 #define CSR_PMPADDR4 0x3b4 #define CSR_PMPADDR5 0x3b5 #define CSR_PMPADDR6 0x3b6 #define CSR_PMPADDR7 0x3b7 #define CSR_PMPADDR8 0x3b8 #define CSR_PMPADDR9 0x3b9 #define CSR_PMPADDR10 0x3ba #define CSR_PMPADDR11 0x3bb #define CSR_PMPADDR12 0x3bc #define CSR_PMPADDR13 0x3bd #define CSR_PMPADDR14 0x3be #define CSR_PMPADDR15 0x3bf #define CSR_TSELECT 0x7a0 #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 #define CSR_TDATA3 0x7a3 #define CSR_DCSR 0x7b0 #define CSR_DPC 0x7b1 #define CSR_DSCRATCH 0x7b2 #define CSR_MCYCLE 0xb00 #define CSR_MINSTRET 0xb02 #define CSR_MHPMCOUNTER3 0xb03 #define CSR_MHPMCOUNTER4 0xb04 #define CSR_MHPMCOUNTER5 0xb05 #define CSR_MHPMCOUNTER6 0xb06 #define CSR_MHPMCOUNTER7 0xb07 #define CSR_MHPMCOUNTER8 0xb08 #define CSR_MHPMCOUNTER9 0xb09 #define CSR_MHPMCOUNTER10 0xb0a #define CSR_MHPMCOUNTER11 0xb0b #define CSR_MHPMCOUNTER12 0xb0c #define CSR_MHPMCOUNTER13 0xb0d #define CSR_MHPMCOUNTER14 0xb0e #define CSR_MHPMCOUNTER15 0xb0f #define CSR_MHPMCOUNTER16 0xb10 #define CSR_MHPMCOUNTER17 0xb11 #define CSR_MHPMCOUNTER18 0xb12 #define CSR_MHPMCOUNTER19 0xb13 #define CSR_MHPMCOUNTER20 0xb14 #define CSR_MHPMCOUNTER21 0xb15 #define CSR_MHPMCOUNTER22 0xb16 #define CSR_MHPMCOUNTER23 0xb17 #define CSR_MHPMCOUNTER24 0xb18 #define CSR_MHPMCOUNTER25 0xb19 #define CSR_MHPMCOUNTER26 0xb1a #define CSR_MHPMCOUNTER27 0xb1b #define CSR_MHPMCOUNTER28 0xb1c #define CSR_MHPMCOUNTER29 0xb1d #define CSR_MHPMCOUNTER30 0xb1e #define CSR_MHPMCOUNTER31 0xb1f #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 #define CSR_MHPMEVENT6 0x326 #define CSR_MHPMEVENT7 0x327 #define CSR_MHPMEVENT8 0x328 #define CSR_MHPMEVENT9 0x329 #define CSR_MHPMEVENT10 0x32a #define CSR_MHPMEVENT11 0x32b #define CSR_MHPMEVENT12 0x32c #define CSR_MHPMEVENT13 0x32d #define CSR_MHPMEVENT14 0x32e #define CSR_MHPMEVENT15 0x32f #define CSR_MHPMEVENT16 0x330 #define CSR_MHPMEVENT17 0x331 #define CSR_MHPMEVENT18 0x332 #define CSR_MHPMEVENT19 0x333 #define CSR_MHPMEVENT20 0x334 #define CSR_MHPMEVENT21 0x335 #define CSR_MHPMEVENT22 0x336 #define CSR_MHPMEVENT23 0x337 #define CSR_MHPMEVENT24 0x338 #define CSR_MHPMEVENT25 0x339 #define CSR_MHPMEVENT26 0x33a #define CSR_MHPMEVENT27 0x33b #define CSR_MHPMEVENT28 0x33c #define CSR_MHPMEVENT29 0x33d #define CSR_MHPMEVENT30 0x33e #define CSR_MHPMEVENT31 0x33f #define CSR_MVENDORID 0xf11 #define CSR_MARCHID 0xf12 #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 #define CSR_CYCLEH 0xc80 #define CSR_TIMEH 0xc81 #define CSR_INSTRETH 0xc82 #define CSR_HPMCOUNTER3H 0xc83 #define CSR_HPMCOUNTER4H 0xc84 #define CSR_HPMCOUNTER5H 0xc85 #define CSR_HPMCOUNTER6H 0xc86 #define CSR_HPMCOUNTER7H 0xc87 #define CSR_HPMCOUNTER8H 0xc88 #define CSR_HPMCOUNTER9H 0xc89 #define CSR_HPMCOUNTER10H 0xc8a #define CSR_HPMCOUNTER11H 0xc8b #define CSR_HPMCOUNTER12H 0xc8c #define CSR_HPMCOUNTER13H 0xc8d #define CSR_HPMCOUNTER14H 0xc8e #define CSR_HPMCOUNTER15H 0xc8f #define CSR_HPMCOUNTER16H 0xc90 #define CSR_HPMCOUNTER17H 0xc91 #define CSR_HPMCOUNTER18H 0xc92 #define CSR_HPMCOUNTER19H 0xc93 #define CSR_HPMCOUNTER20H 0xc94 #define CSR_HPMCOUNTER21H 0xc95 #define CSR_HPMCOUNTER22H 0xc96 #define CSR_HPMCOUNTER23H 0xc97 #define CSR_HPMCOUNTER24H 0xc98 #define CSR_HPMCOUNTER25H 0xc99 #define CSR_HPMCOUNTER26H 0xc9a #define CSR_HPMCOUNTER27H 0xc9b #define CSR_HPMCOUNTER28H 0xc9c #define CSR_HPMCOUNTER29H 0xc9d #define CSR_HPMCOUNTER30H 0xc9e #define CSR_HPMCOUNTER31H 0xc9f #define CSR_MCYCLEH 0xb80 #define CSR_MINSTRETH 0xb82 #define CSR_MHPMCOUNTER3H 0xb83 #define CSR_MHPMCOUNTER4H 0xb84 #define CSR_MHPMCOUNTER5H 0xb85 #define CSR_MHPMCOUNTER6H 0xb86 #define CSR_MHPMCOUNTER7H 0xb87 #define CSR_MHPMCOUNTER8H 0xb88 #define CSR_MHPMCOUNTER9H 0xb89 #define CSR_MHPMCOUNTER10H 0xb8a #define CSR_MHPMCOUNTER11H 0xb8b #define CSR_MHPMCOUNTER12H 0xb8c #define CSR_MHPMCOUNTER13H 0xb8d #define CSR_MHPMCOUNTER14H 0xb8e #define CSR_MHPMCOUNTER15H 0xb8f #define CSR_MHPMCOUNTER16H 0xb90 #define CSR_MHPMCOUNTER17H 0xb91 #define CSR_MHPMCOUNTER18H 0xb92 #define CSR_MHPMCOUNTER19H 0xb93 #define CSR_MHPMCOUNTER20H 0xb94 #define CSR_MHPMCOUNTER21H 0xb95 #define CSR_MHPMCOUNTER22H 0xb96 #define CSR_MHPMCOUNTER23H 0xb97 #define CSR_MHPMCOUNTER24H 0xb98 #define CSR_MHPMCOUNTER25H 0xb99 #define CSR_MHPMCOUNTER26H 0xb9a #define CSR_MHPMCOUNTER27H 0xb9b #define CSR_MHPMCOUNTER28H 0xb9c #define CSR_MHPMCOUNTER29H 0xb9d #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f #define CAUSE_MISALIGNED_FETCH 0x0 #define CAUSE_FETCH_ACCESS 0x1 #define CAUSE_ILLEGAL_INSTRUCTION 0x2 #define CAUSE_BREAKPOINT 0x3 #define CAUSE_MISALIGNED_LOAD 0x4 #define CAUSE_LOAD_ACCESS 0x5 #define CAUSE_MISALIGNED_STORE 0x6 #define CAUSE_STORE_ACCESS 0x7 #define CAUSE_USER_ECALL 0x8 #define CAUSE_SUPERVISOR_ECALL 0x9 #define CAUSE_HYPERVISOR_ECALL 0xa #define CAUSE_MACHINE_ECALL 0xb #define CAUSE_FETCH_PAGE_FAULT 0xc #define CAUSE_LOAD_PAGE_FAULT 0xd #define CAUSE_STORE_PAGE_FAULT 0xf #endif #ifdef DECLARE_INSN DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) DECLARE_INSN(add, MATCH_ADD, MASK_ADD) DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) DECLARE_INSN(or, MATCH_OR, MASK_OR) DECLARE_INSN(and, MATCH_AND, MASK_AND) DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) DECLARE_INSN(lb, MATCH_LB, MASK_LB) DECLARE_INSN(lh, MATCH_LH, MASK_LH) DECLARE_INSN(lw, MATCH_LW, MASK_LW) DECLARE_INSN(ld, MATCH_LD, MASK_LD) DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) DECLARE_INSN(sb, MATCH_SB, MASK_SB) DECLARE_INSN(sh, MATCH_SH, MASK_SH) DECLARE_INSN(sw, MATCH_SW, MASK_SW) DECLARE_INSN(sd, MATCH_SD, MASK_SD) DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) DECLARE_INSN(div, MATCH_DIV, MASK_DIV) DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) DECLARE_INSN(rem, MATCH_REM, MASK_REM) DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) DECLARE_INSN(uret, MATCH_URET, MASK_URET) DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) #endif #ifdef DECLARE_CSR DECLARE_CSR(fflags, CSR_FFLAGS) DECLARE_CSR(frm, CSR_FRM) DECLARE_CSR(fcsr, CSR_FCSR) DECLARE_CSR(cycle, CSR_CYCLE) DECLARE_CSR(time, CSR_TIME) DECLARE_CSR(instret, CSR_INSTRET) DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) DECLARE_CSR(sstatus, CSR_SSTATUS) DECLARE_CSR(sie, CSR_SIE) DECLARE_CSR(stvec, CSR_STVEC) DECLARE_CSR(scounteren, CSR_SCOUNTEREN) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(sbadaddr, CSR_SBADADDR) DECLARE_CSR(sip, CSR_SIP) DECLARE_CSR(sptbr, CSR_SPTBR) DECLARE_CSR(mstatus, CSR_MSTATUS) DECLARE_CSR(misa, CSR_MISA) DECLARE_CSR(medeleg, CSR_MEDELEG) DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) DECLARE_CSR(mtvec, CSR_MTVEC) DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) DECLARE_CSR(mscratch, CSR_MSCRATCH) DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) DECLARE_CSR(mbadaddr, CSR_MBADADDR) DECLARE_CSR(mip, CSR_MIP) DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) DECLARE_CSR(tselect, CSR_TSELECT) DECLARE_CSR(tdata1, CSR_TDATA1) DECLARE_CSR(tdata2, CSR_TDATA2) DECLARE_CSR(tdata3, CSR_TDATA3) DECLARE_CSR(dcsr, CSR_DCSR) DECLARE_CSR(dpc, CSR_DPC) DECLARE_CSR(dscratch, CSR_DSCRATCH) DECLARE_CSR(mcycle, CSR_MCYCLE) DECLARE_CSR(minstret, CSR_MINSTRET) DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) DECLARE_CSR(mvendorid, CSR_MVENDORID) DECLARE_CSR(marchid, CSR_MARCHID) DECLARE_CSR(mimpid, CSR_MIMPID) DECLARE_CSR(mhartid, CSR_MHARTID) DECLARE_CSR(cycleh, CSR_CYCLEH) DECLARE_CSR(timeh, CSR_TIMEH) DECLARE_CSR(instreth, CSR_INSTRETH) DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) DECLARE_CSR(mcycleh, CSR_MCYCLEH) DECLARE_CSR(minstreth, CSR_MINSTRETH) DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) #endif #ifdef DECLARE_CAUSE DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) #endif mss_assert.h000066400000000000000000000015771432224323300364220ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ #ifndef HAL_ASSERT_HEADER #define HAL_ASSERT_HEADER #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * ASSERT() implementation. ******************************************************************************/ /* Disable assertions if we do not recognize the compiler. */ #if defined ( __GNUC__ ) #if defined(NDEBUG) #define ASSERT(CHECK) #else #define ASSERT(CHECK)\ do { \ if (!(CHECK)) \ { \ __asm volatile ("ebreak"); \ }\ } while(0); #endif /* NDEBUG check */ #endif /* compiler check */ #ifdef __cplusplus } #endif #endif /* HAL_ASSERT_HEADER */ mss_axiswitch.c000066400000000000000000000217051432224323300371120ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_axiswitch.c * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS AXI switch configuration * */ #include #include #include "mpfs_hal/mss_hal.h" #ifdef __cplusplus extern "C" { #endif /*Returns the value of AXI_HW_CFG_REG register*/ uint32_t MSS_AXISW_get_hwcfg(void) { return (AXISW->HWCFG); } /*Returns the value of AXI_VERSION_ID_REG register*/ uint32_t MSS_AXISW_get_vid(void) { return (AXISW->VID); } /*Performs write operation on the AXI SWITCH APB interface, * Parameters: * master_port_num = AXI Master Port number. See Enum mss_axisw_mport_t above. Note: QoS values are programmable through registers only for AXI3 configurations. We have AXI4 so the QoS value programming should not be attempted. IF you try to write/read QoS value you will get return value =1 (AXI_ERR_BIT) Burstiness peak rate and transaction rate can be configured using other APIs. data: QoS value to be programmed return value: As received form AXI_ERR_BIT in CMD register. * */ uint32_t MSS_AXISW_write_qos_val(mss_axisw_mport_t master_port_num, uint32_t data) { while(AXISW->CMD & AXISW_CMD_EN_MASK); /*make sure previous command completed*/ AXISW->DATA = data & AXISW_DATA_QOSVAL_MASK; /*only valid values of bits[3:0]*/ AXISW->CMD = (AXISW_CMD_RW_MASK | (master_port_num << AXISW_CMD_RWCHAN) | MSS_AXISW_QOS_VAL | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); /*Wait for command to complete*/ return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } /*Performs read operation on the AXI SWITCH APB interface, * Parameters: * master_port_num = AXI Master Port number. See Enum mss_axisw_mport_t above. * * Note: QoS values are programmable through registers only for AXI3 configurations. We have AXI4 so the QoS value programming should not be attempted. IF you try to write/read QoS value you will get return value =1 (AXI_ERR_BIT) * * returns the data returned by AXI SWITCH read operation for QoS command * * return value: As received form AXI_ERR_BIT in CMD register. */ uint32_t MSS_AXISW_read_qos_val(mss_axisw_mport_t master_port_num, uint32_t* rd_data) { while(AXISW->CMD & AXISW_CMD_EN_MASK); AXISW->CMD &= ~(AXISW_CMD_RW_MASK); /*Clear read/write bit*/ AXISW->CMD = ((master_port_num << AXISW_CMD_RWCHAN) | (MSS_AXISW_QOS_VAL) | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); *rd_data = AXISW->DATA & AXISW_DATA_QOSVAL_MASK; return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } /* Programs the peak rate and transaction rate value for the given master port read/write address channel NOTE: Peak rate and transaction rate are programmed simultaneously in one command. So we must make sure that both desired valid values must be provided. * return value: As received form AXI_ERR_BIT in CMD register. */ uint32_t MSS_AXISW_write_rate(mss_axisw_mport_t master_port_num, mss_axisw_rate_t peak_rate, mss_axisw_rate_t xct_rate) { while(AXISW->CMD & AXISW_CMD_EN_MASK); /*make sure previous command completed*/ AXISW->DATA = ((peak_rate) << AXISW_DATA_PEAKRT) | ((xct_rate) << AXISW_DATA_XCTRT) ; AXISW->CMD = (AXISW_CMD_RW_MASK | (master_port_num << AXISW_CMD_RWCHAN) | (MSS_AXISW_PEAKRT_XCTRT) | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); /*Wait for command to complete*/ return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } /* Reads the peak rate and transaction rate value for the given master port read/write address channel peak_rate: returns the value of peak rate xct_rate: returns the value of transaction rate return value: As received form AXI_ERR_BIT in CMD register. */ uint32_t MSS_AXISW_read_rate(mss_axisw_mport_t master_port_num, mss_axisw_rate_t* peak_rate, mss_axisw_rate_t* xct_rate) { uint32_t temp = 0u; while(AXISW->CMD & AXISW_CMD_EN_MASK); AXISW->CMD &= ~(AXISW_CMD_RW_MASK); /*Clear read/write and command EN bit*/ AXISW->CMD = ((master_port_num << AXISW_CMD_RWCHAN) | (MSS_AXISW_PEAKRT_XCTRT) | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); temp = AXISW->DATA; *peak_rate = (temp & AXISW_DATA_PEAKRT_MASK) >> AXISW_DATA_PEAKRT; *xct_rate = (temp & AXISW_DATA_XCTRT_MASK) >> AXISW_DATA_XCTRT; return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } /* Programs the burstiness value for the given master port read/write address channel burstiness_val: burstiness value to be programmed NOTE: Burstiness value formula as mentioned in AXISW document is Burstiness = DataReg[23:16] + 1 regulator_en: QoS regulator Enable 1= enable, 0 = disable * return value: As received form AXI_ERR_BIT in CMD register. */ int32_t MSS_AXISW_write_burstiness(mss_axisw_mport_t master_port_num, uint32_t burstiness_val, uint32_t regulator_en) { while(AXISW->CMD & AXISW_CMD_EN_MASK); /*make sure previous command completed*/ /*Write burstiness value and enable burstiness regulator. * Burstiness_val=0 is not valid. Burstiness value formula as mentioned in AXISW document is Burstiness = DataReg[23:16] + 1*/ if(burstiness_val == 0) { return -1; } else { AXISW->DATA = ((burstiness_val - 1u) << AXISW_DATA_BURSTI) | (regulator_en & 0x01); } AXISW->CMD = (AXISW_CMD_RW_MASK | (master_port_num << AXISW_CMD_RWCHAN) | (MSS_AXISW_BURSTINESS_EN) | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); /*Wait for command to complete*/ return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } /* Reads the burstiness value for the given master port read/write address channel burstiness_val: Return parameter bit 23:16 shows the burstiness value. NOTE: Burstiness value formula as mentioned in AXISW document is Burstiness = DataReg[23:16] + 1 * return value: As received form AXI_ERR_BIT in CMD register. */ uint32_t MSS_AXISW_read_burstiness(mss_axisw_mport_t master_port_num, uint32_t* burstiness_val) { while(AXISW->CMD & AXISW_CMD_EN_MASK); AXISW->CMD &= ~(AXISW_CMD_RW_MASK); /*Clear read/write and command EN bit*/ AXISW->CMD = ((master_port_num << AXISW_CMD_RWCHAN) | (MSS_AXISW_BURSTINESS_EN) | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); *burstiness_val = ((AXISW->DATA & AXISW_DATA_BURSTI_MASK) >> AXISW_DATA_BURSTI) + 1u; return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } uint32_t MSS_AXISW_write_slave_ready(mss_axisw_mport_t master_port_num, uint8_t slave_ready_en) { while(AXISW->CMD & AXISW_CMD_EN_MASK); /*make sure previous command completed*/ AXISW->DATA = slave_ready_en & 0x01; /*only valid value of bit0*/ AXISW->CMD = (AXISW_CMD_RW_MASK | (master_port_num << AXISW_CMD_RWCHAN) | MSS_AXISW_SLV_RDY | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); /*Wait for command to complete*/ return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } /*Performs read operation on the AXI SWITCH APB interface, * Parameters: * master_port_num = AXI Master Port number. See Enum mss_axisw_mport_t above. * * * slave_ready_en: returns the data returned by AXI SWITCH read operation for slave ready command * return value: As received form AXI_ERR_BIT in CMD register. * */ uint32_t MSS_AXISW_read_slave_ready(mss_axisw_mport_t master_port_num, uint8_t* slave_ready_en) { while(AXISW->CMD & AXISW_CMD_EN_MASK); AXISW->CMD &= ~(AXISW_CMD_RW_MASK); /*Clear read/write bit*/ AXISW->CMD = ((master_port_num << AXISW_CMD_RWCHAN) | (MSS_AXISW_SLV_RDY) | AXISW_CMD_EN_MASK); while(AXISW->CMD & AXISW_CMD_EN_MASK); *slave_ready_en = AXISW->DATA & 0x01; return ((AXISW->CMD & AXISW_CMD_ERR_MASK) >> AXISW_CMD_ERR); /*return error bit value*/ } #ifdef __cplusplus } #endif mss_axiswitch.h000066400000000000000000000137141432224323300371200ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*=========================================================================*//** *//*=========================================================================*/ #ifndef __MSS_AXISW_H_ #define __MSS_AXISW_H_ 1 #include #include #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** */ typedef enum { MSS_AXISW_FIC0_RD_CHAN = 0x000, MSS_AXISW_FIC0_WR_CHAN, MSS_AXISW_FIC1_RD_CHAN, MSS_AXISW_FIC1_WR_CHAN, MSS_AXISW_FIC2_RD_CHAN, MSS_AXISW_FIC2_WR_CHAN, MSS_AXISW_ATHENA_RD_CHAN, MSS_AXISW_ATHENA_WR_CHAN, MSS_AXISW_GEM0_RD_CHAN, MSS_AXISW_GEM0_WR_CHAN, MSS_AXISW_GEM1_RD_CHAN, MSS_AXISW_GEM1_WR_CHAN, MSS_AXISW_MMC_RD_CHAN, MSS_AXISW_MMC_WR_CHAN, MSS_AXISW_USB_RD_CHAN, MSS_AXISW_USB_WR_CHAN, MSS_AXISW_SCB_RD_CHAN, MSS_AXISW_SCB_WR_CHAN, MSS_AXISW_CPLEX_D0_RD_CHAN, MSS_AXISW_CPLEX_D0_WR_CHAN, MSS_AXISW_CPLEX_D1_RD_CHAN, MSS_AXISW_CPLEX_D1_WR_CHAN, MSS_AXISW_CPLEX_F0_RD_CHAN, MSS_AXISW_CPLEX_F0_WR_CHAN, MSS_AXISW_CPLEX_F1_RD_CHAN, MSS_AXISW_CPLEX_F1_WR_CHAN, MSS_AXISW_CPLEX_NC_RD_CHAN, MSS_AXISW_CPLEX_NC_WR_CHAN, MSS_AXISW_TRACE_RD_CHAN, MSS_AXISW_TRACE_WR_CHAN, } mss_axisw_mport_t; typedef enum { MSS_AXISW_BURSTINESS_EN = 0x00, MSS_AXISW_PEAKRT_XCTRT, MSS_AXISW_QOS_VAL, MSS_AXISW_SLV_RDY, } mss_axisw_cmd_t; typedef enum { MSS_AXISW_MASTER_RD_CHAN = 0x00, MSS_AXISW_MASTER_WR_CHAN = 0x01, } mss_axisw_mchan_t; /* The Peak rate and transaction rates are encoded as follows. 1000_0000_0000 1/2 0100_0000_0000 1/4 0010_0000_0000 1/8 0001_0000_0000 1/16 0000_1000_0000 1/32 0000_0100_0000 1/64 0000_0010_0000 1/128 0000_0001_0000 1/256 0000_0000_1000 1/512 0000_0000_0100 1/1024 0000_0000_0010 1/2048 0000_0000_0001 1/4096 Programming the transaction rate as 0000_0000_0000 disables token generation and traffic is not regulated based on the tokens. Programming the peak rate as 0000_0000_0000 disables the peak rate control logic and traffic is not regulated by the peak rate logic. */ typedef enum { MSS_AXISW_TXNRATE_BY4096 = 0x001, MSS_AXISW_TXNRATE_BY2098 = 0x002, MSS_AXISW_TXNRATE_BY1024 = 0x004, MSS_AXISW_TXNRATE_BY512 = 0x008, MSS_AXISW_TXNRATE_BY256 = 0x010, MSS_AXISW_TXNRATE_BY128 = 0x020, MSS_AXISW_TXNRATE_BY64 = 0x040, MSS_AXISW_TXNRATE_BY32 = 0x080, MSS_AXISW_TXNRATE_BY16 = 0x100, MSS_AXISW_TXNRATE_BY8 = 0x200, MSS_AXISW_TXNRATE_BY4 = 0x400, MSS_AXISW_TXNRATE_BY2 = 0x800, MSS_AXISW_TXNRATE_DISABLE = 0x0, } mss_axisw_rate_t; #define AXISW_CMD_EN 31U #define AXISW_CMD_EN_MASK (uint32_t)(0x01U << AXISW_CMD_EN) #define AXISW_CMD_RW 30U #define AXISW_CMD_RW_MASK (uint32_t)(0x01U << AXISW_CMD_RW) #define AXISW_CMD_SWRST 29U #define AXISW_CMD_SWRST_MASK (uint32_t)(0x01U << AXISW_CMD_SWRST) #define AXISW_CMD_ERR 28U #define AXISW_CMD_ERR_MASK (uint32_t)(0x01U << AXISW_CMD_ERR) //#define AXISW_CMD_MPORT 8U //#define AXISW_CMD_MPORT_MASK (0x0F << AXISW_CMD_MPORT) #define AXISW_CMD_RWCHAN 7U #define AXISW_CMD_RWCHAN_MASK (uint32_t)(0x1F << AXISW_CMD_RWCHAN) #define AXISW_CMD_CMD 0U #define AXISW_CMD_CMD_MASK (0x01U << AXISW_CMD_CMD) #define AXISW_DATA_PEAKRT 20U #define AXISW_DATA_PEAKRT_MASK (0xFFFU << AXISW_DATA_PEAKRT) #define AXISW_DATA_XCTRT 4U #define AXISW_DATA_XCTRT_MASK (0xFFFU << AXISW_DATA_XCTRT) #define AXISW_DATA_BURSTI 16U #define AXISW_DATA_BURSTI_MASK (0xFFU << AXISW_DATA_BURSTI) #define AXISW_DATA_QOSVAL 0U #define AXISW_DATA_QOSVAL_MASK (0xFU << AXISW_DATA_QOSVAL) typedef struct { __IO uint32_t VID; __IO uint32_t HWCFG; __IO uint32_t CMD; __IO uint32_t DATA; } AXISW_TypeDef; #define AXISW ((AXISW_TypeDef*)0x20004000UL) uint32_t MSS_AXISW_get_hwcfg(void); uint32_t MSS_AXISW_get_vid(void); uint32_t MSS_AXISW_write_qos_val(mss_axisw_mport_t master_port_num, uint32_t data); uint32_t MSS_AXISW_read_qos_val(mss_axisw_mport_t master_port_num, uint32_t* rd_data); uint32_t MSS_AXISW_write_rate(mss_axisw_mport_t master_port_num, mss_axisw_rate_t peak_rate, mss_axisw_rate_t xct_rate); uint32_t MSS_AXISW_read_rate(mss_axisw_mport_t master_port_num, mss_axisw_rate_t* peak_rate, mss_axisw_rate_t* xct_rate); int32_t MSS_AXISW_write_burstiness(mss_axisw_mport_t master_port_num, uint32_t burstiness_val, uint32_t regulator_en); uint32_t MSS_AXISW_read_burstiness(mss_axisw_mport_t master_port_num, uint32_t* burstiness_val); uint32_t MSS_AXISW_write_slave_ready(mss_axisw_mport_t master_port_num, uint8_t slave_ready_en); uint32_t MSS_AXISW_read_slave_ready(mss_axisw_mport_t master_port_num, uint8_t* slave_ready_en); #ifdef __cplusplus } #endif #endif /* __MSS_AXISW_H_ */ mss_clint.c000066400000000000000000000070171432224323300362200ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_clint.c * @author Microchip-FPGA Embedded Systems Solutions * @brief CLINT access data structures and functions. * */ #include #include "mpfs_hal/mss_hal.h" static uint64_t g_systick_increment[5] = {0ULL,0ULL,0ULL,0ULL,0ULL}; /** * call once at startup * @return */ void reset_mtime(void) { #if ROLLOVER_TEST CLINT->MTIME = 0xFFFFFFFFFFFFF000ULL; #else CLINT->MTIME = 0ULL; #endif } /** * readmtime * @return mtime */ uint64_t readmtime(void) { return (CLINT->MTIME); } /** * Configure system tick * @return SUCCESS or FAIL */ uint32_t SysTick_Config(void) { const uint32_t tick_rate[5] = {HART0_TICK_RATE_MS, HART1_TICK_RATE_MS ,HART2_TICK_RATE_MS ,HART3_TICK_RATE_MS ,HART4_TICK_RATE_MS}; volatile uint32_t ret_val = ERROR; uint64_t mhart_id = read_csr(mhartid); /* * We are assuming the tick rate is in milli-seconds * * convert RTC frequency into milliseconds and multiple by the tick rate * */ g_systick_increment[mhart_id] = ((LIBERO_SETTING_MSS_RTC_TOGGLE_CLK/1000U) * tick_rate[mhart_id]); if (g_systick_increment[mhart_id] > 0ULL) { CLINT->MTIMECMP[mhart_id] = CLINT->MTIME + g_systick_increment[mhart_id]; set_csr(mie, MIP_MTIP); /* mie Register - Machine Timer Interrupt Enable */ __enable_irq(); ret_val = SUCCESS; } return (ret_val); } /** * Disable system tick interrupt */ void disable_systick(void) { clear_csr(mie, MIP_MTIP); /* mie Register - Machine Timer Interrupt Enable */ return; } /*------------------------------------------------------------------------------ * RISC-V interrupt handler for machine timer interrupts. */ void handle_m_timer_interrupt(void) { volatile uint64_t hart_id = read_csr(mhartid); volatile uint32_t error_loop; clear_csr(mie, MIP_MTIP); switch(hart_id) { case 0U: E51_sysTick_IRQHandler(); break; case 1U: U54_1_sysTick_IRQHandler(); break; case 2U: U54_2_sysTick_IRQHandler(); break; case 3U: U54_3_sysTick_IRQHandler(); break; case 4U: U54_4_sysTick_IRQHandler(); break; default: while (hart_id != 0U) { error_loop++; } break; } CLINT->MTIMECMP[read_csr(mhartid)] = CLINT->MTIME + g_systick_increment[hart_id]; set_csr(mie, MIP_MTIP); } /** * */ void handle_m_soft_interrupt(void) { volatile uint64_t hart_id = read_csr(mhartid); volatile uint32_t error_loop; switch(hart_id) { case 0U: E51_software_IRQHandler(); break; case 1U: U54_1_software_IRQHandler(); break; case 2U: U54_2_software_IRQHandler(); break; case 3U: U54_3_software_IRQHandler(); break; case 4U: U54_4_software_IRQHandler(); break; default: while (hart_id != 0U) { error_loop++; } break; } /*Clear software interrupt*/ clear_soft_interrupt(); } mss_clint.h000066400000000000000000000056711432224323300362310ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_clint.h * @author Microchip-FPGA Embedded Systems Solutions * @brief CLINT access data structures and functions. * */ #ifndef MSS_CLINT_H #define MSS_CLINT_H #include #include "encoding.h" #include "atomic.h" #ifdef __cplusplus extern "C" { #endif #define RTC_PRESCALER 100U #define SUCCESS 0U #define ERROR 1U /*============================================================================== * CLINT: Core Local Interrupter */ typedef struct CLINT_Type_t { volatile uint32_t MSIP[5]; volatile uint32_t reserved1[(0x4000U - 0x14U)/4U]; volatile uint64_t MTIMECMP[5]; /* mtime compare value for each hart. When mtime equals this value, interrupt is generated for particular hart */ volatile uint32_t reserved2[((0xbff8U - 0x4028U)/4U)]; volatile uint64_t MTIME; /* contains the current mtime value */ } CLINT_Type; #define CLINT ((CLINT_Type *)CLINT_BASE) /*============================================================================== * The function raise_soft_interrupt() raises a synchronous software interrupt by * writing into the MSIP register. */ static inline void raise_soft_interrupt(unsigned long hart_id) { /*You need to make sure that the global interrupt is enabled*/ /*Note: set_csr(mie, MIP_MSIP) needs to be set on hart you are setting sw interrupt */ CLINT->MSIP[hart_id] = 0x01U; /*raise soft interrupt for hart(x) where x== hart ID*/ mb(); } /*============================================================================== * The function clear_soft_interrupt() clears a synchronous software interrupt by * clearing the MSIP register. */ static inline void clear_soft_interrupt(void) { volatile uint32_t reg; uint64_t hart_id = read_csr(mhartid); CLINT->MSIP[hart_id] = 0x00U; /*clear soft interrupt for hart0*/ reg = CLINT->MSIP[hart_id]; /* we read back to make sure it has been written before moving on */ /* todo: verify line above guaranteed and best way to achieve result */ (void)reg; /* use reg to avoid compiler warning */ } /* * return mtime */ uint64_t readmtime(void); /** * call once at startup * @return */ void reset_mtime(void); /** * Configure system tick * @return SUCCESS or FAIL */ uint32_t SysTick_Config(void); /** * Disable system tick interrupt */ void disable_systick(void); /*------------------------------------------------------------------------------ * RISC-V interrupt handler for machine timer interrupts. */ void handle_m_timer_interrupt(void); /** * */ void handle_m_soft_interrupt(void); #ifdef __cplusplus } #endif #endif /* MSS_CLINT_H */ mss_h2f.c000066400000000000000000000447351432224323300355760ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_m2f.c * @author Microchip-FPGA Embedded Systems Solutions * @brief M2F access data structures and functions. * */ #include "mss_plic.h" #include "mss_h2f.h" #ifdef __cplusplus extern "C" { #endif #define M2F_MAPPING_INVALID 255U /*============================================================================== * M2F_int_mapping, source to M2F output lines * The internal interrupt are multiplexed to fabric I/O lines. * That is, each line will contain several interrupts. */ const uint8_t M2F_int_mapping[PLIC_U54_4_BUS_ERROR_UNIT_OFFSET]= { \ M2F_MAPPING_INVALID /*INVALID_IRQn = 0*/, \ M2F_MAPPING_INVALID /*L2_METADATA_CORR_IRQn = 1*/, \ M2F_MAPPING_INVALID /*L2_METADAT_UNCORR_IRQn = 2*/, \ M2F_MAPPING_INVALID /*L2_DATA_CORR_IRQn = 3*/, \ M2F_MAPPING_INVALID /*L2_DATA_UNCORR_IRQn = 4*/, \ M2F_MAPPING_INVALID /*DMA_CH0_DONE_IRQn = 5*/, \ M2F_MAPPING_INVALID /*DMA_CH0_ERR_IRQn = 6*/, \ M2F_MAPPING_INVALID /*DMA_CH1_DONE_IRQn = 7*/, \ M2F_MAPPING_INVALID /*DMA_CH1_ERR_IRQn = 8*/, \ M2F_MAPPING_INVALID /*DMA_CH2_DONE_IRQn = 9*/, \ M2F_MAPPING_INVALID /*DMA_CH2_ERR_IRQn = 10*/, \ M2F_MAPPING_INVALID /*DMA_CH3_DONE_IRQn = 11*/, \ M2F_MAPPING_INVALID /*DMA_CH3_ERR_IRQn = 12*/, \ 0x00U /*GPIO0_BIT0_or_GPIO2_BIT0_PLIC_0 = 0 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT1_or_GPIO2_BIT1_PLIC_1 = 1 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT2_or_GPIO2_BIT2_PLIC_2 = 2 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT3_or_GPIO2_BIT3_PLIC_3 = 3 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT4_or_GPIO2_BIT4_PLIC_4 = 4 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT5_or_GPIO2_BIT5_PLIC_5 = 5 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT6_or_GPIO2_BIT6_PLIC_6 = 6 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT7_or_GPIO2_BIT7_PLIC_7 = 7 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT8_or_GPIO2_BIT8_PLIC_8 = 8 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT9_or_GPIO2_BIT9_PLIC_9 = 9 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT10_or_GPIO2_BIT10_PLIC_10 = 10 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT11_or_GPIO2_BIT11_PLIC_11 = 11 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT12_or_GPIO2_BIT12_PLIC_12 = 12 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_BIT14_or_GPIO2_BIT13_PLIC_13 = 13 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14 = 14 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT1_or_GPIO2_BIT15_PLIC_15 = 15 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT2_or_GPIO2_BIT16_PLIC_16 = 16 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT3_or_GPIO2_BIT17_PLIC_17 = 17 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT4_or_GPIO2_BIT18_PLIC_18 = 18 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT5_or_GPIO2_BIT19_PLIC_19 = 19 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT6_or_GPIO2_BIT20_PLIC_20 = 20 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT7_or_GPIO2_BIT21_PLIC_21 = 21 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT8_or_GPIO2_BIT22_PLIC_22 = 22 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT9_or_GPIO2_BIT23_PLIC_23 = 23 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT10_or_GPIO2_BIT24_PLIC_24 = 24 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT11_or_GPIO2_BIT25_PLIC_25 = 25 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT12_or_GPIO2_BIT26_PLIC_26 = 26 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT13_or_GPIO2_BIT27_PLIC_27 = 27 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT14_or_GPIO2_BIT28_PLIC_28 = 28 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT15_or_GPIO2_BIT29_PLIC_29 = 29 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT16_or_GPIO2_BIT30_PLIC_30 = 30 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT17_or_GPIO2_BIT31_PLIC_31 = 31 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT18_PLIC_32 = 32 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT19_PLIC_33 = 33 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT20_PLIC_34 = 34 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT21_PLIC_35 = 35 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT22_PLIC_36 = 36 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_BIT23_PLIC_37 = 37 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO0_NON_DIRECT_PLI =38 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO1_NON_DIRECT_PLIC =39 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x00U /*GPIO2_NON_DIRECT_PLIC =40 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*SPI0_PLIC =41 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*SPI1_PLIC =42 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*CAN0_PLIC =43 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*CAN1_PLIC =44 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x02U /*I2C0_MAIN_PLIC =45 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x02U /*I2C0_ALERT_PLIC =46 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x02U /*I2C0_SUS_PLIC =47 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x02U /*I2C1_MAIN_PLIC =48 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x02U /*I2C1_ALERT_PLIC =49 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x02U /*I2C1_SUS_PLIC =50 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x03U /*MAC0_INT_PLIC =51 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x03U /*MAC0_QUEUE1_PLIC =52 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x03U /*MAC0_QUEUE2_PLIC =53 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x03U /*MAC0_QUEUE3_PLIC =54 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x03U /*MAC0_eMAC_PLIC =55 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x03U /*MAC0_MMSL_PLIC =56 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x04U /*MAC1_int_PLIC =57 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x04U /*MAC1_QUEUE1_PLIC =58 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x04U /*MAC1_QUEUE2_PLIC =59 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x04U /*MAC1_QUEUE3_PLIC =60 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x04U /*MAC1_EMAC_PLIC =61 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x04U /*MAC1_MMSL_PLIC =62 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x09U /*DDRC_TRAIN_PLIC =63 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x07U /*SCB_INTERRUPT_PLIC =64 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x06U /*ECC_ERROR_PLIC =65 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x06U /*ECC_CORRECT_PLIC =66 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0BU /*RTC_WAKEUP_PLIC =67 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0BU /*RTC_MATCH_PLIC =68 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0CU /*TIMER1_PLIC =69 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0CU /*TIMER2_PLIC =70 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0DU /*ENVM_PLIC =71 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0DU /*QSPI_PLIC =72 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0EU /*USB_DMA_PLIC =73 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0EU /*USB_MC_PLIC =74 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0FU /*MMC_main_PLIC =75 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0FU /*MMC_wakeup_PLIC =76 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*MMUART0_PLIC_77 =77 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*MMUART1_PLIC =78 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*MMUART2_PLIC =79 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*MMUART3_PLIC =80 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x01U /*MMUART4_PLIC =81 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0AU /*G5C_DEVRST_PLIC =82 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x08U /*g5c_MESSAGE_PLIC =83 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0BU /*USOC_VC_INTERRUPT_PLIC =84 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0BU /*USOC_SMB_INTERRUPT_PLIC =85 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x06U /*E51_0_MAINTENACE_PLIC =86 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG0_MRVP_PLIC =87 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG1_MRVP_PLIC =88 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG2_MRVP_PLIC =89 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG3_MRVP_PLIC =90 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG4_MRVP_PLIC =91 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG0_TOUT_PLIC =92 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG1_TOUT_PLIC =93 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG2_TOUT_PLIC =94 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG3_TOUT_PLIC =95 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x05U /*WDOG4_TOUT_PLIC =96 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0DU /*G5C_MSS_SPI_PLIC =97 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*VOLT_TEMP_ALARM_PLIC =98 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*ATHENA_COMPLETE_PLIC =99 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*ATHENA_ALARM_PLIC =100 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*ATHENA_BUS_ERROR_PLIC =101 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0BU /*USOC_AXIC_US_PLIC =102 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ 0x0BU /*USOC_AXIC_DS_PLIC =103 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_0_PLIC = 105 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_1_PLIC = 106 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_2_PLIC = 107 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_3_PLIC = 108 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_4_PLIC = 109 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_5_PLIC = 110 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_6_PLIC = 111 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_7_PLIC = 112 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_8_PLIC = 113 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_9_PLIC = 114 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_10_PLIC = 115 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_11_PLIC = 116 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_12_PLIC = 117 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_13_PLIC = 118 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_14_PLIC = 119 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_15_PLIC = 120 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_16_PLIC = 121 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_17_PLIC = 122 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_18_PLIC = 123 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_19_PLIC = 124 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_20_PLIC = 125 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_21_PLIC = 126 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_22_PLIC = 127 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_23_PLIC = 128 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_24_PLIC = 129 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_25_PLIC = 130 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_26_PLIC = 131 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_27_PLIC = 132 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_28_PLIC = 133 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_29_PLIC = 134 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_30_PLIC = 135 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_31_PLIC = 136 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_32_PLIC = 137 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_33_PLIC = 138 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_34_PLIC = 139 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_35_PLIC = 140 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_36_PLIC = 141 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_37_PLIC = 142 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_38_PLIC = 143 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_39_PLIC = 144 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_40_PLIC = 145 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_41_PLIC = 146 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_42_PLIC = 147 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_43_PLIC = 148 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_44_PLIC = 149 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_45_PLIC = 150 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_46_PLIC = 151 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_47_PLIC = 152 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_48_PLIC = 153 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_49_PLIC = 154 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_50_PLIC = 155 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_51_PLIC = 156 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_52_PLIC = 157 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_53_PLIC = 158 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_54_PLIC = 159 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_55_PLIC = 160 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_56_PLIC = 161 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_57_PLIC = 162 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_58_PLIC = 163 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_59_PLIC = 164 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_60_PLIC = 165 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_61_PLIC = 166 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_62_PLIC = 167 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*MSS_INT_F2M_63_PLIC = 168 + OFFSET_TO_MSS_GLOBAL_INTS*/, \ M2F_MAPPING_INVALID /*BUS_ERROR_UNIT_HART_0 = 182*/, \ M2F_MAPPING_INVALID /*BUS_ERROR_UNIT_HART_1 = 183*/, \ M2F_MAPPING_INVALID /*BUS_ERROR_UNIT_HART_2 = 184*/, \ M2F_MAPPING_INVALID /*BUS_ERROR_UNIT_HART_3 = 185*/, \ M2F_MAPPING_INVALID /*BUS_ERROR_UNIT_HART_4 = 186 */ }; /** * get source to fabric signal mapping * @param source_int * @return */ static uint32_t get_corresponding_m2f_output(uint32_t source_int) { uint32_t m2f_line = M2F_int_mapping[source_int]; if(m2f_line < M2F_MAPPING_INVALID) /* if no error */ { return(0x01U << m2f_line); } return(m2f_line); } /** * set M2F controller to reset to defaults- disabled */ void reset_m2f(void) { uint8_t index = 0U; M2F_CONTROLLER->ENABLE = 0U; while(index < 4U) { M2F_CONTROLLER->PLENABLE[index] = 0U; index++; } } /** * enables output which will mirror PLIC input. PLIC mapping given above for reference * @param source_int */ void enable_m2f_int_output(uint32_t source_int) { uint32_t output_signal = get_corresponding_m2f_output(source_int); if(output_signal != M2F_MAPPING_INVALID) { source_int -= OFFSET_TO_MSS_GLOBAL_INTS; /* enable the input */ M2F_CONTROLLER->PLENABLE[source_int/32U] |= (0x01U << (source_int % 32U)); /* enable the output */ M2F_CONTROLLER->ENABLE |= ((output_signal<<16U) | 0x01U); } } /** * enables output which will mirror PLIC input. PLIC mapping given above for reference * @param source_int */ void disable_m2f_int_output(uint32_t source_int) { uint32_t output_signal = get_corresponding_m2f_output(source_int); if(output_signal != M2F_MAPPING_INVALID) { /* enable the input */ M2F_CONTROLLER->PLENABLE[source_int/32U] &= ~(source_int % 32U); /* enable the output */ M2F_CONTROLLER->ENABLE &= ~(((output_signal<<16U))); } } #ifdef __cplusplus } #endif mss_h2f.h000066400000000000000000000053701432224323300355730ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_m2f.h * @author Microchip-FPGA Embedded Systems Solutions * @brief M2F access data structures and functions. * * Definitions and functions associated with host to fabric interrupt controller. * */ #ifndef MSS_M2F_H #define MSS_M2F_H #include "mpfs_hal_config/mss_sw_config.h" #ifdef __cplusplus extern "C" { #endif /* M2F line Group Ored (no of interrupts ored to one output line) 0 GPIO 41 1 MMUART,SPI,CAN 9 2 I2C 6 3 MAC0 6 4 MAC1 6 5 WATCHDOGS 10 6 Maintenance 3 7 SCB 1 8 G5C-Message 1 9 DDRC 1 10 G5C-DEVRST 2 11 RTC/USOC 4 12 TIMER 2 13 ENVM, QSPI 2 14 USB 2 15 MMC/SDIO 2 */ /*============================================================================== * Host to Fabric interrupt controller * * For an interrupt to activate the PENABLE and appropriate HENABLE and PENABLE bits must be set. * * Note. Since Interrupts 127:94 are not used in the system the enable registers are non-write-able and always read as zeros. * */ typedef struct { volatile uint32_t ENABLE; /* bit o: Enables all the M2FINT outputs, bit 31:16 Enables individual M2F outputs */ volatile uint32_t M2FSTATUS; /* 15:0 Read back of the 16-bit M2F Interrupts before the M2F and global enable */ uint32_t filler[2U]; /* fill the gap in the memory map */ volatile uint32_t PLSTATUS[4U]; /* Indicates that the PLINT interrupt is active before the PLINT enable i.e. direct read of the PLINT inputs [31:0] from PLSTATUS[0] direct read of the PLINT inputs [63:32] from PLSTATUS[1] etc */ volatile uint32_t PLENABLE[4U]; /* Enables PLINT interrupts PLENABLE[0] 31:0, PLENABLE[1] 63:32, 95:64, 127:96 */ } M2F_CONTROLLER_Type; #ifndef M2F_BASE_ADDRESS #if (LIBERO_SETTING_APBBUS_CR & (1U<<23U)) #define M2F_BASE_ADDRESS 0x28126000 #else #define M2F_BASE_ADDRESS 0x20126000 #endif #endif #define M2F_CONTROLLER ((M2F_CONTROLLER_Type *)M2F_BASE_ADDRESS) void reset_m2f(void); void enable_m2f_int_output(uint32_t source_int); void disable_m2f_int_output(uint32_t source_int); #ifdef __cplusplus } #endif #endif /* MSS_M2F_H */ mss_hart_ints.h000066400000000000000000000356361432224323300371170ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_hart_ints.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MPFS local interrupt definitions * * Definitions and functions associated with local interrupts for each hart. * */ #ifndef MSS_HART_INTS_H #define MSS_HART_INTS_H #include #ifdef __cplusplus extern "C" { #endif typedef struct BEU_Type_ { volatile uint64_t CAUSE; volatile uint64_t VALUE; volatile uint64_t ENABLE; volatile uint64_t PLIC_INT; volatile uint64_t ACCRUED; volatile uint64_t LOCAL_INT; volatile uint64_t reserved2[((0x1000U/8U) - 0x6U)]; } BEU_Type; typedef struct BEU_Types_ { volatile BEU_Type regs[5]; } BEU_Types; #define MSS_BUS_ERROR_UNIT_H0 0x01700000UL #define MSS_BUS_ERROR_UNIT_H1 0x01701000UL #define MSS_BUS_ERROR_UNIT_H2 0x01702000UL #define MSS_BUS_ERROR_UNIT_H3 0x01703000UL #define MSS_BUS_ERROR_UNIT_H4 0x01704000UL #define BEU ((BEU_Types *)MSS_BUS_ERROR_UNIT_H0) /* * Local Interrupt offsets for the E51 */ #define E51_MAINTENANCE_INT_OFFSET 0 #define E51_USOC_SMB_INTERRUPT_INT_OFFSET 1 #define E51_USOC_VC_INTERRUPT_INT_OFFSET 2 #define E51_G5C_MESSAGE_INT_OFFSET 3 #define E51_G5C_DEVRST_INT_OFFSET 4 #define E51_WDOG4_TOUT_INT_OFFSET 5 #define E51_WDOG3_TOUT_INT_OFFSET 6 #define E51_WDOG2_TOUT_INT_OFFSET 7 #define E51_WDOG1_TOUT_INT_OFFSET 8 #define E51_WDOG0_TOUT_INT_OFFSET 9 #define E51_WDOG0_MVRP_INT_OFFSET 10 #define E51_MMUART0_INT_OFFSET 11 #define E51_ENVM_INT_OFFSET 12 #define E51_ECC_CORRECT_INT_OFFSET 13 #define E51_ECC_ERROR_INT_OFFSET 14 #define E51_scb_INTERRUPT_INT_OFFSET 15 #define E51_F2M_32_INT_OFFSET 16 #define E51_F2M_33_INT_OFFSET 17 #define E51_F2M_34_INT_OFFSET 18 #define E51_F2M_35_INT_OFFSET 19 #define E51_F2M_36_INT_OFFSET 20 #define E51_F2M_37_INT_OFFSET 21 #define E51_F2M_38_INT_OFFSET 22 #define E51_F2M_39_INT_OFFSET 23 #define E51_F2M_40_INT_OFFSET 24 #define E51_F2M_41_INT_OFFSET 25 #define E51_F2M_42_INT_OFFSET 26 #define E51_F2M_43_INT_OFFSET 27 #define E51_F2M_44_INT_OFFSET 28 #define E51_F2M_45_INT_OFFSET 29 #define E51_F2M_46_INT_OFFSET 30 #define E51_F2M_47_INT_OFFSET 31 #define E51_F2M_48_INT_OFFSET 32 #define E51_F2M_49_INT_OFFSET 33 #define E51_F2M_50_INT_OFFSET 34 #define E51_F2M_51_INT_OFFSET 35 #define E51_F2M_52_INT_OFFSET 36 #define E51_F2M_53_INT_OFFSET 37 #define E51_F2M_54_INT_OFFSET 38 #define E51_F2M_55_INT_OFFSET 39 #define E51_F2M_56_INT_OFFSET 40 #define E51_F2M_57_INT_OFFSET 41 #define E51_F2M_58_INT_OFFSET 42 #define E51_F2M_59_INT_OFFSET 43 #define E51_F2M_60_INT_OFFSET 44 #define E51_F2M_61_INT_OFFSET 45 #define E51_F2M_62_INT_OFFSET 46 #define E51_F2M_63_INT_OFFSET 47 #define LOCAL_INT_MAX 47U /* Highest numbered */ #define LOCAL_INT_UNUSED 127U /* Signifies unused interrupt */ /* * Interrupts associated with * MAINTENANCE_INT_OFFSET * This maps to the E51_maintenance_local_IRQHandler(void) handler * * A group of interrupt events are grouped into a single maintenance interrupt * to the E51 CPU. * These interrupts are individually enabled using the following MSS system * register: * SYSREG->MAINTENANCE_INTEN_CR * On receiving this interrupt the E51 should read the following system register * to determine the source of the interrupt * SYSREG->MAINTENANCE_INT_SR * The bit defines associated with the MAINTENANCE_INTEN_CR and * MAINTENANCE_INT_SR registers are listed in the file mss_sysreg.h * see: * MAINTENANCE_INTEN_CR_PLL_MASK (0x01 << 0x0) * MAINTENANCE_INTEN_CR_MPU_MASK (0x01 << 0x1) * MAINTENANCE_INTEN_CR_DECODE_MASK (0x01 << 0x2) * MAINTENANCE_INTEN_CR_LP_STATE_ENTER_MASK (0x01 << 0x3) * MAINTENANCE_INTEN_CR_LP_STATE_EXIT_MASK (0x01 << 0x4) * MAINTENANCE_INTEN_CR_FF_START_MASK (0x01 << 0x5) * MAINTENANCE_INTEN_CR_FF_END_MASK (0x01 << 0x6) * MAINTENANCE_INTEN_CR_FPGA_ON_MASK (0x01 << 0x7) * MAINTENANCE_INTEN_CR_FPGA_OFF_MASK (0x01 << 0x8) * MAINTENANCE_INTEN_CR_SCB_ERROR_MASK (0x01 << 0x9) * MAINTENANCE_INTEN_CR_SCB_FAULT_MASK (0x01 << 0xA) * MAINTENANCE_INTEN_CR_MESH_ERROR_MASK (0x01 << 0xB) * MAINTENANCE_INTEN_CR_IO_BANK_B2_ON_MASK (0x01 << 0xC) * MAINTENANCE_INTEN_CR_IO_BANK_B4_ON_MASK (0x01 << 0xD) * MAINTENANCE_INTEN_CR_IO_BANK_B5_ON_MASK (0x01 << 0xE) * MAINTENANCE_INTEN_CR_IO_BANK_B6_ON_MASK (0x01 << 0xF) * MAINTENANCE_INTEN_CR_IO_BANK_B2_OFF_MASK (0x01 << 0x10) * MAINTENANCE_INTEN_CR_IO_BANK_B4_OFF_MASK (0x01 << 0x11) * MAINTENANCE_INTEN_CR_IO_BANK_B5_OFF_MASK (0x01 << 0x12) * MAINTENANCE_INTEN_CR_IO_BANK_B6_OFF_MASK (0x01 << 0x13) * MAINTENANCE_INTEN_CR_DLL_MASK (0x01 << 0x14) * * The PLL, MPU and DLL maintenance interrupts have their own sub group * registers for enabling and clearing multiple associated events * See the defines for * SYSREG->PLL_STATUS_INTEN_CR * SYSREG->PLL_STATUS_SR * * SYSREG->MPU_VIOLATION_INTEN_CR * SYSREG->MPU_VIOLATION_SR * * SYSREG->DLL_STATUS_CR * SYSREG->DLL_STATUS_SR * */ /* * Interrupt numbers U54's */ /* U0 (first U54) and U1 connected to mac0 */ #define U54_MAC0_INT_INT_OFFSET 8 /* determine source mac using hart ID */ #define U54_MAC0_QUEUE1_INT_OFFSET 7 #define U54_MAC0_QUEUE2_INT_OFFSET 6 #define U54_MAC0_QUEUE3_INT_OFFSET 5 #define U54_MAC0_EMAC_INT_OFFSET 4 #define U54_MAC0_MMSL_INT_OFFSET 3 /* U2 and U3 connected to mac1 */ #define U54_MAC1_INT_INT_OFFSET 8 /* determine source mac using hart ID */ #define U54_MAC1_QUEUE1_INT_OFFSET 7 #define U54_MAC1_QUEUE2_INT_OFFSET 6 #define U54_MAC1_QUEUE3_INT_OFFSET 5 #define U54_MAC1_EMAC_INT_OFFSET 4 #define U54_MAC1_MMSL_INT_OFFSET 3 /* MMUART1 connected to U54 0 */ /* MMUART2 connected to U54 1 */ /* MMUART3 connected to U54 2 */ /* MMUART4 connected to U54 3 */ #define U54_MMUARTx_INT_OFFSET 11 /* MMUART1 connected to U54 0 */ #define U54_WDOGx_MVRP_INT_OFFSET 10 /* determine source mac using hart ID */ #define U54_WDOGx_TOUT_INT_OFFSET 9 /* determine source mac using hart ID */ #define U54_F2M_0_INT_OFFSET 16 #define U54_F2M_1_INT_OFFSET 17 #define U54_F2M_2_INT_OFFSET 18 #define U54_F2M_3_INT_OFFSET 19 #define U54_F2M_4_INT_OFFSET 20 #define U54_F2M_5_INT_OFFSET 21 #define U54_F2M_6_INT_OFFSET 22 #define U54_F2M_7_INT_OFFSET 23 #define U54_F2M_8_INT_OFFSET 24 #define U54_F2M_9_INT_OFFSET 25 #define U54_F2M_10_INT_OFFSET 26 #define U54_F2M_11_INT_OFFSET 27 #define U54_F2M_12_INT_OFFSET 28 #define U54_F2M_13_INT_OFFSET 29 #define U54_F2M_14_INT_OFFSET 30 #define U54_F2M_15_INT_OFFSET 31 #define U54_F2M_16_INT_OFFSET 32 #define U54_F2M_17_INT_OFFSET 33 #define U54_F2M_18_INT_OFFSET 34 #define U54_F2M_19_INT_OFFSET 35 #define U54_F2M_20_INT_OFFSET 36 #define U54_F2M_21_INT_OFFSET 37 #define U54_F2M_22_INT_OFFSET 38 #define U54_F2M_23_INT_OFFSET 39 #define U54_F2M_24_INT_OFFSET 40 #define U54_F2M_25_INT_OFFSET 41 #define U54_F2M_26_INT_OFFSET 42 #define U54_F2M_27_INT_OFFSET 43 #define U54_F2M_28_INT_OFFSET 44 #define U54_F2M_29_INT_OFFSET 45 #define U54_F2M_30_INT_OFFSET 46 #define U54_F2M_31_INT_OFFSET 47 void handle_m_ext_interrupt(void); void E51_software_IRQHandler(void); void U54_1_software_IRQHandler(void); void U54_2_software_IRQHandler(void); void U54_3_software_IRQHandler(void); void U54_4_software_IRQHandler(void); void E51_sysTick_IRQHandler(void); void U54_1_sysTick_IRQHandler(void); void U54_2_sysTick_IRQHandler(void); void U54_3_sysTick_IRQHandler(void); void U54_4_sysTick_IRQHandler(void); /* * * Local interrupt defines * */ void E51_maintenance_local_IRQHandler(void); void E51_usoc_smb_local_IRQHandler(void); void E51_usoc_vc_local_IRQHandler(void); void E51_g5c_message_local_IRQHandler(void); void E51_g5c_devrst_local_IRQHandler(void); void E51_wdog4_tout_local_IRQHandler(void); void E51_wdog3_tout_local_IRQHandler(void); void E51_wdog2_tout_local_IRQHandler(void); void E51_wdog1_tout_local_IRQHandler(void); void E51_wdog0_tout_local_IRQHandler(void); void E51_wdog0_mvrp_local_IRQHandler(void); void E51_mmuart0_local_IRQHandler(void); void E51_envm_local_IRQHandler(void); void E51_ecc_correct_local_IRQHandler(void); void E51_ecc_error_local_IRQHandler(void); void E51_scb_local_IRQHandler(void); void E51_f2m_32_local_IRQHandler(void); void E51_f2m_33_local_IRQHandler(void); void E51_f2m_34_local_IRQHandler(void); void E51_f2m_35_local_IRQHandler(void); void E51_f2m_36_local_IRQHandler(void); void E51_f2m_37_local_IRQHandler(void); void E51_f2m_38_local_IRQHandler(void); void E51_f2m_39_local_IRQHandler(void); void E51_f2m_40_local_IRQHandler(void); void E51_f2m_41_local_IRQHandler(void); void E51_f2m_42_local_IRQHandler(void); void E51_f2m_43_local_IRQHandler(void); void E51_f2m_44_local_IRQHandler(void); void E51_f2m_45_local_IRQHandler(void); void E51_f2m_46_local_IRQHandler(void); void E51_f2m_47_local_IRQHandler(void); void E51_f2m_48_local_IRQHandler(void); void E51_f2m_49_local_IRQHandler(void); void E51_f2m_50_local_IRQHandler(void); void E51_f2m_51_local_IRQHandler(void); void E51_f2m_52_local_IRQHandler(void); void E51_f2m_53_local_IRQHandler(void); void E51_f2m_54_local_IRQHandler(void); void E51_f2m_55_local_IRQHandler(void); void E51_f2m_56_local_IRQHandler(void); void E51_f2m_57_local_IRQHandler(void); void E51_f2m_58_local_IRQHandler(void); void E51_f2m_59_local_IRQHandler(void); void E51_f2m_60_local_IRQHandler(void); void E51_f2m_61_local_IRQHandler(void); void E51_f2m_62_local_IRQHandler(void); void E51_f2m_63_local_IRQHandler(void); /* * U54 */ void U54_spare_0_local_IRQHandler(void); void U54_spare_1_local_IRQHandler(void); void U54_spare_2_local_IRQHandler(void); void U54_1_mac0_mmsl_local_IRQHandler(void); void U54_1_mac0_emac_local_IRQHandler(void); void U54_1_mac0_queue3_local_IRQHandler(void); void U54_1_mac0_queue2_local_IRQHandler(void); void U54_1_mac0_queue1_local_IRQHandler(void); void U54_1_mac0_int_local_IRQHandler(void); void U54_2_mac0_mmsl_local_IRQHandler(void); void U54_2_mac0_emac_local_IRQHandler(void); void U54_2_mac0_queue3_local_IRQHandler(void); void U54_2_mac0_queue2_local_IRQHandler(void); void U54_2_mac0_queue1_local_IRQHandler(void); void U54_2_mac0_int_local_IRQHandler(void); void U54_3_mac1_mmsl_local_IRQHandler(void); void U54_3_mac1_emac_local_IRQHandler(void); void U54_3_mac1_queue3_local_IRQHandler(void); void U54_3_mac1_queue2_local_IRQHandler(void); void U54_3_mac1_queue1_local_IRQHandler(void); void U54_3_mac1_int_local_IRQHandler(void); void U54_4_mac1_mmsl_local_IRQHandler(void); void U54_4_mac1_emac_local_IRQHandler(void); void U54_4_mac1_queue3_local_IRQHandler(void); void U54_4_mac1_queue2_local_IRQHandler(void); void U54_4_mac1_queue1_local_IRQHandler(void); void U54_4_mac1_int_local_IRQHandler(void); void U54_1_wdog_tout_local_IRQHandler(void); void U54_2_wdog_tout_local_IRQHandler(void); void U54_3_wdog_tout_local_IRQHandler(void); void U54_4_wdog_tout_local_IRQHandler(void); void mvrp_u54_local_IRQHandler_10(void); /* legacy name */ void U54_1_wdog_mvrp_local_IRQHandler(void); void U54_2_wdog_mvrp_local_IRQHandler(void); void U54_3_wdog_mvrp_local_IRQHandler(void); void U54_4_wdog_mvrp_local_IRQHandler(void); void U54_1_mmuart1_local_IRQHandler(void); void U54_2_mmuart2_local_IRQHandler(void); void U54_3_mmuart3_local_IRQHandler(void); void U54_4_mmuart4_local_IRQHandler(void); void U54_spare_3_local_IRQHandler(void); void U54_spare_4_local_IRQHandler(void); void U54_spare_5_local_IRQHandler(void); void U54_spare_6_local_IRQHandler(void); void U54_f2m_0_local_IRQHandler(void); void U54_f2m_1_local_IRQHandler(void); void U54_f2m_2_local_IRQHandler(void); void U54_f2m_3_local_IRQHandler(void); void U54_f2m_4_local_IRQHandler(void); void U54_f2m_5_local_IRQHandler(void); void U54_f2m_6_local_IRQHandler(void); void U54_f2m_7_local_IRQHandler(void); void U54_f2m_8_local_IRQHandler(void); void U54_f2m_9_local_IRQHandler(void); void U54_f2m_10_local_IRQHandler(void); void U54_f2m_11_local_IRQHandler(void); void U54_f2m_12_local_IRQHandler(void); void U54_f2m_13_local_IRQHandler(void); void U54_f2m_14_local_IRQHandler(void); void U54_f2m_15_local_IRQHandler(void); void U54_f2m_16_local_IRQHandler(void); void U54_f2m_17_local_IRQHandler(void); void U54_f2m_18_local_IRQHandler(void); void U54_f2m_19_local_IRQHandler(void); void U54_f2m_20_local_IRQHandler(void); void U54_f2m_21_local_IRQHandler(void); void U54_f2m_22_local_IRQHandler(void); void U54_f2m_23_local_IRQHandler(void); void U54_f2m_24_local_IRQHandler(void); void U54_f2m_25_local_IRQHandler(void); void U54_f2m_26_local_IRQHandler(void); void U54_f2m_27_local_IRQHandler(void); void U54_f2m_28_local_IRQHandler(void); void U54_f2m_29_local_IRQHandler(void); void U54_f2m_30_local_IRQHandler(void); void U54_f2m_31_local_IRQHandler(void); #ifdef __cplusplus } #endif #endif /* MSS_HART_INTS_H */ mss_irq_handler_stubs.c000066400000000000000000000640121432224323300406150ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_irq_handler_stubs.c * @author Microchip-FPGA Embedded Systems Solutions * @brief MPFS MSS Interrupt Function stubs. * * The functions below will only be linked with the application code if the user * does not provide an implementation for these functions. These functions are * defined with weak linking so that they can be overridden by a function with * same prototype in the user's application code. * */ #include #include "mpfs_hal/mss_hal.h" __attribute__((weak)) void handle_m_ext_interrupt(void) { } __attribute__((weak)) void E51_software_IRQHandler(void) { } __attribute__((weak)) void U54_1_software_IRQHandler(void) { } __attribute__((weak)) void U54_2_software_IRQHandler(void) { } __attribute__((weak)) void U54_3_software_IRQHandler(void) { } __attribute__((weak)) void U54_4_software_IRQHandler(void) { } __attribute__((weak)) void E51_sysTick_IRQHandler(void) { } __attribute__((weak)) void U54_1_sysTick_IRQHandler(void) { } __attribute__((weak)) void U54_2_sysTick_IRQHandler(void) { } __attribute__((weak)) void U54_3_sysTick_IRQHandler(void) { } __attribute__((weak)) void U54_4_sysTick_IRQHandler(void) { } __attribute__((weak)) uint8_t PLIC_Invalid_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch0_DONE_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch0_ERR_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch1_DONE_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch1_ERR_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch2_DONE_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch2_ERR_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch3_DONE_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_dma_ch3_ERR_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_l2_metadata_corr_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_l2_metadata_uncorr_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_l2_data_corr_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_l2_data_uncorr_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit0_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit1_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit2_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit3_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit4_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit5_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit6_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit7_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit8_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit9_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit10_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit11_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit12_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_bit13_or_gpio2_bit13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit0_or_gpio2_bit14_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit1_or_gpio2_bit15_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit2_or_gpio2_bit16_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit3_or_gpio2_bit17_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit4_or_gpio2_bit18_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit5_or_gpio2_bit19_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit6_or_gpio2_bit20_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit7_or_gpio2_bit21_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit8_or_gpio2_bit22_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit9_or_gpio2_bit23_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit10_or_gpio2_bit24_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit11_or_gpio2_bit25_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit12_or_gpio2_bit26_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit13_or_gpio2_bit27_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit14_or_gpio2_bit28_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit15_or_gpio2_bit29_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit16_or_gpio2_bit30_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit17_or_gpio2_bit31_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit18_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit19_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit20_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit21_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit22_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_bit23_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio0_non_direct_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio1_non_direct_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_gpio2_non_direct_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_spi0_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_spi1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_external_can0_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_can1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_External_i2c0_main_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_External_i2c0_alert_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_i2c0_sus_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_i2c1_main_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_i2c1_alert_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_i2c1_sus_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac0_int_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac0_queue1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac0_queue2_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac0_queue3_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac0_emac_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac0_mmsl_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac1_int_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac1_queue1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac1_queue2_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac1_queue3_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac1_emac_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mac1_mmsl_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_ddrc_train_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_scb_interrupt_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_ecc_error_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_ecc_correct_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_rtc_wakeup_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_rtc_match_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_timer1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_timer2_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_envm_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_qspi_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_usb_dma_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_usb_mc_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmc_main_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmc_wakeup_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmuart0_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmuart1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmuart2_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmuart3_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_mmuart4_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_devrst_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_g5c_message_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_usoc_vc_interrupt_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_usoc_smb_interrupt_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_E51_Maintence_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog0_mvrp_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog1_mvrp_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog2_mvrp_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog3_mvrp_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog4_mvrp_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog0_tout_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog1_tout_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog2_tout_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog3_tout_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_wdog4_tout_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_g5c_mss_spi_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_volt_temp_alarm_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_athena_complete_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_athena_alarm_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_athena_bus_error_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_usoc_axic_us_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_usoc_axic_ds_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_reserved_104_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_0_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_1_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_2_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_3_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_4_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_5_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_6_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_7_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_8_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_9_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_10_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_11_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_12_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_13_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_14_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_15_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_16_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_17_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_18_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_19_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_20_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_21_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_22_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_23_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_24_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_25_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_26_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_27_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_28_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_29_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_30_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_31_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_32_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_33_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_34_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_35_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_36_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_37_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_38_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_39_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_40_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_41_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_42_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_43_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_44_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_45_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_46_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_47_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_48_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_49_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_50_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_51_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_52_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_53_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_54_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_55_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_56_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_57_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_58_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_59_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_60_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_61_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_62_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_f2m_63_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_E51_bus_error_unit_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_U54_1_bus_error_unit_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_U54_2_bus_error_unit_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_U54_3_bus_error_unit_IRQHandler(void) { return(0U); } __attribute__((weak)) uint8_t PLIC_U54_4_bus_error_unit_IRQHandler(void) { return(0U); } /* Local interrupt stubs */ __attribute__((weak)) void E51_maintenance_local_IRQHandler(void) { } __attribute__((weak)) void E51_usoc_smb_local_IRQHandler(void) { } __attribute__((weak)) void E51_usoc_vc_local_IRQHandler(void) { } __attribute__((weak)) void E51_g5c_message_local_IRQHandler(void) { } __attribute__((weak)) void E51_g5c_devrst_local_IRQHandler(void) { } __attribute__((weak)) void E51_wdog4_tout_local_IRQHandler(void) { } __attribute__((weak)) void E51_wdog3_tout_local_IRQHandler(void) { } __attribute__((weak)) void E51_wdog2_tout_local_IRQHandler(void) { } __attribute__((weak)) void E51_wdog1_tout_local_IRQHandler(void) { } __attribute__((weak)) void E51_wdog0_tout_local_IRQHandler(void) { } __attribute__((weak)) void E51_wdog0_mvrp_local_IRQHandler(void) { } __attribute__((weak)) void E51_mmuart0_local_IRQHandler(void) { } __attribute__((weak)) void E51_envm_local_IRQHandler(void) { } __attribute__((weak)) void E51_ecc_correct_local_IRQHandler(void) { } __attribute__((weak)) void E51_ecc_error_local_IRQHandler(void) { } __attribute__((weak)) void E51_scb_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_32_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_33_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_34_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_35_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_36_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_37_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_38_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_39_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_40_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_41_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_42_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_43_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_44_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_45_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_46_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_47_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_48_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_49_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_50_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_51_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_52_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_53_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_54_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_55_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_56_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_57_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_58_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_59_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_60_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_61_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_62_local_IRQHandler(void) { } __attribute__((weak)) void E51_f2m_63_local_IRQHandler(void) { } /* * U54 */ __attribute__((weak)) void U54_spare_0_local_IRQHandler(void) { } __attribute__((weak)) void U54_spare_1_local_IRQHandler(void) { } __attribute__((weak)) void U54_spare_2_local_IRQHandler(void) { } /* Ethernet MACs - GEM0 is on U54s 1 and 2, GEM1 is on U54s 3 and 4 */ /* U54 1 */ __attribute__((weak)) void U54_1_mac0_mmsl_local_IRQHandler(void) { } __attribute__((weak)) void U54_1_mac0_emac_local_IRQHandler(void) { } __attribute__((weak)) void U54_1_mac0_queue3_local_IRQHandler(void) { } __attribute__((weak)) void U54_1_mac0_queue2_local_IRQHandler(void) { } __attribute__((weak)) void U54_1_mac0_queue1_local_IRQHandler(void) { } __attribute__((weak)) void U54_1_mac0_int_local_IRQHandler(void) { } /* U54 2 */ __attribute__((weak)) void U54_2_mac0_mmsl_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_mac0_emac_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_mac0_queue3_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_mac0_queue2_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_mac0_queue1_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_mac0_int_local_IRQHandler(void) { } /* U54 3 */ __attribute__((weak)) void U54_3_mac1_mmsl_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_mac1_emac_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_mac1_queue3_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_mac1_queue2_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_mac1_queue1_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_mac1_int_local_IRQHandler(void) { } /* U54 4 */ __attribute__((weak)) void U54_4_mac1_mmsl_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_mac1_emac_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_mac1_queue3_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_mac1_queue2_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_mac1_queue1_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_mac1_int_local_IRQHandler(void) { } __attribute__((weak)) void U54_1_wdog_tout_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_wdog_tout_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_wdog_tout_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_wdog_tout_local_IRQHandler(void) { } __attribute__((weak)) void mvrp_u54_local_IRQHandler_10(void) { } __attribute__((weak)) void U54_1_wdog_mvrp_local_IRQHandler(void) { mvrp_u54_local_IRQHandler_10(); } __attribute__((weak)) void U54_2_wdog_mvrp_local_IRQHandler(void) { mvrp_u54_local_IRQHandler_10(); } __attribute__((weak)) void U54_3_wdog_mvrp_local_IRQHandler(void) { mvrp_u54_local_IRQHandler_10(); } __attribute__((weak)) void U54_4_wdog_mvrp_local_IRQHandler(void) { mvrp_u54_local_IRQHandler_10(); } __attribute__((weak)) void U54_1_mmuart1_local_IRQHandler(void) { } __attribute__((weak)) void U54_2_mmuart2_local_IRQHandler(void) { } __attribute__((weak)) void U54_3_mmuart3_local_IRQHandler(void) { } __attribute__((weak)) void U54_4_mmuart4_local_IRQHandler(void) { } __attribute__((weak)) void U54_spare_3_local_IRQHandler(void) { } __attribute__((weak)) void U54_spare_4_local_IRQHandler(void) { } __attribute__((weak)) void U54_spare_5_local_IRQHandler(void) { } __attribute__((weak)) void U54_spare_6_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_0_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_1_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_2_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_3_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_4_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_5_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_6_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_7_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_8_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_9_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_10_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_11_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_12_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_13_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_14_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_15_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_16_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_17_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_18_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_19_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_20_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_21_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_22_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_23_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_24_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_25_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_26_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_27_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_28_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_29_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_30_local_IRQHandler(void) { } __attribute__((weak)) void U54_f2m_31_local_IRQHandler(void) { } mss_l2_cache.c000066400000000000000000000263171432224323300365530ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_l2_cache.c * @author Microchip-FPGA Embedded Systems Solutions * @brief The code in this file is executed before any code/data sections are * copied. This code must not rely sdata/data section content. Hence, global * variables should not be used unless they are constants. * */ /*============================================================================== * */ #include #include #include "mpfs_hal/mss_hal.h" #include "mss_l2_cache.h" /*============================================================================== * Local defines */ #if (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0) static const uint64_t g_init_marker = INIT_MARKER; #endif /*============================================================================== * Local functions. */ static void check_config_l2_scratchpad(void); /*============================================================================== * This code should only be executed from E51 to be functional. * Configure the L2 cache memory: * - Set the number of cache ways used as cache based on the MSS Configurator * settings. * - Configure some of the enabled ways as scratchpad based on linker * configuration and space allocated by configurator. */ __attribute__((weak)) void config_l2_cache(void) { _Static_assert(LIBERO_SETTING_WAY_ENABLE < 16U, "Too many ways"); /* * confirm the amount of l2lim used in the Linker script has been allocated * in the MSS Configurator */ ASSERT(((const uint64_t)&__l2lim_end - (const uint64_t)&__l2lim_start)\ <= ((15U - LIBERO_SETTING_WAY_ENABLE) * WAY_BYTE_LENGTH)); /* * confirm the amount of l2lim used in the Linker script has been allocated * in the MSS Configurator */ ASSERT(((const uint64_t)&__l2lim_end - (const uint64_t)&__l2lim_start)\ <= ((15U - LIBERO_SETTING_WAY_ENABLE) * WAY_BYTE_LENGTH)); /* * Set the number of ways that will be shared between cache and scratchpad. */ CACHE_CTRL->WAY_ENABLE = LIBERO_SETTING_WAY_ENABLE; /* * shutdown L2 as directed */ SYSREG->L2_SHUTDOWN_CR = LIBERO_SETTING_L2_SHUTDOWN_CR; /* The scratchpad has already been set-up, first check enough space before copying */ check_config_l2_scratchpad(); /* If you are not using scratchpad, no need to include the following code */ _Static_assert(LIBERO_SETTING_WAY_ENABLE >= LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS, "Scratchpad Missing"); /* * Compute the CONFIG_SERVICE_SCRUB=ymask used to specify ways that will be used by the * scratchpad. */ uint32_t scratchpad_ways_mask = 0U; #if (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0) uint32_t inc; uint32_t seed_ways_mask = 0x1U << LIBERO_SETTING_WAY_ENABLE; for(inc = 0; inc < LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS; ++inc) { scratchpad_ways_mask |= (seed_ways_mask >> inc) ; } #else (void)scratchpad_ways_mask; #endif /* * Make sure ways are masked if being used as scratchpad */ ASSERT((LIBERO_SETTING_WAY_MASK_DMA & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_0 & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_1 & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_2 & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_3 & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_E51_DCACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_E51_ICACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_1_DCACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_2_DCACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_3_DCACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_4_DCACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_1_ICACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_2_ICACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_3_ICACHE & scratchpad_ways_mask) == 0UL); ASSERT((LIBERO_SETTING_WAY_MASK_U54_4_ICACHE & scratchpad_ways_mask) == 0UL); /* * Setup all masters, apart from one we are using to setup scratch */ CACHE_CTRL->WAY_MASK_DMA = LIBERO_SETTING_WAY_MASK_DMA; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_0 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_0; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_1 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_1; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_2 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_2; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_3 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_3; CACHE_CTRL->WAY_MASK_E51_ICACHE = LIBERO_SETTING_WAY_MASK_E51_ICACHE; CACHE_CTRL->WAY_MASK_U54_1_DCACHE = LIBERO_SETTING_WAY_MASK_U54_1_DCACHE; CACHE_CTRL->WAY_MASK_U54_1_ICACHE = LIBERO_SETTING_WAY_MASK_U54_1_ICACHE; CACHE_CTRL->WAY_MASK_U54_2_DCACHE = LIBERO_SETTING_WAY_MASK_U54_2_DCACHE; CACHE_CTRL->WAY_MASK_U54_2_ICACHE = LIBERO_SETTING_WAY_MASK_U54_2_ICACHE; CACHE_CTRL->WAY_MASK_U54_3_DCACHE = LIBERO_SETTING_WAY_MASK_U54_3_DCACHE; CACHE_CTRL->WAY_MASK_U54_3_ICACHE = LIBERO_SETTING_WAY_MASK_U54_3_ICACHE; CACHE_CTRL->WAY_MASK_U54_4_DCACHE = LIBERO_SETTING_WAY_MASK_U54_4_DCACHE; CACHE_CTRL->WAY_MASK_U54_4_ICACHE = LIBERO_SETTING_WAY_MASK_U54_4_ICACHE; #if (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0) /* * Assign ways to Zero Device */ uint64_t * p_scratchpad = (uint64_t *)ZERO_DEVICE_BOTTOM; uint32_t ways_inc; uint64_t current_way = 0x1U << (((LIBERO_SETTING_WAY_ENABLE + 1U) - LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS) ); for(ways_inc = 0; ways_inc < LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS; ++ways_inc) { /* * Populate the scratchpad memory one way at a time. */ CACHE_CTRL->WAY_MASK_E51_DCACHE = current_way; mb(); /* * Write to the first 64-bit location of each cache block. */ for(inc = 0; inc < (WAY_BYTE_LENGTH / CACHE_BLOCK_BYTE_LENGTH); ++inc) { *p_scratchpad = g_init_marker + inc; p_scratchpad += CACHE_BLOCK_BYTE_LENGTH / UINT64_BYTE_LENGTH; } current_way = current_way << 1U; mb(); } #endif /* (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0) */ /* * Prevent E51 from evicting from scratchpad ways. */ CACHE_CTRL->WAY_MASK_E51_DCACHE = LIBERO_SETTING_WAY_MASK_E51_DCACHE; mb(); } /*============================================================================== * Configure the L2 scratchpad based on linker symbols: * __l2_scratchpad_vma_start * __l2_scratchpad_vma_end * * These linker symbols specify the start address and length of the scratchpad. * The scratchpad must be located within the Zero Device memory range. */ static void check_config_l2_scratchpad(void) { extern char __l2_scratchpad_vma_start; extern char __l2_scratchpad_vma_end; uint8_t n_scratchpad_ways; const uint64_t end = (const uint64_t)&__l2_scratchpad_vma_end; const uint64_t start = (const uint64_t)&__l2_scratchpad_vma_start; uint64_t modulo; ASSERT(start >= (uint64_t)ZERO_DEVICE_BOTTOM); ASSERT(end < (uint64_t)ZERO_DEVICE_TOP); ASSERT(end >= start); /* * Figure out how many cache ways will be required from linker script * symbols. */ n_scratchpad_ways = (uint8_t)((end - start) / WAY_BYTE_LENGTH); modulo = (end - start) % WAY_BYTE_LENGTH; if(modulo > 0) { ++n_scratchpad_ways; } ASSERT(LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS >= n_scratchpad_ways); } #if 0 // todo - remove, no longer used /*============================================================================== * Reserve a number of cache ways to be used as scratchpad memory. * * @param nways * Number of ways to be used as scratchpad. One way is 128Kbytes. * * @param scratchpad_start * Start address within the Zero Device memory range in which the scratchpad * will be located. */ static void reserve_scratchpad_ways(uint8_t nways, uint64_t * scratchpad_start) { uint8_t way_enable; uint64_t available_ways = 1; uint64_t scratchpad_ways = 0; uint64_t non_scratchpad_ways; uint32_t inc; ASSERT(scratchpad_start >= (uint64_t *)ZERO_DEVICE_BOTTOM); ASSERT(scratchpad_start < (uint64_t *)ZERO_DEVICE_TOP); /* * Ensure at least one way remains available as cache. */ way_enable = CACHE_CTRL->WAY_ENABLE; ASSERT(nways <= way_enable); if(nways <= way_enable) { /* * Compute the mask used to specify ways that will be used by the * scratchpad. */ for(inc = 0; inc < way_enable; ++inc) { available_ways = (available_ways << 1) | (uint64_t)0x01; if(inc < nways) { scratchpad_ways = (scratchpad_ways << 1) | (uint64_t)0x01; } } /* * Prevent other masters from evicting cache lines from scratchpad ways. * Only allow E51 to evict from scratchpad ways. */ non_scratchpad_ways = available_ways & ~scratchpad_ways; CACHE_CTRL->WAY_MASK_DMA = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_0 = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_1 = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_2 = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_3 = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_E51_ICACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_1_DCACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_1_ICACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_2_DCACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_2_ICACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_3_DCACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_3_ICACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_4_DCACHE = non_scratchpad_ways; CACHE_CTRL->WAY_MASK_U54_4_ICACHE = non_scratchpad_ways; /* * Assign ways to Zero Device */ uint64_t * p_scratchpad = scratchpad_start; int ways_inc; uint64_t current_way = 1; for(ways_inc = 0; ways_inc < nways; ++ways_inc) { /* * Populate the scratchpad memory one way at a time. */ CACHE_CTRL->WAY_MASK_E51_DCACHE = current_way; /* * Write to the first 64-bit location of each cache block. */ for(inc = 0; inc < (WAY_BYTE_LENGTH / CACHE_BLOCK_BYTE_LENGTH); ++inc) { *p_scratchpad = g_init_marker + inc; p_scratchpad += CACHE_BLOCK_BYTE_LENGTH / UINT64_BYTE_LENGTH; } current_way = current_way << 1U; mb(); } /* * Prevent E51 from evicting from scratchpad ways. */ CACHE_CTRL->WAY_MASK_E51_DCACHE = non_scratchpad_ways; } } #endif mss_l2_cache.h000066400000000000000000000700301432224323300365470ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*************************************************************************** * @file mss_l2_cache.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MACROs defines and prototypes associated with L2 Cache * */ #ifndef MSS_L2_CACHE_H #define MSS_L2_CACHE_H #include #include "encoding.h" #ifdef __cplusplus extern "C" { #endif /* * The following defines will be present in configurator generated xml Q1 2021 * In the interim, you can manually edit if required. */ #if !defined (LIBERO_SETTING_WAY_ENABLE) /*Way indexes less than or equal to this register value may be used by the cache. E.g. set to 0x7, will allocate 8 cache ways, 0-7 to cache, and leave 8-15 as LIM. Note 1: Way 0 is always allocated as cache. Note 2: each way is 128KB. */ #define LIBERO_SETTING_WAY_ENABLE 0x00000007UL /* WAY_ENABLE [0:8] RW value= 0x7 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_DMA) /*Way mask register master DMA. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_DMA 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_AXI4_PORT_0) /*Way mask register master DMA. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_AXI4_PORT_0 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_AXI4_PORT_1) /*Way mask register master DMA. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_AXI4_PORT_1 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_AXI4_PORT_2) /*Way mask registerAXI slave port 2. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_AXI4_PORT_2 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_AXI4_PORT_3) /*Way mask register AXI slave port 3. Set field to 1 to disable way from this master. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_AXI4_PORT_3 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_E51_DCACHE) /*Way mask register E51 data cache (hart0). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_E51_DCACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_E51_ICACHE) /*Way mask registerE52 instruction cache (hart0). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_E51_ICACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_1_DCACHE) /*Way mask register data cache (hart1). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_1_DCACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_1_ICACHE) /*Way mask register instruction cache (hart1). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_1_ICACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_2_DCACHE) /*Way mask register data cache (hart2). Set field to 1 to disable way from this master. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_2_DCACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_2_ICACHE) /*Way mask register instruction cache (hart2). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_2_ICACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_3_DCACHE) /*Way mask register data cache (hart3). Set field to 1 to disable way from this master.Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_3_DCACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_3_ICACHE) /*Way mask register instruction cache(hart3). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_3_ICACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_4_DCACHE) /*Way mask register data cache (hart4). Set field to 1 to disable way from this master. Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_4_DCACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_WAY_MASK_U54_4_ICACHE) /*Way mask register instruction cache (hart4). Set field to zero to disable way from this master. The available cache ways are 0 to number set in WAY_ENABLE register. If using scratch pad memory, the ways you want reserved for scrathpad are not available for selection, you must set to 0. e.g. If three ways reserved for scratchpad, WAY_MASK_0, WAY_MASK_1 and WAY_MASK_2 will be set to zero for all masters, so they can not evict the way. */ #define LIBERO_SETTING_WAY_MASK_U54_4_ICACHE 0x0000FFFFUL /* WAY_MASK_0 [0:1] RW value= 0x1 */ /* WAY_MASK_1 [1:1] RW value= 0x1 */ /* WAY_MASK_2 [2:1] RW value= 0x1 */ /* WAY_MASK_3 [3:1] RW value= 0x1 */ /* WAY_MASK_4 [4:1] RW value= 0x1 */ /* WAY_MASK_5 [5:1] RW value= 0x1 */ /* WAY_MASK_6 [6:1] RW value= 0x1 */ /* WAY_MASK_7 [7:1] RW value= 0x1 */ /* WAY_MASK_8 [8:1] RW value= 0x1 */ /* WAY_MASK_9 [9:1] RW value= 0x1 */ /* WAY_MASK_10 [10:1] RW value= 0x1 */ /* WAY_MASK_11 [11:1] RW value= 0x1 */ /* WAY_MASK_12 [12:1] RW value= 0x1 */ /* WAY_MASK_13 [13:1] RW value= 0x1 */ /* WAY_MASK_14 [14:1] RW value= 0x1 */ /* WAY_MASK_15 [15:1] RW value= 0x1 */ #endif #if !defined (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS) /*Number of ways reserved for scratchpad. Note 1: This is not a register Note 2: each way is 128KB. Note 3: Embedded software expects cache ways allocated for scratchpad start at way 0, and work up. */ #define LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS 0x00000000UL /* NUM_OF_WAYS [0:8] RW value= 0x0 */ #endif #if !defined (LIBERO_SETTING_L2_SHUTDOWN_CR) /*Number of ways reserved for scratchpad. Note 1: This is not a register Note 2: each way is 128KB. Note 3: Embedded software expects cache ways allocated for scratchpad start at way 0, and work up. */ #define LIBERO_SETTING_L2_SHUTDOWN_CR 0x00000000UL /* NUM_OF_WAYS [0:8] RW value= 0x0 */ #endif /*============================================================================== * Define describing cache characteristics. */ #define MAX_WAY_ENABLE 15 #define NB_SETS 512 #define NB_BANKS 4 #define CACHE_BLOCK_BYTE_LENGTH 64 #define UINT64_BYTE_LENGTH 8 #define WAY_BYTE_LENGTH (CACHE_BLOCK_BYTE_LENGTH * NB_SETS * NB_BANKS) #define ZERO_DEVICE_BOTTOM 0x0A000000ULL #define ZERO_DEVICE_TOP 0x0C000000ULL #define CACHE_CTRL_BASE 0x02010000ULL #define INIT_MARKER 0xC0FFEEBEC0010000ULL #define SHUTDOWN_CACHE_CC24_00_07_MASK 0x01 #define SHUTDOWN_CACHE_CC24_08_15_MASK 0x02 #define SHUTDOWN_CACHE_CC24_16_23_MASK 0x04 #define SHUTDOWN_CACHE_CC24_24_31_MASK 0x08 /*============================================================================== * Cache controller registers definitions */ #define RO volatile const #define RW volatile #define WO volatile typedef struct { RO uint8_t BANKS; RO uint8_t WAYS; RO uint8_t SETS; RO uint8_t BYTES; } CACHE_CONFIG_typedef; typedef struct { CACHE_CONFIG_typedef CONFIG; RO uint32_t RESERVED; RW uint8_t WAY_ENABLE; RO uint8_t RESERVED0[55]; RW uint32_t ECC_INJECT_ERROR; RO uint32_t RESERVED1[47]; RO uint64_t ECC_DIR_FIX_ADDR; RO uint32_t ECC_DIR_FIX_COUNT; RO uint32_t RESERVED2[13]; RO uint64_t ECC_DATA_FIX_ADDR; RO uint32_t ECC_DATA_FIX_COUNT; RO uint32_t RESERVED3[5]; RO uint64_t ECC_DATA_FAIL_ADDR; RO uint32_t ECC_DATA_FAIL_COUNT; RO uint32_t RESERVED4[37]; WO uint64_t FLUSH64; RO uint64_t RESERVED5[7]; WO uint32_t FLUSH32; RO uint32_t RESERVED6[367]; RW uint64_t WAY_MASK_DMA; RW uint64_t WAY_MASK_AXI4_SLAVE_PORT_0; RW uint64_t WAY_MASK_AXI4_SLAVE_PORT_1; RW uint64_t WAY_MASK_AXI4_SLAVE_PORT_2; RW uint64_t WAY_MASK_AXI4_SLAVE_PORT_3; RW uint64_t WAY_MASK_E51_DCACHE; RW uint64_t WAY_MASK_E51_ICACHE; RW uint64_t WAY_MASK_U54_1_DCACHE; RW uint64_t WAY_MASK_U54_1_ICACHE; RW uint64_t WAY_MASK_U54_2_DCACHE; RW uint64_t WAY_MASK_U54_2_ICACHE; RW uint64_t WAY_MASK_U54_3_DCACHE; RW uint64_t WAY_MASK_U54_3_ICACHE; RW uint64_t WAY_MASK_U54_4_DCACHE; RW uint64_t WAY_MASK_U54_4_ICACHE; } CACHE_CTRL_typedef; #define CACHE_CTRL ((volatile CACHE_CTRL_typedef *) CACHE_CTRL_BASE) void config_l2_cache(void); uint8_t check_num_scratch_ways(uint64_t *start, uint64_t *end); #ifdef __cplusplus } #endif #endif /* MSS_L2_CACHE_H */ mss_legacy_defines.h000066400000000000000000001300111432224323300400440ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2021-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_hart_ints.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MPFS legacy defines * * Mapping of older defines to newer defines to allow older code compile * */ #ifndef MSS_LEGACY_DEFINES_H #define MSS_LEGACY_DEFINES_H #include #ifdef __cplusplus extern "C" { #endif #define maintenance_e51_local_IRQHandler_0 E51_maintenance_local_IRQHandler #define usoc_smb_interrupt_e51_local_IRQHandler_1 E51_usoc_smb_local_IRQHandler #define usoc_vc_interrupt_e51_local_IRQHandler_2 E51_usoc_vc_local_IRQHandler #define g5c_message_e51_local_IRQHandler_3 E51_g5c_message_local_IRQHandler #define g5c_devrst_e51_local_IRQHandler_4 E51_g5c_devrst_local_IRQHandler #define wdog4_tout_e51_local_IRQHandler_5 E51_wdog4_tout_local_IRQHandler #define wdog3_tout_e51_local_IRQHandler_6 E51_wdog3_tout_local_IRQHandler #define wdog2_tout_e51_local_IRQHandler_7 E51_wdog2_tout_local_IRQHandler #define wdog1_tout_e51_local_IRQHandler_8 E51_wdog1_tout_local_IRQHandler #define wdog0_tout_e51_local_IRQHandler_9 E51_wdog0_tout_local_IRQHandler #define wdog0_mvrp_e51_local_IRQHandler_10 E51_wdog0_mvrp_local_IRQHandler #define mmuart0_e51_local_IRQHandler_11 E51_mmuart0_local_IRQHandler #define envm_e51_local_IRQHandler_12 E51_envm_local_IRQHandler #define ecc_correct_e51_local_IRQHandler_13 E51_ecc_correct_local_IRQHandler #define ecc_error_e51_local_IRQHandler_14 E51_ecc_error_local_IRQHandler #define scb_interrupt_e51_local_IRQHandler_15 E51_scb_local_IRQHandler #define fabric_f2h_32_e51_local_IRQHandler_16 E51_f2m_32_local_IRQHandler #define fabric_f2h_33_e51_local_IRQHandler_17 E51_f2m_33_local_IRQHandler #define fabric_f2h_34_e51_local_IRQHandler_18 E51_f2m_34_local_IRQHandler #define fabric_f2h_35_e51_local_IRQHandler_19 E51_f2m_35_local_IRQHandler #define fabric_f2h_36_e51_local_IRQHandler_20 E51_f2m_36_local_IRQHandler #define fabric_f2h_37_e51_local_IRQHandler_21 E51_f2m_37_local_IRQHandler #define fabric_f2h_38_e51_local_IRQHandler_22 E51_f2m_38_local_IRQHandler #define fabric_f2h_39_e51_local_IRQHandler_23 E51_f2m_39_local_IRQHandler #define fabric_f2h_40_e51_local_IRQHandler_24 E51_f2m_40_local_IRQHandler #define fabric_f2h_41_e51_local_IRQHandler_25 E51_f2m_41_local_IRQHandler #define fabric_f2h_42_e51_local_IRQHandler_26 E51_f2m_42_local_IRQHandler #define fabric_f2h_43_e51_local_IRQHandler_27 E51_f2m_43_local_IRQHandler #define fabric_f2h_44_e51_local_IRQHandler_28 E51_f2m_44_local_IRQHandler #define fabric_f2h_45_e51_local_IRQHandler_29 E51_f2m_45_local_IRQHandler #define fabric_f2h_46_e51_local_IRQHandler_30 E51_f2m_46_local_IRQHandler #define fabric_f2h_47_e51_local_IRQHandler_31 E51_f2m_47_local_IRQHandler #define fabric_f2h_48_e51_local_IRQHandler_32 E51_f2m_48_local_IRQHandler #define fabric_f2h_49_e51_local_IRQHandler_33 E51_f2m_49_local_IRQHandler #define fabric_f2h_50_e51_local_IRQHandler_34 E51_f2m_50_local_IRQHandler #define fabric_f2h_51_e51_local_IRQHandler_35 E51_f2m_51_local_IRQHandler #define fabric_f2h_52_e51_local_IRQHandler_36 E51_f2m_52_local_IRQHandler #define fabric_f2h_53_e51_local_IRQHandler_37 E51_f2m_53_local_IRQHandler #define fabric_f2h_54_e51_local_IRQHandler_38 E51_f2m_54_local_IRQHandler #define fabric_f2h_55_e51_local_IRQHandler_39 E51_f2m_55_local_IRQHandler #define fabric_f2h_56_e51_local_IRQHandler_40 E51_f2m_56_local_IRQHandler #define fabric_f2h_57_e51_local_IRQHandler_41 E51_f2m_57_local_IRQHandler #define fabric_f2h_58_e51_local_IRQHandler_42 E51_f2m_58_local_IRQHandler #define fabric_f2h_59_e51_local_IRQHandler_43 E51_f2m_59_local_IRQHandler #define fabric_f2h_60_e51_local_IRQHandler_44 E51_f2m_60_local_IRQHandler #define fabric_f2h_61_e51_local_IRQHandler_45 E51_f2m_61_local_IRQHandler #define fabric_f2h_62_e51_local_IRQHandler_46 E51_f2m_62_local_IRQHandler #define fabric_f2h_63_e51_local_IRQHandler_47 E51_f2m_63_local_IRQHandler #define spare_u54_local_IRQHandler_0 U54_spare_0_local_IRQHandler #define spare_u54_local_IRQHandler_1 U54_spare_1_local_IRQHandler #define spare_u54_local_IRQHandler_2 U54_spare_2_local_IRQHandler #define mac_mmsl_u54_1_local_IRQHandler_3 U54_1_mac0_mmsl_local_IRQHandler #define mac_emac_u54_1_local_IRQHandler_4 U54_1_mac0_emac_local_IRQHandler #define mac_queue3_u54_1_local_IRQHandler_5 U54_1_mac0_queue3_local_IRQHandler #define mac_queue2_u54_1_local_IRQHandler_6 U54_1_mac0_queue2_local_IRQHandler #define mac_queue1_u54_1_local_IRQHandler_7 U54_1_mac0_queue1_local_IRQHandler #define mac_int_u54_1_local_IRQHandler_8 U54_1_mac0_int_local_IRQHandler #define mac_mmsl_u54_2_local_IRQHandler_3 U54_2_mac0_mmsl_local_IRQHandler #define mac_emac_u54_2_local_IRQHandler_4 U54_2_mac0_emac_local_IRQHandler #define mac_queue3_u54_2_local_IRQHandler_5 U54_2_mac0_queue3_local_IRQHandler #define mac_queue2_u54_2_local_IRQHandler_6 U54_2_mac0_queue2_local_IRQHandler #define mac_queue1_u54_2_local_IRQHandler_7 U54_2_mac0_queue1_local_IRQHandler #define mac_int_u54_2_local_IRQHandler_8 U54_2_mac0_int_local_IRQHandler #define mac_mmsl_u54_3_local_IRQHandler_3 U54_3_mac1_mmsl_local_IRQHandler #define mac_emac_u54_3_local_IRQHandler_4 U54_3_mac1_emac_local_IRQHandler #define mac_queue3_u54_3_local_IRQHandler_5 U54_3_mac1_queue3_local_IRQHandler #define mac_queue2_u54_3_local_IRQHandler_6 U54_3_mac1_queue2_local_IRQHandler #define mac_queue1_u54_3_local_IRQHandler_7 U54_3_mac1_queue1_local_IRQHandler #define mac_int_u54_3_local_IRQHandler_8 U54_3_mac1_int_local_IRQHandler #define mac_mmsl_u54_4_local_IRQHandler_3 U54_4_mac1_mmsl_local_IRQHandler #define mac_emac_u54_4_local_IRQHandler_4 U54_4_mac1_emac_local_IRQHandler #define mac_queue3_u54_4_local_IRQHandler_5 U54_4_mac1_queue3_local_IRQHandler #define mac_queue2_u54_4_local_IRQHandler_6 U54_4_mac1_queue2_local_IRQHandler #define mac_queue1_u54_4_local_IRQHandler_7 U54_4_mac1_queue1_local_IRQHandler #define mac_int_u54_4_local_IRQHandler_8 U54_4_mac1_int_local_IRQHandler #define wdog_tout_u54_h1_local_IRQHandler_9 U54_1_wdog_tout_local_IRQHandler /* * Update your watchdog code if using mvrp_u54_local_IRQHandler_10() * to use the following instead: * U54_1_wdog_mvrp_local_IRQHandler() * U54_2_wdog_mvrp_local_IRQHandler() * U54_3_wdog_mvrp_local_IRQHandler() * U54_4_wdog_mvrp_local_IRQHandler() */ #define mmuart_u54_h1_local_IRQHandler_11 U54_1_mmuart1_local_IRQHandler #define wdog_tout_u54_h2_local_IRQHandler_9 U54_2_wdog_tout_local_IRQHandler #define mmuart_u54_h2_local_IRQHandler_11 U54_2_mmuart2_local_IRQHandler #define wdog_tout_u54_h3_local_IRQHandler_9 U54_3_wdog_tout_local_IRQHandler #define mmuart_u54_h3_local_IRQHandler_11 U54_3_mmuart3_local_IRQHandler #define wdog_tout_u54_h4_local_IRQHandler_9 U54_4_wdog_tout_local_IRQHandler #define mmuart_u54_h4_local_IRQHandler_11 U54_4_mmuart4_local_IRQHandler #define spare_u54_local_IRQHandler_12 U54_spare_3_local_IRQHandler #define spare_u54_local_IRQHandler_13 U54_spare_4_local_IRQHandler #define spare_u54_local_IRQHandler_14 U54_spare_5_local_IRQHandler #define spare_u54_local_IRQHandler_15 U54_spare_6_local_IRQHandler #define fabric_f2h_0_u54_local_IRQHandler_16 U54_f2m_0_local_IRQHandler #define fabric_f2h_1_u54_local_IRQHandler_17 U54_f2m_1_local_IRQHandler #define fabric_f2h_2_u54_local_IRQHandler_18 U54_f2m_2_local_IRQHandler #define fabric_f2h_3_u54_local_IRQHandler_19 U54_f2m_3_local_IRQHandler #define fabric_f2h_4_u54_local_IRQHandler_20 U54_f2m_4_local_IRQHandler #define fabric_f2h_5_u54_local_IRQHandler_21 U54_f2m_5_local_IRQHandler #define fabric_f2h_6_u54_local_IRQHandler_22 U54_f2m_6_local_IRQHandler #define fabric_f2h_7_u54_local_IRQHandler_23 U54_f2m_7_local_IRQHandler #define fabric_f2h_8_u54_local_IRQHandler_24 U54_f2m_8_local_IRQHandler #define fabric_f2h_9_u54_local_IRQHandler_25 U54_f2m_9_local_IRQHandler #define fabric_f2h_10_u54_local_IRQHandler_26 U54_f2m_10_local_IRQHandler #define fabric_f2h_11_u54_local_IRQHandler_27 U54_f2m_11_local_IRQHandler #define fabric_f2h_12_u54_local_IRQHandler_28 U54_f2m_12_local_IRQHandler #define fabric_f2h_13_u54_local_IRQHandler_29 U54_f2m_13_local_IRQHandler #define fabric_f2h_14_u54_local_IRQHandler_30 U54_f2m_14_local_IRQHandler #define fabric_f2h_15_u54_local_IRQHandler_31 U54_f2m_15_local_IRQHandler #define fabric_f2h_16_u54_local_IRQHandler_32 U54_f2m_16_local_IRQHandler #define fabric_f2h_17_u54_local_IRQHandler_33 U54_f2m_17_local_IRQHandler #define fabric_f2h_18_u54_local_IRQHandler_34 U54_f2m_18_local_IRQHandler #define fabric_f2h_19_u54_local_IRQHandler_35 U54_f2m_19_local_IRQHandler #define fabric_f2h_20_u54_local_IRQHandler_36 U54_f2m_20_local_IRQHandler #define fabric_f2h_21_u54_local_IRQHandler_37 U54_f2m_21_local_IRQHandler #define fabric_f2h_22_u54_local_IRQHandler_38 U54_f2m_22_local_IRQHandler #define fabric_f2h_23_u54_local_IRQHandler_39 U54_f2m_23_local_IRQHandler #define fabric_f2h_24_u54_local_IRQHandler_40 U54_f2m_24_local_IRQHandler #define fabric_f2h_25_u54_local_IRQHandler_41 U54_f2m_25_local_IRQHandler #define fabric_f2h_26_u54_local_IRQHandler_42 U54_f2m_26_local_IRQHandler #define fabric_f2h_27_u54_local_IRQHandler_43 U54_f2m_27_local_IRQHandler #define fabric_f2h_28_u54_local_IRQHandler_44 U54_f2m_28_local_IRQHandler #define fabric_f2h_29_u54_local_IRQHandler_45 U54_f2m_29_local_IRQHandler #define fabric_f2h_30_u54_local_IRQHandler_46 U54_f2m_30_local_IRQHandler #define fabric_f2h_31_u54_local_IRQHandler_47 U54_f2m_31_local_IRQHandler #define MAINTENANCE_E51_INT 0 #define USOC_SMB_INTERRUPT_E51_INT 1 #define USOC_VC_INTERRUPT_E51_INT 2 #define G5C_MESSAGE_E51_INT 3 #define G5C_DEVRST_E51_INT 4 #define WDOG4_TOUT_E51_INT 5 #define WDOG3_TOUT_E51_INT 6 #define WDOG2_TOUT_E51_INT 7 #define WDOG1_TOUT_E51_INT 8 #define WDOG0_TOUT_E51_INT 9 #define WDOG0_MVRP_E51_INT 10 #define MMUART0_E51_INT 11 #define ENVM_E51_INT 12 #define ECC_CORRECT_E51_INT 13 #define ECC_ERROR_E51_INT 14 #define scb_INTERRUPT_E51_INT 15 #define FABRIC_F2H_32_E51_INT 16 #define FABRIC_F2H_33_E51_INT 17 #define FABRIC_F2H_34_E51_INT 18 #define FABRIC_F2H_35_E51_INT 19 #define FABRIC_F2H_36_E51_INT 20 #define FABRIC_F2H_37_E51_INT 21 #define FABRIC_F2H_38_E51_INT 22 #define FABRIC_F2H_39_E51_INT 23 #define FABRIC_F2H_40_E51_INT 24 #define FABRIC_F2H_41_E51_INT 25 #define FABRIC_F2H_42_E51_INT 26 #define FABRIC_F2H_43_E51_INT 27 #define FABRIC_F2H_44_E51_INT 28 #define FABRIC_F2H_45_E51_INT 29 #define FABRIC_F2H_46_E51_INT 30 #define FABRIC_F2H_47_E51_INT 31 #define FABRIC_F2H_48_E51_INT 32 #define FABRIC_F2H_49_E51_INT 33 #define FABRIC_F2H_50_E51_INT 34 #define FABRIC_F2H_51_E51_INT 35 #define FABRIC_F2H_52_E51_INT 36 #define FABRIC_F2H_53_E51_INT 37 #define FABRIC_F2H_54_E51_INT 38 #define FABRIC_F2H_55_E51_INT 39 #define FABRIC_F2H_56_E51_INT 40 #define FABRIC_F2H_57_E51_INT 41 #define FABRIC_F2H_58_E51_INT 42 #define FABRIC_F2H_59_E51_INT 43 #define FABRIC_F2H_60_E51_INT 44 #define FABRIC_F2H_61_E51_INT 45 #define FABRIC_F2H_62_E51_INT 46 #define FABRIC_F2H_63_E51_INT 47 /* U0 (first U54) and U1 connected to mac0 */ #define MAC0_INT_U54_INT 8 /* determine source mac using hart ID */ #define MAC0_QUEUE1_U54_INT 7 #define MAC0_QUEUE2_U54_INT 6 #define MAC0_QUEUE3_U54_INT 5 #define MAC0_EMAC_U54_INT 4 #define MAC0_MMSL_U54_INT 3 /* U2 and U3 connected to mac1 */ #define MAC1_INT_U54_INT 8 /* determine source mac using hart ID */ #define MAC1_QUEUE1_U54_INT 7 #define MAC1_QUEUE2_U54_INT 6 #define MAC1_QUEUE3_U54_INT 5 #define MAC1_EMAC_U54_INT 4 #define MAC1_MMSL_U54_INT 3 /* MMUART1 connected to U54 0 */ /* MMUART2 connected to U54 1 */ /* MMUART3 connected to U54 2 */ /* MMUART4 connected to U54 3 */ #define MMUARTx_U54_INT 11 /* MMUART1 connected to U54 0 */ #define WDOGx_MVRP_U54_INT 10 /* determine source mac using hart ID */ #define WDOGx_TOUT_U54_INT 9 /* determine source mac using hart ID */ #define H2_FABRIC_F2H_0_U54_INT 16 #define H2_FABRIC_F2H_1_U54_INT 17 #define H2_FABRIC_F2H_2_U54_INT 18 #define H2_FABRIC_F2H_3_U54_INT 19 #define H2_FABRIC_F2H_4_U54_INT 20 #define H2_FABRIC_F2H_5_U54_INT 21 #define H2_FABRIC_F2H_6_U54_INT 22 #define H2_FABRIC_F2H_7_U54_INT 23 #define H2_FABRIC_F2H_8_U54_INT 24 #define H2_FABRIC_F2H_9_U54_INT 25 #define H2_FABRIC_F2H_10_U54_INT 26 #define H2_FABRIC_F2H_11_U54_INT 27 #define H2_FABRIC_F2H_12_U54_INT 28 #define H2_FABRIC_F2H_13_U54_INT 29 #define H2_FABRIC_F2H_14_U54_INT 30 #define H2_FABRIC_F2H_15_U54_INT 31 #define H2_FABRIC_F2H_16_U54_INT 32 #define H2_FABRIC_F2H_17_U54_INT 33 #define H2_FABRIC_F2H_18_U54_INT 34 #define H2_FABRIC_F2H_19_U54_INT 35 #define H2_FABRIC_F2H_20_U54_INT 36 #define H2_FABRIC_F2H_21_U54_INT 37 #define H2_FABRIC_F2H_22_U54_INT 38 #define H2_FABRIC_F2H_23_U54_INT 39 #define H2_FABRIC_F2H_24_U54_INT 40 #define H2_FABRIC_F2H_25_U54_INT 41 #define H2_FABRIC_F2H_26_U54_INT 42 #define H2_FABRIC_F2H_27_U54_INT 43 #define H2_FABRIC_F2H_28_U54_INT 44 #define H2_FABRIC_F2H_29_U54_INT 45 #define H2_FABRIC_F2H_30_U54_INT 46 #define H2_FABRIC_F2H_31_U54_INT 47 #define Invalid_IRQHandler PLIC_Invalid_IRQHandler #define l2_metadata_corr_IRQHandler PLIC_l2_metadata_corr_IRQHandler #define l2_metadata_uncorr_IRQHandler PLIC_l2_metadata_uncorr_IRQHandler #define l2_data_corr_IRQHandler PLIC_l2_data_corr_IRQHandler #define l2_data_uncorr_IRQHandler PLIC_l2_data_uncorr_IRQHandler #define dma_ch0_DONE_IRQHandler PLIC_dma_ch0_DONE_IRQHandler #define dma_ch0_ERR_IRQHandler PLIC_dma_ch0_ERR_IRQHandler #define dma_ch1_DONE_IRQHandler PLIC_dma_ch1_DONE_IRQHandler #define dma_ch1_ERR_IRQHandler PLIC_dma_ch1_ERR_IRQHandler #define dma_ch2_DONE_IRQHandler PLIC_dma_ch2_DONE_IRQHandler #define dma_ch2_ERR_IRQHandler PLIC_dma_ch2_ERR_IRQHandler #define dma_ch3_DONE_IRQHandler PLIC_dma_ch3_DONE_IRQHandler #define dma_ch3_ERR_IRQHandler PLIC_dma_ch3_ERR_IRQHandler #define gpio0_bit0_or_gpio2_bit13_plic_0_IRQHandler PLIC_gpio0_bit0_or_gpio2_bit13_IRQHandler #define gpio0_bit1_or_gpio2_bit13_plic_1_IRQHandler PLIC_gpio0_bit1_or_gpio2_bit13_IRQHandler #define gpio0_bit2_or_gpio2_bit13_plic_2_IRQHandler PLIC_gpio0_bit2_or_gpio2_bit13_IRQHandler #define gpio0_bit3_or_gpio2_bit13_plic_3_IRQHandler PLIC_gpio0_bit3_or_gpio2_bit13_IRQHandler #define gpio0_bit4_or_gpio2_bit13_plic_4_IRQHandler PLIC_gpio0_bit4_or_gpio2_bit13_IRQHandler #define gpio0_bit5_or_gpio2_bit13_plic_5_IRQHandler PLIC_gpio0_bit5_or_gpio2_bit13_IRQHandler #define gpio0_bit6_or_gpio2_bit13_plic_6_IRQHandler PLIC_gpio0_bit6_or_gpio2_bit13_IRQHandler #define gpio0_bit7_or_gpio2_bit13_plic_7_IRQHandler PLIC_gpio0_bit7_or_gpio2_bit13_IRQHandler #define gpio0_bit8_or_gpio2_bit13_plic_8_IRQHandler PLIC_gpio0_bit8_or_gpio2_bit13_IRQHandler #define gpio0_bit9_or_gpio2_bit13_plic_9_IRQHandler PLIC_gpio0_bit9_or_gpio2_bit13_IRQHandler #define gpio0_bit10_or_gpio2_bit13_plic_10_IRQHandler PLIC_gpio0_bit10_or_gpio2_bit13_IRQHandler #define gpio0_bit11_or_gpio2_bit13_plic_11_IRQHandler PLIC_gpio0_bit11_or_gpio2_bit13_IRQHandler #define gpio0_bit12_or_gpio2_bit13_plic_12_IRQHandler PLIC_gpio0_bit12_or_gpio2_bit13_IRQHandler #define gpio0_bit13_or_gpio2_bit13_plic_13_IRQHandler PLIC_gpio0_bit13_or_gpio2_bit13_IRQHandler #define gpio1_bit0_or_gpio2_bit14_plic_14_IRQHandler PLIC_gpio1_bit0_or_gpio2_bit14_IRQHandler #define gpio1_bit1_or_gpio2_bit15_plic_15_IRQHandler PLIC_gpio1_bit1_or_gpio2_bit15_IRQHandler #define gpio1_bit2_or_gpio2_bit16_plic_16_IRQHandler PLIC_gpio1_bit2_or_gpio2_bit16_IRQHandler #define gpio1_bit3_or_gpio2_bit17_plic_17_IRQHandler PLIC_gpio1_bit3_or_gpio2_bit17_IRQHandler #define gpio1_bit4_or_gpio2_bit18_plic_18_IRQHandler PLIC_gpio1_bit4_or_gpio2_bit18_IRQHandler #define gpio1_bit5_or_gpio2_bit19_plic_19_IRQHandler PLIC_gpio1_bit5_or_gpio2_bit19_IRQHandler #define gpio1_bit6_or_gpio2_bit20_plic_20_IRQHandler PLIC_gpio1_bit6_or_gpio2_bit20_IRQHandler #define gpio1_bit7_or_gpio2_bit21_plic_21_IRQHandler PLIC_gpio1_bit7_or_gpio2_bit21_IRQHandler #define gpio1_bit8_or_gpio2_bit22_plic_22_IRQHandler PLIC_gpio1_bit8_or_gpio2_bit22_IRQHandler #define gpio1_bit9_or_gpio2_bit23_plic_23_IRQHandler PLIC_gpio1_bit9_or_gpio2_bit23_IRQHandler #define gpio1_bit10_or_gpio2_bit24_plic_24_IRQHandler PLIC_gpio1_bit10_or_gpio2_bit24_IRQHandler #define gpio1_bit11_or_gpio2_bit25_plic_25_IRQHandler PLIC_gpio1_bit11_or_gpio2_bit25_IRQHandler #define gpio1_bit12_or_gpio2_bit26_plic_26_IRQHandler PLIC_gpio1_bit12_or_gpio2_bit26_IRQHandler #define gpio1_bit13_or_gpio2_bit27_plic_27_IRQHandler PLIC_gpio1_bit13_or_gpio2_bit27_IRQHandler #define gpio1_bit14_or_gpio2_bit28_plic_28_IRQHandler PLIC_gpio1_bit14_or_gpio2_bit28_IRQHandler #define gpio1_bit15_or_gpio2_bit29_plic_29_IRQHandler PLIC_gpio1_bit15_or_gpio2_bit29_IRQHandler #define gpio1_bit16_or_gpio2_bit30_plic_30_IRQHandler PLIC_gpio1_bit16_or_gpio2_bit30_IRQHandler #define gpio1_bit17_or_gpio2_bit31_plic_31_IRQHandler PLIC_gpio1_bit17_or_gpio2_bit31_IRQHandler #define gpio1_bit18_plic_32_IRQHandler PLIC_gpio1_bit18_IRQHandler #define gpio1_bit19_plic_33_IRQHandler PLIC_gpio1_bit19_IRQHandler #define gpio1_bit20_plic_34_IRQHandler PLIC_gpio1_bit20_IRQHandler #define gpio1_bit21_plic_35_IRQHandler PLIC_gpio1_bit21_IRQHandler #define gpio1_bit22_plic_36_IRQHandler PLIC_gpio1_bit22_IRQHandler #define gpio1_bit23_plic_37_IRQHandler PLIC_gpio1_bit23_IRQHandler #define gpio0_non_direct_plic_IRQHandler PLIC_gpio0_non_direct_IRQHandler #define gpio1_non_direct_plic_IRQHandler PLIC_gpio1_non_direct_IRQHandler #define gpio2_non_direct_plic_IRQHandler PLIC_gpio2_non_direct_IRQHandler #define spi0_plic_IRQHandler PLIC_spi0_IRQHandler #define spi1_plic_IRQHandler PLIC_spi1_IRQHandler #define external_can0_plic_IRQHandler PLIC_external_can0_IRQHandler #define can1_IRQHandler PLIC_can1_IRQHandler #define External_i2c0_main_plic_IRQHandler PLIC_External_i2c0_main_IRQHandler #define External_i2c0_alert_plic_IRQHandler PLIC_External_i2c0_alert_IRQHandler #define i2c0_sus_plic_IRQHandler PLIC_i2c0_sus_IRQHandler #define i2c1_main_plic_IRQHandler PLIC_i2c1_main_IRQHandler #define i2c1_alert_plic_IRQHandler PLIC_i2c1_alert_IRQHandler #define i2c1_sus_plic_IRQHandler PLIC_i2c1_sus_IRQHandler #define mac0_int_plic_IRQHandler PLIC_mac0_int_IRQHandler #define mac0_queue1_plic_IRQHandler PLIC_mac0_queue1_IRQHandler #define mac0_queue2_plic_IRQHandler PLIC_mac0_queue2_IRQHandler #define mac0_queue3_plic_IRQHandler PLIC_mac0_queue3_IRQHandler #define mac0_emac_plic_IRQHandler PLIC_mac0_emac_IRQHandler #define mac0_mmsl_plic_IRQHandler PLIC_mac0_mmsl_IRQHandler #define mac1_int_plic_IRQHandler PLIC_mac1_int_IRQHandler #define mac1_queue1_plic_IRQHandler PLIC_mac1_queue1_IRQHandler #define mac1_queue2_plic_IRQHandler PLIC_mac1_queue2_IRQHandler #define mac1_queue3_plic_IRQHandler PLIC_mac1_queue3_IRQHandler #define mac1_emac_plic_IRQHandler PLIC_mac1_emac_IRQHandler #define mac1_mmsl_plic_IRQHandler PLIC_mac1_mmsl_IRQHandler #define ddrc_train_plic_IRQHandler PLIC_ddrc_train_IRQHandler #define scb_interrupt_plic_IRQHandler PLIC_scb_interrupt_IRQHandler #define ecc_error_plic_IRQHandler PLIC_ecc_error_IRQHandler #define ecc_correct_plic_IRQHandler PLIC_ecc_correct_IRQHandler #define rtc_wakeup_plic_IRQHandler PLIC_rtc_wakeup_IRQHandler #define rtc_match_plic_IRQHandler PLIC_rtc_match_IRQHandler #define timer1_plic_IRQHandler PLIC_timer1_IRQHandler #define timer2_plic_IRQHandler PLIC_timer2_IRQHandler #define envm_plic_IRQHandler PLIC_envm_IRQHandler #define qspi_plic_IRQHandler PLIC_qspi_IRQHandler #define usb_dma_plic_IRQHandler PLIC_usb_dma_IRQHandler #define usb_mc_plic_IRQHandler PLIC_usb_mc_IRQHandler #define mmc_main_plic_IRQHandler PLIC_mmc_main_IRQHandler #define mmc_wakeup_plic_IRQHandler PLIC_mmc_wakeup_IRQHandler #define mmuart0_plic_77_IRQHandler PLIC_mmuart0_IRQHandler #define mmuart1_plic_IRQHandler PLIC_mmuart1_IRQHandler #define mmuart2_plic_IRQHandler PLIC_mmuart2_IRQHandler #define mmuart3_plic_IRQHandler PLIC_mmuart3_IRQHandler #define mmuart4_plic_IRQHandler PLIC_mmuart4_IRQHandler #define g5c_devrst_plic_IRQHandler PLIC_devrst_IRQHandler #define g5c_message_plic_IRQHandler PLIC_g5c_message_IRQHandler #define usoc_vc_interrupt_plic_IRQHandler PLIC_usoc_vc_interrupt_IRQHandler #define usoc_smb_interrupt_plic_IRQHandler PLIC_usoc_smb_interrupt_IRQHandler #define e51_0_Maintence_plic_IRQHandler PLIC_E51_Maintence_IRQHandler #define wdog0_mvrp_plic_IRQHandler PLIC_wdog0_mvrp_IRQHandler #define wdog1_mvrp_plic_IRQHandler PLIC_wdog1_mvrp_IRQHandler #define wdog2_mvrp_plic_IRQHandler PLIC_wdog2_mvrp_IRQHandler #define wdog3_mvrp_plic_IRQHandler PLIC_wdog3_mvrp_IRQHandler #define wdog4_mvrp_plic_IRQHandler PLIC_wdog4_mvrp_IRQHandler #define wdog0_tout_plic_IRQHandler PLIC_wdog0_tout_IRQHandler #define wdog1_tout_plic_IRQHandler PLIC_wdog1_tout_IRQHandler #define wdog2_tout_plic_IRQHandler PLIC_wdog2_tout_IRQHandler #define wdog3_tout_plic_IRQHandler PLIC_wdog3_tout_IRQHandler #define wdog4_tout_plic_IRQHandler PLIC_wdog4_tout_IRQHandler #define g5c_mss_spi_plic_IRQHandler PLIC_g5c_mss_spi_IRQHandler #define volt_temp_alarm_plic_IRQHandler PLIC_volt_temp_alarm_IRQHandler #define athena_complete_plic_IRQHandler PLIC_athena_complete_IRQHandler #define athena_alarm_plic_IRQHandler PLIC_athena_alarm_IRQHandler #define athena_bus_error_plic_IRQHandler PLIC_athena_bus_error_IRQHandler #define usoc_axic_us_plic_IRQHandler PLIC_usoc_axic_us_IRQHandler #define usoc_axic_ds_plic_IRQHandler PLIC_usoc_axic_ds_IRQHandler #define reserved_104_plic_IRQHandler PLIC_reserved_104_IRQHandler #define fabric_f2h_0_plic_IRQHandler PLIC_f2m_0_IRQHandler #define fabric_f2h_1_plic_IRQHandler PLIC_f2m_1_IRQHandler #define fabric_f2h_2_plic_IRQHandler PLIC_f2m_2_IRQHandler #define fabric_f2h_3_plic_IRQHandler PLIC_f2m_3_IRQHandler #define fabric_f2h_4_plic_IRQHandler PLIC_f2m_4_IRQHandler #define fabric_f2h_5_plic_IRQHandler PLIC_f2m_5_IRQHandler #define fabric_f2h_6_plic_IRQHandler PLIC_f2m_6_IRQHandler #define fabric_f2h_7_plic_IRQHandler PLIC_f2m_7_IRQHandler #define fabric_f2h_8_plic_IRQHandler PLIC_f2m_8_IRQHandler #define fabric_f2h_9_plic_IRQHandler PLIC_f2m_9_IRQHandler #define fabric_f2h_10_plic_IRQHandler PLIC_f2m_10_IRQHandler #define fabric_f2h_11_plic_IRQHandler PLIC_f2m_11_IRQHandler #define fabric_f2h_12_plic_IRQHandler PLIC_f2m_12_IRQHandler #define fabric_f2h_13_plic_IRQHandler PLIC_f2m_13_IRQHandler #define fabric_f2h_14_plic_IRQHandler PLIC_f2m_14_IRQHandler #define fabric_f2h_15_plic_IRQHandler PLIC_f2m_15_IRQHandler #define fabric_f2h_16_plic_IRQHandler PLIC_f2m_16_IRQHandler #define fabric_f2h_17_plic_IRQHandler PLIC_f2m_17_IRQHandler #define fabric_f2h_18_plic_IRQHandler PLIC_f2m_18_IRQHandler #define fabric_f2h_19_plic_IRQHandler PLIC_f2m_19_IRQHandler #define fabric_f2h_20_plic_IRQHandler PLIC_f2m_20_IRQHandler #define fabric_f2h_21_plic_IRQHandler PLIC_f2m_21_IRQHandler #define fabric_f2h_22_plic_IRQHandler PLIC_f2m_22_IRQHandler #define fabric_f2h_23_plic_IRQHandler PLIC_f2m_23_IRQHandler #define fabric_f2h_24_plic_IRQHandler PLIC_f2m_24_IRQHandler #define fabric_f2h_25_plic_IRQHandler PLIC_f2m_25_IRQHandler #define fabric_f2h_26_plic_IRQHandler PLIC_f2m_26_IRQHandler #define fabric_f2h_27_plic_IRQHandler PLIC_f2m_27_IRQHandler #define fabric_f2h_28_plic_IRQHandler PLIC_f2m_28_IRQHandler #define fabric_f2h_29_plic_IRQHandler PLIC_f2m_29_IRQHandler #define fabric_f2h_30_plic_IRQHandler PLIC_f2m_30_IRQHandler #define fabric_f2h_31_plic_IRQHandler PLIC_f2m_31_IRQHandler #define fabric_f2h_32_plic_IRQHandler PLIC_f2m_32_IRQHandler #define fabric_f2h_33_plic_IRQHandler PLIC_f2m_33_IRQHandler #define fabric_f2h_34_plic_IRQHandler PLIC_f2m_34_IRQHandler #define fabric_f2h_35_plic_IRQHandler PLIC_f2m_35_IRQHandler #define fabric_f2h_36_plic_IRQHandler PLIC_f2m_36_IRQHandler #define fabric_f2h_37_plic_IRQHandler PLIC_f2m_37_IRQHandler #define fabric_f2h_38_plic_IRQHandler PLIC_f2m_38_IRQHandler #define fabric_f2h_39_plic_IRQHandler PLIC_f2m_39_IRQHandler #define fabric_f2h_40_plic_IRQHandler PLIC_f2m_40_IRQHandler #define fabric_f2h_41_plic_IRQHandler PLIC_f2m_41_IRQHandler #define fabric_f2h_42_plic_IRQHandler PLIC_f2m_42_IRQHandler #define fabric_f2h_43_plic_IRQHandler PLIC_f2m_43_IRQHandler #define fabric_f2h_44_plic_IRQHandler PLIC_f2m_44_IRQHandler #define fabric_f2h_45_plic_IRQHandler PLIC_f2m_45_IRQHandler #define fabric_f2h_46_plic_IRQHandler PLIC_f2m_46_IRQHandler #define fabric_f2h_47_plic_IRQHandler PLIC_f2m_47_IRQHandler #define fabric_f2h_48_plic_IRQHandler PLIC_f2m_48_IRQHandler #define fabric_f2h_49_plic_IRQHandler PLIC_f2m_49_IRQHandler #define fabric_f2h_50_plic_IRQHandler PLIC_f2m_50_IRQHandler #define fabric_f2h_51_plic_IRQHandler PLIC_f2m_51_IRQHandler #define fabric_f2h_52_plic_IRQHandler PLIC_f2m_52_IRQHandler #define fabric_f2h_53_plic_IRQHandler PLIC_f2m_53_IRQHandler #define fabric_f2h_54_plic_IRQHandler PLIC_f2m_54_IRQHandler #define fabric_f2h_55_plic_IRQHandler PLIC_f2m_55_IRQHandler #define fabric_f2h_56_plic_IRQHandler PLIC_f2m_56_IRQHandler #define fabric_f2h_57_plic_IRQHandler PLIC_f2m_57_IRQHandler #define fabric_f2h_58_plic_IRQHandler PLIC_f2m_58_IRQHandler #define fabric_f2h_59_plic_IRQHandler PLIC_f2m_59_IRQHandler #define fabric_f2h_60_plic_IRQHandler PLIC_f2m_60_IRQHandler #define fabric_f2h_61_plic_IRQHandler PLIC_f2m_61_IRQHandler #define fabric_f2h_62_plic_IRQHandler PLIC_f2m_62_IRQHandler #define fabric_f2h_63_plic_IRQHandler PLIC_f2m_63_IRQHandler #define bus_error_unit_hart_0_plic_IRQHandler PLIC_E51_bus_error_unit_hart_0_IRQHandler #define bus_error_unit_hart_1_plic_IRQHandler PLIC_U54_1_bus_error_unit_IRQHandler #define bus_error_unit_hart_2_plic_IRQHandler PLIC_U54_2_bus_error_unit_IRQHandler #define bus_error_unit_hart_3_plic_IRQHandler PLIC_U54_3_bus_error_unit_IRQHandler #define bus_error_unit_hart_4_plic_IRQHandler PLIC_U54_4_bus_error_unit_IRQHandler #define INVALID_IRQn PLIC_INVALID_INT_OFFSET #define L2_METADATA_CORR_IRQn PLIC_L2_METADATA_CORR_INT_OFFSET #define L2_METADAT_UNCORR_IRQn PLIC_L2_METADAT_UNCORR_INT_OFFSET #define L2_DATA_CORR_IRQn PLIC_L2_DATA_CORR_INT_OFFSET #define L2_DATA_UNCORR_IRQn PLIC_L2_DATA_UNCORR_INT_OFFSET #define DMA_CH0_DONE_IRQn PLIC_DMA_CH0_DONE_INT_OFFSET #define DMA_CH0_ERR_IRQn PLIC_DMA_CH0_ERR_INT_OFFSET #define DMA_CH1_DONE_IRQn PLIC_DMA_CH1_DONE_INT_OFFSET #define DMA_CH1_ERR_IRQn PLIC_DMA_CH1_ERR_INT_OFFSET #define DMA_CH2_DONE_IRQn PLIC_DMA_CH2_DONE_INT_OFFSET #define DMA_CH2_ERR_IRQn PLIC_DMA_CH2_ERR_INT_OFFSET #define DMA_CH3_DONE_IRQn PLIC_DMA_CH3_DONE_INT_OFFSET #define DMA_CH3_ERR_IRQn PLIC_DMA_CH3_ERR_INT_OFFSET #define GPIO0_BIT0_or_GPIO2_BIT0_PLIC_0 PLIC_GPIO0_BIT0_or_GPIO2_BIT0_INT_OFFSET #define GPIO0_BIT1_or_GPIO2_BIT1_PLIC_1 PLIC_GPIO0_BIT1_or_GPIO2_BIT1_INT_OFFSET #define GPIO0_BIT2_or_GPIO2_BIT2_PLIC_2 PLIC_GPIO0_BIT2_or_GPIO2_BIT2_INT_OFFSET #define GPIO0_BIT3_or_GPIO2_BIT3_PLIC_3 PLIC_GPIO0_BIT3_or_GPIO2_BIT3_INT_OFFSET #define GPIO0_BIT4_or_GPIO2_BIT4_PLIC_4 PLIC_GPIO0_BIT4_or_GPIO2_BIT4_INT_OFFSET #define GPIO0_BIT5_or_GPIO2_BIT5_PLIC_5 PLIC_GPIO0_BIT5_or_GPIO2_BIT5_INT_OFFSET #define GPIO0_BIT6_or_GPIO2_BIT6_PLIC_6 PLIC_GPIO0_BIT6_or_GPIO2_BIT6_INT_OFFSET #define GPIO0_BIT7_or_GPIO2_BIT7_PLIC_7 PLIC_GPIO0_BIT7_or_GPIO2_BIT7_INT_OFFSET #define GPIO0_BIT8_or_GPIO2_BIT8_PLIC_8 PLIC_GPIO0_BIT8_or_GPIO2_BIT8_INT_OFFSET #define GPIO0_BIT9_or_GPIO2_BIT9_PLIC_9 PLIC_GPIO0_BIT9_or_GPIO2_BIT9_INT_OFFSET #define GPIO0_BIT10_or_GPIO2_BIT10_PLIC_10 PLIC_GPIO0_BIT10_or_GPIO2_BIT10_INT_OFFSET #define GPIO0_BIT11_or_GPIO2_BIT11_PLIC_11 PLIC_GPIO0_BIT11_or_GPIO2_BIT11_INT_OFFSET #define GPIO0_BIT12_or_GPIO2_BIT12_PLIC_12 PLIC_GPIO0_BIT12_or_GPIO2_BIT12_INT_OFFSET #define GPIO0_BIT13_or_GPIO2_BIT13_PLIC_13 PLIC_GPIO0_BIT13_or_GPIO2_BIT13_INT_OFFSET #define GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14 PLIC_GPIO1_BIT0_or_GPIO2_BIT14_INT_OFFSET #define GPIO1_BIT1_or_GPIO2_BIT15_PLIC_15 PLIC_GPIO1_BIT1_or_GPIO2_BIT15_INT_OFFSET #define GPIO1_BIT2_or_GPIO2_BIT16_PLIC_16 PLIC_GPIO1_BIT2_or_GPIO2_BIT16_INT_OFFSET #define GPIO1_BIT3_or_GPIO2_BIT17_PLIC_17 PLIC_GPIO1_BIT3_or_GPIO2_BIT17_INT_OFFSET #define GPIO1_BIT4_or_GPIO2_BIT18_PLIC_18 PLIC_GPIO1_BIT4_or_GPIO2_BIT18_INT_OFFSET #define GPIO1_BIT5_or_GPIO2_BIT19_PLIC_19 PLIC_GPIO1_BIT5_or_GPIO2_BIT19_INT_OFFSET #define GPIO1_BIT6_or_GPIO2_BIT20_PLIC_20 PLIC_GPIO1_BIT6_or_GPIO2_BIT20_INT_OFFSET #define GPIO1_BIT7_or_GPIO2_BIT21_PLIC_21 PLIC_GPIO1_BIT7_or_GPIO2_BIT21_INT_OFFSET #define GPIO1_BIT8_or_GPIO2_BIT22_PLIC_22 PLIC_GPIO1_BIT8_or_GPIO2_BIT22_INT_OFFSET #define GPIO1_BIT9_or_GPIO2_BIT23_PLIC_23 PLIC_GPIO1_BIT9_or_GPIO2_BIT23_INT_OFFSET #define GPIO1_BIT10_or_GPIO2_BIT24_PLIC_24 PLIC_GPIO1_BIT10_or_GPIO2_BIT24_INT_OFFSET #define GPIO1_BIT11_or_GPIO2_BIT25_PLIC_25 PLIC_GPIO1_BIT11_or_GPIO2_BIT25_INT_OFFSET #define GPIO1_BIT12_or_GPIO2_BIT26_PLIC_26 PLIC_GPIO1_BIT12_or_GPIO2_BIT26_INT_OFFSET #define GPIO1_BIT13_or_GPIO2_BIT27_PLIC_27 PLIC_GPIO1_BIT13_or_GPIO2_BIT27_INT_OFFSET #define GPIO1_BIT14_or_GPIO2_BIT28_PLIC_28 PLIC_GPIO1_BIT14_or_GPIO2_BIT28_INT_OFFSET #define GPIO1_BIT15_or_GPIO2_BIT29_PLIC_29 PLIC_GPIO1_BIT15_or_GPIO2_BIT29_INT_OFFSET #define GPIO1_BIT16_or_GPIO2_BIT30_PLIC_30 PLIC_GPIO1_BIT16_or_GPIO2_BIT30_INT_OFFSET #define GPIO1_BIT17_or_GPIO2_BIT31_PLIC_31 PLIC_GPIO1_BIT17_or_GPIO2_BIT31_INT_OFFSET #define GPIO1_BIT18_PLIC_32 PLIC_GPIO1_BIT18_INT_OFFSET #define GPIO1_BIT19_PLIC_33 PLIC_GPIO1_BIT19_INT_OFFSET #define GPIO1_BIT20_PLIC_34 PLIC_GPIO1_BIT20_INT_OFFSET #define GPIO1_BIT21_PLIC_35 PLIC_GPIO1_BIT21_INT_OFFSET #define GPIO1_BIT22_PLIC_36 PLIC_GPIO1_BIT22_INT_OFFSET #define GPIO1_BIT23_PLIC_37 PLIC_GPIO1_BIT23_INT_OFFSET #define GPIO0_NON_DIRECT_PLIC PLIC_GPIO0_NON_DIRECT_INT_OFFSET #define GPIO1_NON_DIRECT_PLIC PLIC_GPIO1_NON_DIRECT_INT_OFFSET #define GPIO2_NON_DIRECT_PLIC PLIC_GPIO2_NON_DIRECT_INT_OFFSET #define SPI0_PLIC PLIC_SPI0_INT_OFFSET #define SPI1_PLIC PLIC_SPI1_INT_OFFSET #define CAN0_PLIC PLIC_CAN0_INT_OFFSET #define CAN1_PLIC PLIC_CAN1_INT_OFFSET #define I2C0_MAIN_PLIC PLIC_I2C0_MAIN_INT_OFFSET #define I2C0_ALERT_PLIC PLIC_I2C0_ALERT_INT_OFFSET #define I2C0_SUS_PLIC PLIC_I2C0_SUS_INT_OFFSET #define I2C1_MAIN_PLIC PLIC_I2C1_MAIN_INT_OFFSET #define I2C1_ALERT_PLIC PLIC_I2C1_ALERT_INT_OFFSET #define I2C1_SUS_PLIC PLIC_I2C1_SUS_INT_OFFSET #define MAC0_INT_PLIC PLIC_MAC0_INT_INT_OFFSET #define MAC0_QUEUE1_PLIC PLIC_MAC0_QUEUE1_INT_OFFSET #define MAC0_QUEUE2_PLIC PLIC_MAC0_QUEUE2_INT_OFFSET #define MAC0_QUEUE3_PLIC PLIC_MAC0_QUEUE3_INT_OFFSET #define MAC0_EMAC_PLIC PLIC_MAC0_EMAC_INT_OFFSET #define MAC0_MMSL_PLIC PLIC_MAC0_MMSL_INT_OFFSET #define MAC1_INT_PLIC PLIC_MAC1_INT_INT_OFFSET #define MAC1_QUEUE1_PLIC PLIC_MAC1_QUEUE1_INT_OFFSET #define MAC1_QUEUE2_PLIC PLIC_MAC1_QUEUE2_INT_OFFSET #define MAC1_QUEUE3_PLIC PLIC_MAC1_QUEUE3_INT_OFFSET #define MAC1_EMAC_PLIC PLIC_MAC1_EMAC_INT_OFFSET #define MAC1_MMSL_PLIC PLIC_MAC1_MMSL_INT_OFFSET #define DDRC_TRAIN_PLIC PLIC_DDRC_TRAIN_INT_OFFSET #define SCB_INTERRUPT_PLIC PLIC_SCB_INTERRUPT_INT_OFFSET #define ECC_ERROR_PLIC PLIC_ECC_ERROR_INT_OFFSET #define ECC_CORRECT_PLIC PLIC_ECC_CORRECT_INT_OFFSET #define RTC_WAKEUP_PLIC PLIC_RTC_WAKEUP_INT_OFFSET #define RTC_MATCH_PLIC PLIC_RTC_MATCH_INT_OFFSET #define TIMER1_PLIC PLIC_TIMER1_INT_OFFSET #define TIMER2_PLIC PLIC_TIMER2_INT_OFFSET #define ENVM_PLIC PLIC_ENVM_INT_OFFSET #define QSPI_PLIC PLIC_QSPI_INT_OFFSET #define USB_DMA_PLIC PLIC_USB_DMA_INT_OFFSET #define USB_MC_PLIC PLIC_USB_MC_INT_OFFSET #define MMC_main_PLIC PLIC_MMC_main_INT_OFFSET #define MMC_wakeup_PLIC PLIC_MMC_wakeup_INT_OFFSET #define MMUART0_PLIC_77 PLIC_MMUART0_INT_OFFSET #define MMUART1_PLIC PLIC_MMUART1_INT_OFFSET #define MMUART2_PLIC PLIC_MMUART2_INT_OFFSET #define MMUART3_PLIC PLIC_MMUART3_INT_OFFSET #define MMUART4_PLIC PLIC_MMUART4_INT_OFFSET #define G5C_DEVRST_PLIC G5C_DEVRST_INT_OFFSET #define g5c_MESSAGE_PLIC g5c_MESSAGE_INT_OFFSET #define USOC_VC_INTERRUPT_PLIC USOC_VC_INTERRUPT_INT_OFFSET #define USOC_SMB_INTERRUPT_PLIC USOC_SMB_INTERRUPT_INT_OFFSET #define E51_0_MAINTENACE_PLIC E51_0_MAINTENACE_INT_OFFSET #define WDOG0_MRVP_PLIC PLIC_WDOG0_MRVP_INT_OFFSET #define WDOG1_MRVP_PLIC PLIC_WDOG1_MRVP_INT_OFFSET #define WDOG2_MRVP_PLIC PLIC_WDOG2_MRVP_INT_OFFSET #define WDOG3_MRVP_PLIC PLIC_WDOG3_MRVP_INT_OFFSET #define WDOG4_MRVP_PLIC PLIC_WDOG4_MRVP_INT_OFFSET #define WDOG0_TOUT_PLIC PLIC_WDOG0_TOUT_INT_OFFSET #define WDOG1_TOUT_PLIC PLIC_WDOG1_TOUT_INT_OFFSET #define WDOG2_TOUT_PLIC PLIC_WDOG2_TOUT_INT_OFFSET #define WDOG3_TOUT_PLIC PLIC_WDOG3_TOUT_INT_OFFSET #define WDOG4_TOUT_PLIC PLIC_WDOG4_TOUT_INT_OFFSET #define G5C_MSS_SPI_PLIC G5C_MSS_SPI_INT_OFFSET #define VOLT_TEMP_ALARM_PLIC VOLT_TEMP_ALARM_INT_OFFSET #define ATHENA_COMPLETE_PLIC ATHENA_COMPLETE_INT_OFFSET #define ATHENA_ALARM_PLIC ATHENA_ALARM_INT_OFFSET #define ATHENA_BUS_ERROR_PLIC ATHENA_BUS_ERROR_INT_OFFSET #define USOC_AXIC_US_PLIC USOC_AXIC_US_INT_OFFSET #define USOC_AXIC_DS_PLIC USOC_AXIC_DS_INT_OFFSET #define FABRIC_F2H_0_PLIC PLIC_F2M_0_INT_OFFSET #define FABRIC_F2H_1_PLIC PLIC_F2M_1_INT_OFFSET #define FABRIC_F2H_2_PLIC PLIC_F2M_2_INT_OFFSET #define FABRIC_F2H_3_PLIC PLIC_F2M_3_INT_OFFSET #define FABRIC_F2H_4_PLIC PLIC_F2M_4_INT_OFFSET #define FABRIC_F2H_5_PLIC PLIC_F2M_5_INT_OFFSET #define FABRIC_F2H_6_PLIC PLIC_F2M_6_INT_OFFSET #define FABRIC_F2H_7_PLIC PLIC_F2M_7_INT_OFFSET #define FABRIC_F2H_8_PLIC PLIC_F2M_8_INT_OFFSET #define FABRIC_F2H_9_PLIC PLIC_F2M_9_INT_OFFSET #define FABRIC_F2H_10_PLIC PLIC_F2M_10_INT_OFFSET #define FABRIC_F2H_11_PLIC PLIC_F2M_11_INT_OFFSET #define FABRIC_F2H_12_PLIC PLIC_F2M_12_INT_OFFSET #define FABRIC_F2H_13_PLIC PLIC_F2M_13_INT_OFFSET #define FABRIC_F2H_14_PLIC PLIC_F2M_14_INT_OFFSET #define FABRIC_F2H_15_PLIC PLIC_F2M_15_INT_OFFSET #define FABRIC_F2H_16_PLIC PLIC_F2M_16_INT_OFFSET #define FABRIC_F2H_17_PLIC PLIC_F2M_17_INT_OFFSET #define FABRIC_F2H_18_PLIC PLIC_F2M_18_INT_OFFSET #define FABRIC_F2H_19_PLIC PLIC_F2M_19_INT_OFFSET #define FABRIC_F2H_20_PLIC PLIC_F2M_20_INT_OFFSET #define FABRIC_F2H_21_PLIC PLIC_F2M_21_INT_OFFSET #define FABRIC_F2H_22_PLIC PLIC_F2M_22_INT_OFFSET #define FABRIC_F2H_23_PLIC PLIC_F2M_23_INT_OFFSET #define FABRIC_F2H_24_PLIC PLIC_F2M_24_INT_OFFSET #define FABRIC_F2H_25_PLIC PLIC_F2M_25_INT_OFFSET #define FABRIC_F2H_26_PLIC PLIC_F2M_26_INT_OFFSET #define FABRIC_F2H_27_PLIC PLIC_F2M_27_INT_OFFSET #define FABRIC_F2H_28_PLIC PLIC_F2M_28_INT_OFFSET #define FABRIC_F2H_29_PLIC PLIC_F2M_29_INT_OFFSET #define FABRIC_F2H_30_PLIC PLIC_F2M_30_INT_OFFSET #define FABRIC_F2H_31_PLIC PLIC_F2M_31_INT_OFFSET #define FABRIC_F2H_32_PLIC PLIC_F2M_32_INT_OFFSET #define FABRIC_F2H_33_PLIC PLIC_F2M_33_INT_OFFSET #define FABRIC_F2H_34_PLIC PLIC_F2M_34_INT_OFFSET #define FABRIC_F2H_35_PLIC PLIC_F2M_35_INT_OFFSET #define FABRIC_F2H_36_PLIC PLIC_F2M_36_INT_OFFSET #define FABRIC_F2H_37_PLIC PLIC_F2M_37_INT_OFFSET #define FABRIC_F2H_38_PLIC PLIC_F2M_38_INT_OFFSET #define FABRIC_F2H_39_PLIC PLIC_F2M_39_INT_OFFSET #define FABRIC_F2H_40_PLIC PLIC_F2M_40_INT_OFFSET #define FABRIC_F2H_41_PLIC PLIC_F2M_41_INT_OFFSET #define FABRIC_F2H_42_PLIC PLIC_F2M_42_INT_OFFSET #define FABRIC_F2H_43_PLIC PLIC_F2M_43_INT_OFFSET #define FABRIC_F2H_44_PLIC PLIC_F2M_44_INT_OFFSET #define FABRIC_F2H_45_PLIC PLIC_F2M_45_INT_OFFSET #define FABRIC_F2H_46_PLIC PLIC_F2M_46_INT_OFFSET #define FABRIC_F2H_47_PLIC PLIC_F2M_47_INT_OFFSET #define FABRIC_F2H_48_PLIC PLIC_F2M_48_INT_OFFSET #define FABRIC_F2H_49_PLIC PLIC_F2M_49_INT_OFFSET #define FABRIC_F2H_50_PLIC PLIC_F2M_50_INT_OFFSET #define FABRIC_F2H_51_PLIC PLIC_F2M_51_INT_OFFSET #define FABRIC_F2H_52_PLIC PLIC_F2M_52_INT_OFFSET #define FABRIC_F2H_53_PLIC PLIC_F2M_53_INT_OFFSET #define FABRIC_F2H_54_PLIC PLIC_F2M_54_INT_OFFSET #define FABRIC_F2H_55_PLIC PLIC_F2M_55_INT_OFFSET #define FABRIC_F2H_56_PLIC PLIC_F2M_56_INT_OFFSET #define FABRIC_F2H_57_PLIC PLIC_F2M_57_INT_OFFSET #define FABRIC_F2H_58_PLIC PLIC_F2M_58_INT_OFFSET #define FABRIC_F2H_59_PLIC PLIC_F2M_59_INT_OFFSET #define FABRIC_F2H_60_PLIC PLIC_F2M_60_INT_OFFSET #define FABRIC_F2H_61_PLIC PLIC_F2M_61_INT_OFFSET #define FABRIC_F2H_62_PLIC PLIC_F2M_62_INT_OFFSET #define FABRIC_F2H_63_PLIC PLIC_F2M_63_INT_OFFSET #define BUS_ERROR_UNIT_HART_0 PLIC_E51_BUS_ERROR_UNIT_OFFSET #define BUS_ERROR_UNIT_HART_1 PLIC_U54_1_BUS_ERROR_UNIT_OFFSET #define BUS_ERROR_UNIT_HART_2 PLIC_U54_2_BUS_ERROR_UNIT_OFFSET #define BUS_ERROR_UNIT_HART_3 PLIC_U54_3_BUS_ERROR_UNIT_OFFSET #define BUS_ERROR_UNIT_HART_4 PLIC_U54_4_BUS_ERROR_UNIT_OFFSET #define Software_h0_IRQHandler E51_software_IRQHandler #define Software_h1_IRQHandler U54_1_software_IRQHandler #define Software_h2_IRQHandler U54_2_software_IRQHandler #define Software_h3_IRQHandler U54_3_software_IRQHandler #define Software_h4_IRQHandler U54_4_software_IRQHandler #define SysTick_Handler_h0_IRQHandler E51_sysTick_IRQHandler #define SysTick_Handler_h1_IRQHandler U54_1_sysTick_IRQHandler #define SysTick_Handler_h2_IRQHandler U54_2_sysTick_IRQHandler #define SysTick_Handler_h3_IRQHandler U54_3_sysTick_IRQHandler #define SysTick_Handler_h4_IRQHandler U54_4_sysTick_IRQHandler #ifdef __cplusplus } #endif #endif /* MSS_HART_INTS_H */ mss_mpu.c000066400000000000000000000222041432224323300357030ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_mpu.c * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS MPU driver for configuring access regions for the * external masters. * */ /*=========================================================================*//** *//*=========================================================================*/ #include #include #include "mpfs_hal/mss_hal.h" static uint64_t pmp_get_napot_base_and_range(uint64_t reg, uint64_t *range); uint8_t num_pmp_lut[10U] = {16U,16U,8U,4U,8U,8U,4U,4U,8U,2U}; /** * \brief MPU configuration from Libero for FIC0 * */ const uint64_t mpu_fic0_values[] = { LIBERO_SETTING_FIC0_MPU_CFG_PMP0, LIBERO_SETTING_FIC0_MPU_CFG_PMP1, LIBERO_SETTING_FIC0_MPU_CFG_PMP2, LIBERO_SETTING_FIC0_MPU_CFG_PMP3, LIBERO_SETTING_FIC0_MPU_CFG_PMP4, LIBERO_SETTING_FIC0_MPU_CFG_PMP5, LIBERO_SETTING_FIC0_MPU_CFG_PMP6, LIBERO_SETTING_FIC0_MPU_CFG_PMP7, LIBERO_SETTING_FIC0_MPU_CFG_PMP8, LIBERO_SETTING_FIC0_MPU_CFG_PMP9, LIBERO_SETTING_FIC0_MPU_CFG_PMP10, LIBERO_SETTING_FIC0_MPU_CFG_PMP11, LIBERO_SETTING_FIC0_MPU_CFG_PMP12, LIBERO_SETTING_FIC0_MPU_CFG_PMP13, LIBERO_SETTING_FIC0_MPU_CFG_PMP14, LIBERO_SETTING_FIC0_MPU_CFG_PMP15 }; /** * \brief MPU configuration from Libero for FIC1 * */ const uint64_t mpu_fic1_values[] = { LIBERO_SETTING_FIC1_MPU_CFG_PMP0, LIBERO_SETTING_FIC1_MPU_CFG_PMP1, LIBERO_SETTING_FIC1_MPU_CFG_PMP2, LIBERO_SETTING_FIC1_MPU_CFG_PMP3, LIBERO_SETTING_FIC1_MPU_CFG_PMP4, LIBERO_SETTING_FIC1_MPU_CFG_PMP5, LIBERO_SETTING_FIC1_MPU_CFG_PMP6, LIBERO_SETTING_FIC1_MPU_CFG_PMP7, LIBERO_SETTING_FIC1_MPU_CFG_PMP8, LIBERO_SETTING_FIC1_MPU_CFG_PMP9, LIBERO_SETTING_FIC1_MPU_CFG_PMP10, LIBERO_SETTING_FIC1_MPU_CFG_PMP11, LIBERO_SETTING_FIC1_MPU_CFG_PMP12, LIBERO_SETTING_FIC1_MPU_CFG_PMP13, LIBERO_SETTING_FIC1_MPU_CFG_PMP14, LIBERO_SETTING_FIC1_MPU_CFG_PMP15 }; /** * \brief MPU configuration from Libero for FIC2 * */ const uint64_t mpu_fic2_values[] = { LIBERO_SETTING_FIC2_MPU_CFG_PMP0, LIBERO_SETTING_FIC2_MPU_CFG_PMP1, LIBERO_SETTING_FIC2_MPU_CFG_PMP2, LIBERO_SETTING_FIC2_MPU_CFG_PMP3, LIBERO_SETTING_FIC2_MPU_CFG_PMP4, LIBERO_SETTING_FIC2_MPU_CFG_PMP5, LIBERO_SETTING_FIC2_MPU_CFG_PMP6, LIBERO_SETTING_FIC2_MPU_CFG_PMP7, }; /** * \brief MPU configuration from Libero for ATHENA * */ const uint64_t mpu_crypto_values[] = { LIBERO_SETTING_CRYPTO_MPU_CFG_PMP0, LIBERO_SETTING_CRYPTO_MPU_CFG_PMP1, LIBERO_SETTING_CRYPTO_MPU_CFG_PMP2, LIBERO_SETTING_CRYPTO_MPU_CFG_PMP3, }; /** * \brief MPU configuration from Libero for GEM0 * */ const uint64_t mpu_gem0_values[] = { LIBERO_SETTING_GEM0_MPU_CFG_PMP0, LIBERO_SETTING_GEM0_MPU_CFG_PMP1, LIBERO_SETTING_GEM0_MPU_CFG_PMP2, LIBERO_SETTING_GEM0_MPU_CFG_PMP3, LIBERO_SETTING_GEM0_MPU_CFG_PMP4, LIBERO_SETTING_GEM0_MPU_CFG_PMP5, LIBERO_SETTING_GEM0_MPU_CFG_PMP6, LIBERO_SETTING_GEM0_MPU_CFG_PMP7, }; /** * \brief MPU configuration from Libero for GEM1 * */ const uint64_t mpu_gem1_values[] = { LIBERO_SETTING_GEM1_MPU_CFG_PMP0, LIBERO_SETTING_GEM1_MPU_CFG_PMP1, LIBERO_SETTING_GEM1_MPU_CFG_PMP2, LIBERO_SETTING_GEM1_MPU_CFG_PMP3, LIBERO_SETTING_GEM1_MPU_CFG_PMP4, LIBERO_SETTING_GEM1_MPU_CFG_PMP5, LIBERO_SETTING_GEM1_MPU_CFG_PMP6, LIBERO_SETTING_GEM1_MPU_CFG_PMP7, }; /** * \brief MPU configuration from Libero for MMC * */ const uint64_t mpu_mmc_values[] = { LIBERO_SETTING_MMC_MPU_CFG_PMP0, LIBERO_SETTING_MMC_MPU_CFG_PMP1, LIBERO_SETTING_MMC_MPU_CFG_PMP2, LIBERO_SETTING_MMC_MPU_CFG_PMP3, }; /** * \brief MPU configuration from Libero for SCB * */ const uint64_t mpu_scb_values[] = { LIBERO_SETTING_SCB_MPU_CFG_PMP0, LIBERO_SETTING_SCB_MPU_CFG_PMP1, LIBERO_SETTING_SCB_MPU_CFG_PMP2, LIBERO_SETTING_SCB_MPU_CFG_PMP3, LIBERO_SETTING_SCB_MPU_CFG_PMP4, LIBERO_SETTING_SCB_MPU_CFG_PMP5, LIBERO_SETTING_SCB_MPU_CFG_PMP6, LIBERO_SETTING_SCB_MPU_CFG_PMP7, }; /** * \brief MPU configuration from Libero for USB * */ const uint64_t mpu_usb_values[] = { LIBERO_SETTING_USB_MPU_CFG_PMP0, LIBERO_SETTING_USB_MPU_CFG_PMP1, LIBERO_SETTING_USB_MPU_CFG_PMP2, LIBERO_SETTING_USB_MPU_CFG_PMP3, }; /** * \brief MPU configuration from Libero for TRACE * */ const uint64_t mpu_trace_values[] = { LIBERO_SETTING_TRACE_MPU_CFG_PMP0, LIBERO_SETTING_TRACE_MPU_CFG_PMP1, }; /***************************************************************************//** * MSS_MPU_auto_configure() * Set MPU's up with configuration from Libero * * * @return */ uint8_t mpu_configure(void) { config_64_copy((void *)(&(MSS_MPU(MSS_MPU_FIC0)->PMPCFG)), &(mpu_fic0_values), sizeof(mpu_fic0_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_FIC1)->PMPCFG)), &(mpu_fic1_values), sizeof(mpu_fic1_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_FIC2)->PMPCFG)), &(mpu_fic2_values), sizeof(mpu_fic2_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_CRYPTO)->PMPCFG)), &(mpu_crypto_values), sizeof(mpu_crypto_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_GEM0)->PMPCFG)), &(mpu_gem0_values), sizeof(mpu_gem0_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_GEM1)->PMPCFG)), &(mpu_gem1_values), sizeof(mpu_gem1_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_USB)->PMPCFG)), &(mpu_usb_values), sizeof(mpu_usb_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_MMC)->PMPCFG)), &(mpu_mmc_values), sizeof(mpu_mmc_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_SCB)->PMPCFG)), &(mpu_scb_values), sizeof(mpu_scb_values)); config_64_copy((void *)(&(MSS_MPU(MSS_MPU_TRACE)->PMPCFG)), &(mpu_trace_values), sizeof(mpu_trace_values)); return(0); } /***************************************************************************//** */ uint8_t MSS_MPU_configure(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region, uint64_t base, uint64_t size, uint8_t permission, mss_mpu_addrm_t matching_mode, uint8_t lock_en) { uint64_t temp = size, cnt=0ULL; uint64_t range; /*size must be minimum 4k Size must be power of 2 different masters have different number of regions*/ if((size >= 4096ULL) && (0U == (size & (size - 1U))) && (pmp_region < num_pmp_lut[master_port])) { while((0 == (temp & 0x01U))) { cnt++; temp >>= 1U; } range = (1ULL << (cnt-1U))-1U; MSS_MPU(master_port)->PMPCFG[pmp_region].raw = (base | range) >> 2U; MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode = (uint8_t)(permission | (uint8_t)(matching_mode << 3U) | (lock_en << 0x7U)); return ((uint8_t)0); } else { return ((uint8_t)1); } } uint8_t MSS_MPU_get_config(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region, uint64_t* base, uint64_t* size, uint8_t* permission, mss_mpu_addrm_t* matching_mode, uint8_t* lock_en) { uint64_t reg; /*All AXI external masters dont have same number of PMP regions*/ if(pmp_region < num_pmp_lut[master_port]) { reg = MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.pmp; *base = pmp_get_napot_base_and_range(reg, size); reg = MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode; *lock_en = ( reg >> 0x7U) & 0x1U; *matching_mode = (mss_mpu_addrm_t)( (reg >> 3ULL) & 0x3U); *permission = reg & 0x7U; return ((uint8_t)0); } else { return ((uint8_t)1); } } static uint64_t pmp_get_napot_base_and_range(uint64_t reg, uint64_t *range) { /* construct a mask of all bits bar the top bit */ uint64_t mask = 0U; uint64_t base = reg; uint64_t numbits = (sizeof(uint64_t) * 8U) + 2U; mask = (mask - 1U) >> 1U; while (mask) { if ((reg & mask) == mask) { /* this is the mask to use */ base = reg & ~mask; break; } mask >>= 1U; numbits--; } *range = (1LU << numbits); return (base << 2U); } mss_mpu.h000066400000000000000000000121411432224323300357070ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_mpu.h * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS MPU driver APIs for configuring access regions for * the external masters. * */ /*=========================================================================*//** *//*=========================================================================*/ #ifndef MSS_MPU_H #define MSS_MPU_H #include #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** */ #define MPU_MODE_READ_ACCESS (1U << 0U) #define MPU_MODE_WRITE_ACCESS (1U << 1U) #define MPU_MODE_EXEC_ACCESS (1U << 2U) typedef enum { MSS_MPU_FIC0 = 0x00, MSS_MPU_FIC1, MSS_MPU_FIC2, MSS_MPU_CRYPTO, MSS_MPU_GEM0, MSS_MPU_GEM1, MSS_MPU_USB, MSS_MPU_MMC, MSS_MPU_SCB, MSS_MPU_TRACE, MSS_MPU_SEG0, MSS_MPU_SEG1, } mss_mpu_mport_t; typedef enum { MSS_MPU_AM_OFF = 0x00U, MSS_MPU_AM_NAPOT = 0x03U, } mss_mpu_addrm_t; typedef enum { MSS_MPU_PMP_REGION0 = 0x00, MSS_MPU_PMP_REGION1, MSS_MPU_PMP_REGION2, MSS_MPU_PMP_REGION3, MSS_MPU_PMP_REGION4, MSS_MPU_PMP_REGION5, MSS_MPU_PMP_REGION6, MSS_MPU_PMP_REGION7, MSS_MPU_PMP_REGION8, MSS_MPU_PMP_REGION9, MSS_MPU_PMP_REGION10, MSS_MPU_PMP_REGION11, MSS_MPU_PMP_REGION12, MSS_MPU_PMP_REGION13, MSS_MPU_PMP_REGION14, MSS_MPU_PMP_REGION15, } mss_mpu_pmp_region_t; extern uint8_t num_pmp_lut[10]; #ifndef __I #define __I const volatile #endif #ifndef __IO #define __IO volatile #endif #ifndef __O #define __O volatile #endif typedef struct { union { struct { __IO uint64_t pmp : 38; __IO uint64_t rsrvd : 18; __IO uint64_t mode : 8; } MPUCFG_TypeDef; uint64_t raw; }; } MPU_CFG; typedef struct { __IO uint64_t addr : 38; __IO uint64_t rw : 1; __IO uint64_t id : 4; __IO uint64_t failed : 1; __IO uint64_t padding : (64-44); } MPU_FailStatus_TypeDef; typedef struct { MPU_CFG PMPCFG[16U]; __IO MPU_FailStatus_TypeDef STATUS; } MPU_TypeDef; #define MSS_MPU(master) ( (MPU_TypeDef*) (0x20005000UL + ((master) << 8U))) uint8_t mpu_configure(void); uint8_t MSS_MPU_configure(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region, uint64_t base, uint64_t size, uint8_t permission, mss_mpu_addrm_t matching_mode, uint8_t lock_en); uint8_t MSS_MPU_get_config(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region, uint64_t* base, uint64_t* size, uint8_t* permission, mss_mpu_addrm_t* matching_mode, uint8_t* lock_en); static inline uint8_t MSS_MPU_lock_region(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region) { if(pmp_region < num_pmp_lut[master_port]) { MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode |= (0x1U << 7U); return (0U); } else { return (1U); } } /*permission value could be bitwise or of: * MPU_MODE_READ_ACCESS * MPU_MODE_WRITE_ACCESS * MPU_MODE_EXEC_ACCESS * * */ static inline uint8_t MSS_MPU_set_permission(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region, uint8_t permission) { if(pmp_region < num_pmp_lut[master_port]) { MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode |= permission; return (0U); } else { return (1U); } } static inline uint8_t MSS_MPU_get_permission(mss_mpu_mport_t master_port, mss_mpu_pmp_region_t pmp_region, uint8_t* permission) { if(pmp_region < num_pmp_lut[master_port]) { *permission = MSS_MPU(master_port)->PMPCFG[pmp_region].MPUCFG_TypeDef.mode & 0x7U; return (0U); } else { return (1U); } } /*read the Fail status register when there is a MPU access failure. See the return type MPU_FailStatus_TypeDef for the details of the STATUS bitfield. The status failed bit(offset 42) needs to be reset using the corresponding bit in SYSREG->mpu_violation_sr */ static inline MPU_FailStatus_TypeDef MSS_MPU_get_failstatus(mss_mpu_mport_t master_port) { return (MSS_MPU(master_port)->STATUS); } #ifdef __cplusplus } #endif #endif /* MSS_MPU_H */ mss_mtrap.c000066400000000000000000000471561432224323300362420ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*************************************************************************** * * @file mss_mtrap.c * @author Microchip-FPGA Embedded Systems Solutions * @brief trap functions * */ #include "mpfs_hal/mss_hal.h" #ifdef __cplusplus extern "C" { #endif void handle_local_interrupt(uint8_t interrupt_no); void handle_m_soft_interrupt(void); void handle_m_timer_interrupt(void); void illegal_insn_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc); void misaligned_store_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc); void misaligned_load_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc); void pmp_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc); void trap_from_machine_mode(uintptr_t * regs, uintptr_t dummy, uintptr_t mepc); void bad_trap(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc); void bad_trap(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc) { (void)regs; (void)dummy; (void)mepc; while(1) { } } void misaligned_store_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc) { (void)regs; (void)mcause; (void)mepc; while(1) { } } void misaligned_load_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc) { (void)regs; (void)mcause; (void)mepc; while(1) { } } void illegal_insn_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc) { (void)regs; (void)mcause; (void)mepc; while(1) { } } void pmp_trap(uintptr_t * regs, uintptr_t mcause, uintptr_t mepc) { (void)regs; (void)mcause; (void)mepc; while(1) { } } /*------------------------------------------------------------------------------ * RISC-V interrupt handler for external interrupts. */ uint8_t (*ext_irq_handler_table[PLIC_NUM_SOURCES])(void) = { PLIC_Invalid_IRQHandler, PLIC_l2_metadata_corr_IRQHandler, PLIC_l2_metadata_uncorr_IRQHandler, PLIC_l2_data_corr_IRQHandler, PLIC_l2_data_uncorr_IRQHandler, PLIC_dma_ch0_DONE_IRQHandler, PLIC_dma_ch0_ERR_IRQHandler, PLIC_dma_ch1_DONE_IRQHandler, PLIC_dma_ch1_ERR_IRQHandler, PLIC_dma_ch2_DONE_IRQHandler, PLIC_dma_ch2_ERR_IRQHandler, PLIC_dma_ch3_DONE_IRQHandler, PLIC_dma_ch3_ERR_IRQHandler, PLIC_gpio0_bit0_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit1_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit2_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit3_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit4_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit5_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit6_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit7_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit8_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit9_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit10_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit11_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit12_or_gpio2_bit13_IRQHandler, PLIC_gpio0_bit13_or_gpio2_bit13_IRQHandler, PLIC_gpio1_bit0_or_gpio2_bit14_IRQHandler, PLIC_gpio1_bit1_or_gpio2_bit15_IRQHandler, PLIC_gpio1_bit2_or_gpio2_bit16_IRQHandler, PLIC_gpio1_bit3_or_gpio2_bit17_IRQHandler, PLIC_gpio1_bit4_or_gpio2_bit18_IRQHandler, PLIC_gpio1_bit5_or_gpio2_bit19_IRQHandler, PLIC_gpio1_bit6_or_gpio2_bit20_IRQHandler, PLIC_gpio1_bit7_or_gpio2_bit21_IRQHandler, PLIC_gpio1_bit8_or_gpio2_bit22_IRQHandler, PLIC_gpio1_bit9_or_gpio2_bit23_IRQHandler, PLIC_gpio1_bit10_or_gpio2_bit24_IRQHandler, PLIC_gpio1_bit11_or_gpio2_bit25_IRQHandler, PLIC_gpio1_bit12_or_gpio2_bit26_IRQHandler, PLIC_gpio1_bit13_or_gpio2_bit27_IRQHandler, PLIC_gpio1_bit14_or_gpio2_bit28_IRQHandler, PLIC_gpio1_bit15_or_gpio2_bit29_IRQHandler, PLIC_gpio1_bit16_or_gpio2_bit30_IRQHandler, PLIC_gpio1_bit17_or_gpio2_bit31_IRQHandler, PLIC_gpio1_bit18_IRQHandler, PLIC_gpio1_bit19_IRQHandler, PLIC_gpio1_bit20_IRQHandler, PLIC_gpio1_bit21_IRQHandler, PLIC_gpio1_bit22_IRQHandler, PLIC_gpio1_bit23_IRQHandler, PLIC_gpio0_non_direct_IRQHandler, PLIC_gpio1_non_direct_IRQHandler, PLIC_gpio2_non_direct_IRQHandler, PLIC_spi0_IRQHandler, PLIC_spi1_IRQHandler, PLIC_external_can0_IRQHandler, PLIC_can1_IRQHandler, PLIC_External_i2c0_main_IRQHandler, PLIC_External_i2c0_alert_IRQHandler, PLIC_i2c0_sus_IRQHandler, PLIC_i2c1_main_IRQHandler, PLIC_i2c1_alert_IRQHandler, PLIC_i2c1_sus_IRQHandler, PLIC_mac0_int_IRQHandler, PLIC_mac0_queue1_IRQHandler, PLIC_mac0_queue2_IRQHandler, PLIC_mac0_queue3_IRQHandler, PLIC_mac0_emac_IRQHandler, PLIC_mac0_mmsl_IRQHandler, PLIC_mac1_int_IRQHandler, PLIC_mac1_queue1_IRQHandler, PLIC_mac1_queue2_IRQHandler, PLIC_mac1_queue3_IRQHandler, PLIC_mac1_emac_IRQHandler, PLIC_mac1_mmsl_IRQHandler, PLIC_ddrc_train_IRQHandler, PLIC_scb_interrupt_IRQHandler, PLIC_ecc_error_IRQHandler, PLIC_ecc_correct_IRQHandler, PLIC_rtc_wakeup_IRQHandler, PLIC_rtc_match_IRQHandler, PLIC_timer1_IRQHandler, PLIC_timer2_IRQHandler, PLIC_envm_IRQHandler, PLIC_qspi_IRQHandler, PLIC_usb_dma_IRQHandler, PLIC_usb_mc_IRQHandler, PLIC_mmc_main_IRQHandler, PLIC_mmc_wakeup_IRQHandler, PLIC_mmuart0_IRQHandler, PLIC_mmuart1_IRQHandler, PLIC_mmuart2_IRQHandler, PLIC_mmuart3_IRQHandler, PLIC_mmuart4_IRQHandler, PLIC_devrst_IRQHandler, PLIC_g5c_message_IRQHandler, PLIC_usoc_vc_interrupt_IRQHandler, PLIC_usoc_smb_interrupt_IRQHandler, PLIC_E51_Maintence_IRQHandler, PLIC_wdog0_mvrp_IRQHandler, PLIC_wdog1_mvrp_IRQHandler, /*100 contains multiple interrupts- */ PLIC_wdog2_mvrp_IRQHandler, PLIC_wdog3_mvrp_IRQHandler, PLIC_wdog4_mvrp_IRQHandler, PLIC_wdog0_tout_IRQHandler, PLIC_wdog1_tout_IRQHandler, PLIC_wdog2_tout_IRQHandler, PLIC_wdog3_tout_IRQHandler, PLIC_wdog4_tout_IRQHandler, PLIC_g5c_mss_spi_IRQHandler, PLIC_volt_temp_alarm_IRQHandler, PLIC_athena_complete_IRQHandler, PLIC_athena_alarm_IRQHandler, PLIC_athena_bus_error_IRQHandler, PLIC_usoc_axic_us_IRQHandler, PLIC_usoc_axic_ds_IRQHandler, PLIC_reserved_104_IRQHandler, PLIC_f2m_0_IRQHandler, PLIC_f2m_1_IRQHandler, PLIC_f2m_2_IRQHandler, PLIC_f2m_3_IRQHandler, PLIC_f2m_4_IRQHandler, PLIC_f2m_5_IRQHandler, PLIC_f2m_6_IRQHandler, PLIC_f2m_7_IRQHandler, PLIC_f2m_8_IRQHandler, PLIC_f2m_9_IRQHandler, PLIC_f2m_10_IRQHandler, PLIC_f2m_11_IRQHandler, PLIC_f2m_12_IRQHandler, PLIC_f2m_13_IRQHandler, PLIC_f2m_14_IRQHandler, PLIC_f2m_15_IRQHandler, PLIC_f2m_16_IRQHandler, PLIC_f2m_17_IRQHandler, PLIC_f2m_18_IRQHandler, PLIC_f2m_19_IRQHandler, PLIC_f2m_20_IRQHandler, PLIC_f2m_21_IRQHandler, PLIC_f2m_22_IRQHandler, PLIC_f2m_23_IRQHandler, PLIC_f2m_24_IRQHandler, PLIC_f2m_25_IRQHandler, PLIC_f2m_26_IRQHandler, PLIC_f2m_27_IRQHandler, PLIC_f2m_28_IRQHandler, PLIC_f2m_29_IRQHandler, PLIC_f2m_30_IRQHandler, PLIC_f2m_31_IRQHandler, PLIC_f2m_32_IRQHandler, PLIC_f2m_33_IRQHandler, PLIC_f2m_34_IRQHandler, PLIC_f2m_35_IRQHandler, PLIC_f2m_36_IRQHandler, PLIC_f2m_37_IRQHandler, PLIC_f2m_38_IRQHandler, PLIC_f2m_39_IRQHandler, PLIC_f2m_40_IRQHandler, PLIC_f2m_41_IRQHandler, PLIC_f2m_42_IRQHandler, PLIC_f2m_43_IRQHandler, PLIC_f2m_44_IRQHandler, PLIC_f2m_45_IRQHandler, PLIC_f2m_46_IRQHandler, PLIC_f2m_47_IRQHandler, PLIC_f2m_48_IRQHandler, PLIC_f2m_49_IRQHandler, PLIC_f2m_50_IRQHandler, PLIC_f2m_51_IRQHandler, PLIC_f2m_52_IRQHandler, PLIC_f2m_53_IRQHandler, PLIC_f2m_54_IRQHandler, PLIC_f2m_55_IRQHandler, PLIC_f2m_56_IRQHandler, PLIC_f2m_57_IRQHandler, PLIC_f2m_58_IRQHandler, PLIC_f2m_59_IRQHandler, PLIC_f2m_60_IRQHandler, PLIC_f2m_61_IRQHandler, PLIC_f2m_62_IRQHandler, PLIC_f2m_63_IRQHandler, PLIC_E51_bus_error_unit_IRQHandler, PLIC_U54_1_bus_error_unit_IRQHandler, PLIC_U54_2_bus_error_unit_IRQHandler, PLIC_U54_3_bus_error_unit_IRQHandler, PLIC_U54_4_bus_error_unit_IRQHandler }; #define E51_LOCAL_NUM_SOURCES 48U void (*E51_local_irq_handler_table[E51_LOCAL_NUM_SOURCES])(void) = { E51_maintenance_local_IRQHandler, /* reference multiple interrupts */ E51_usoc_smb_local_IRQHandler, E51_usoc_vc_local_IRQHandler, E51_g5c_message_local_IRQHandler, E51_g5c_devrst_local_IRQHandler, E51_wdog4_tout_local_IRQHandler, E51_wdog3_tout_local_IRQHandler, E51_wdog2_tout_local_IRQHandler, E51_wdog1_tout_local_IRQHandler, E51_wdog0_tout_local_IRQHandler, E51_wdog0_mvrp_local_IRQHandler, E51_mmuart0_local_IRQHandler, E51_envm_local_IRQHandler, E51_ecc_correct_local_IRQHandler, E51_ecc_error_local_IRQHandler, E51_scb_local_IRQHandler, E51_f2m_32_local_IRQHandler, E51_f2m_33_local_IRQHandler, E51_f2m_34_local_IRQHandler, E51_f2m_35_local_IRQHandler, E51_f2m_36_local_IRQHandler, E51_f2m_37_local_IRQHandler, E51_f2m_38_local_IRQHandler, E51_f2m_39_local_IRQHandler, E51_f2m_40_local_IRQHandler, E51_f2m_41_local_IRQHandler, E51_f2m_42_local_IRQHandler, E51_f2m_43_local_IRQHandler, E51_f2m_44_local_IRQHandler, E51_f2m_45_local_IRQHandler, E51_f2m_46_local_IRQHandler, E51_f2m_47_local_IRQHandler, E51_f2m_48_local_IRQHandler, E51_f2m_49_local_IRQHandler, E51_f2m_50_local_IRQHandler, E51_f2m_51_local_IRQHandler, E51_f2m_52_local_IRQHandler, E51_f2m_53_local_IRQHandler, E51_f2m_54_local_IRQHandler, E51_f2m_55_local_IRQHandler, E51_f2m_56_local_IRQHandler, E51_f2m_57_local_IRQHandler, E51_f2m_58_local_IRQHandler, E51_f2m_59_local_IRQHandler, E51_f2m_60_local_IRQHandler, E51_f2m_61_local_IRQHandler, E51_f2m_62_local_IRQHandler, E51_f2m_63_local_IRQHandler }; typedef void (*local_int_p_t)(void); /* U54 1 */ local_int_p_t local_irq_handler_1_table[E51_LOCAL_NUM_SOURCES] = { /*reference multiple interrupts*/ U54_spare_0_local_IRQHandler, U54_spare_1_local_IRQHandler, U54_spare_2_local_IRQHandler, /*parse hart ID to discover which mac is the source*/ U54_1_mac0_mmsl_local_IRQHandler, U54_1_mac0_emac_local_IRQHandler, U54_1_mac0_queue3_local_IRQHandler, U54_1_mac0_queue2_local_IRQHandler, U54_1_mac0_queue1_local_IRQHandler, U54_1_mac0_int_local_IRQHandler, /*parse hart ID to discover which wdog is the source*/ U54_1_wdog_tout_local_IRQHandler, U54_1_wdog_mvrp_local_IRQHandler, U54_1_mmuart1_local_IRQHandler, U54_spare_3_local_IRQHandler, U54_spare_4_local_IRQHandler, U54_spare_5_local_IRQHandler, U54_spare_6_local_IRQHandler, U54_f2m_0_local_IRQHandler, U54_f2m_1_local_IRQHandler, U54_f2m_2_local_IRQHandler, U54_f2m_3_local_IRQHandler, U54_f2m_4_local_IRQHandler, U54_f2m_5_local_IRQHandler, U54_f2m_6_local_IRQHandler, U54_f2m_7_local_IRQHandler, U54_f2m_8_local_IRQHandler, U54_f2m_9_local_IRQHandler, U54_f2m_10_local_IRQHandler, U54_f2m_11_local_IRQHandler, U54_f2m_12_local_IRQHandler, U54_f2m_13_local_IRQHandler, U54_f2m_14_local_IRQHandler, U54_f2m_15_local_IRQHandler, U54_f2m_16_local_IRQHandler, U54_f2m_17_local_IRQHandler, U54_f2m_18_local_IRQHandler, U54_f2m_19_local_IRQHandler, U54_f2m_20_local_IRQHandler, U54_f2m_21_local_IRQHandler, U54_f2m_22_local_IRQHandler, U54_f2m_23_local_IRQHandler, U54_f2m_24_local_IRQHandler, U54_f2m_25_local_IRQHandler, U54_f2m_26_local_IRQHandler, U54_f2m_27_local_IRQHandler, U54_f2m_28_local_IRQHandler, U54_f2m_29_local_IRQHandler, U54_f2m_30_local_IRQHandler, U54_f2m_31_local_IRQHandler }; /* U54 2 */ local_int_p_t local_irq_handler_2_table[E51_LOCAL_NUM_SOURCES] = { /*reference multiple interrupts*/ U54_spare_0_local_IRQHandler, U54_spare_1_local_IRQHandler, U54_spare_2_local_IRQHandler, /*parse hart ID to discover which mac is the source*/ U54_2_mac0_mmsl_local_IRQHandler, U54_2_mac0_emac_local_IRQHandler, U54_2_mac0_queue3_local_IRQHandler, U54_2_mac0_queue2_local_IRQHandler, U54_2_mac0_queue1_local_IRQHandler, U54_2_mac0_int_local_IRQHandler, /*parse hart ID to discover which wdog is the source*/ U54_2_wdog_tout_local_IRQHandler, U54_2_wdog_mvrp_local_IRQHandler, U54_2_mmuart2_local_IRQHandler, U54_spare_3_local_IRQHandler, U54_spare_4_local_IRQHandler, U54_spare_5_local_IRQHandler, U54_spare_6_local_IRQHandler, U54_f2m_0_local_IRQHandler, U54_f2m_1_local_IRQHandler, U54_f2m_2_local_IRQHandler, U54_f2m_3_local_IRQHandler, U54_f2m_4_local_IRQHandler, U54_f2m_5_local_IRQHandler, U54_f2m_6_local_IRQHandler, U54_f2m_7_local_IRQHandler, U54_f2m_8_local_IRQHandler, U54_f2m_9_local_IRQHandler, U54_f2m_10_local_IRQHandler, U54_f2m_11_local_IRQHandler, U54_f2m_12_local_IRQHandler, U54_f2m_13_local_IRQHandler, U54_f2m_14_local_IRQHandler, U54_f2m_15_local_IRQHandler, U54_f2m_16_local_IRQHandler, U54_f2m_17_local_IRQHandler, U54_f2m_18_local_IRQHandler, U54_f2m_19_local_IRQHandler, U54_f2m_20_local_IRQHandler, U54_f2m_21_local_IRQHandler, U54_f2m_22_local_IRQHandler, U54_f2m_23_local_IRQHandler, U54_f2m_24_local_IRQHandler, U54_f2m_25_local_IRQHandler, U54_f2m_26_local_IRQHandler, U54_f2m_27_local_IRQHandler, U54_f2m_28_local_IRQHandler, U54_f2m_29_local_IRQHandler, U54_f2m_30_local_IRQHandler, U54_f2m_31_local_IRQHandler }; /* U54 3 */ local_int_p_t local_irq_handler_3_table[E51_LOCAL_NUM_SOURCES] = { /*reference multiple interrupts*/ U54_spare_0_local_IRQHandler, U54_spare_1_local_IRQHandler, U54_spare_2_local_IRQHandler, /*parse hart ID to discover which mac is the source*/ U54_3_mac1_mmsl_local_IRQHandler, U54_3_mac1_emac_local_IRQHandler, U54_3_mac1_queue3_local_IRQHandler, U54_3_mac1_queue2_local_IRQHandler, U54_3_mac1_queue1_local_IRQHandler, U54_3_mac1_int_local_IRQHandler, /*parse hart ID to discover which wdog is the source*/ U54_3_wdog_tout_local_IRQHandler, U54_3_wdog_mvrp_local_IRQHandler, U54_3_mmuart3_local_IRQHandler, U54_spare_3_local_IRQHandler, U54_spare_4_local_IRQHandler, U54_spare_5_local_IRQHandler, U54_spare_6_local_IRQHandler, U54_f2m_0_local_IRQHandler, U54_f2m_1_local_IRQHandler, U54_f2m_2_local_IRQHandler, U54_f2m_3_local_IRQHandler, U54_f2m_4_local_IRQHandler, U54_f2m_5_local_IRQHandler, U54_f2m_6_local_IRQHandler, U54_f2m_7_local_IRQHandler, U54_f2m_8_local_IRQHandler, U54_f2m_9_local_IRQHandler, U54_f2m_10_local_IRQHandler, U54_f2m_11_local_IRQHandler, U54_f2m_12_local_IRQHandler, U54_f2m_13_local_IRQHandler, U54_f2m_14_local_IRQHandler, U54_f2m_15_local_IRQHandler, U54_f2m_16_local_IRQHandler, U54_f2m_17_local_IRQHandler, U54_f2m_18_local_IRQHandler, U54_f2m_19_local_IRQHandler, U54_f2m_20_local_IRQHandler, U54_f2m_21_local_IRQHandler, U54_f2m_22_local_IRQHandler, U54_f2m_23_local_IRQHandler, U54_f2m_24_local_IRQHandler, U54_f2m_25_local_IRQHandler, U54_f2m_26_local_IRQHandler, U54_f2m_27_local_IRQHandler, U54_f2m_28_local_IRQHandler, U54_f2m_29_local_IRQHandler, U54_f2m_30_local_IRQHandler, U54_f2m_31_local_IRQHandler }; /* U54 4 */ local_int_p_t local_irq_handler_4_table[E51_LOCAL_NUM_SOURCES] = { /*reference multiple interrupts*/ U54_spare_0_local_IRQHandler, U54_spare_1_local_IRQHandler, U54_spare_2_local_IRQHandler, /*parse hart ID to discover which mac is the source*/ U54_4_mac1_mmsl_local_IRQHandler, U54_4_mac1_emac_local_IRQHandler, U54_4_mac1_queue3_local_IRQHandler, U54_4_mac1_queue2_local_IRQHandler, U54_4_mac1_queue1_local_IRQHandler, U54_4_mac1_int_local_IRQHandler, /*parse hart ID to discover which wdog is the source*/ U54_4_wdog_tout_local_IRQHandler, U54_4_wdog_mvrp_local_IRQHandler, U54_4_mmuart4_local_IRQHandler, U54_spare_3_local_IRQHandler, U54_spare_4_local_IRQHandler, U54_spare_5_local_IRQHandler, U54_spare_6_local_IRQHandler, U54_f2m_0_local_IRQHandler, U54_f2m_1_local_IRQHandler, U54_f2m_2_local_IRQHandler, U54_f2m_3_local_IRQHandler, U54_f2m_4_local_IRQHandler, U54_f2m_5_local_IRQHandler, U54_f2m_6_local_IRQHandler, U54_f2m_7_local_IRQHandler, U54_f2m_8_local_IRQHandler, U54_f2m_9_local_IRQHandler, U54_f2m_10_local_IRQHandler, U54_f2m_11_local_IRQHandler, U54_f2m_12_local_IRQHandler, U54_f2m_13_local_IRQHandler, U54_f2m_14_local_IRQHandler, U54_f2m_15_local_IRQHandler, U54_f2m_16_local_IRQHandler, U54_f2m_17_local_IRQHandler, U54_f2m_18_local_IRQHandler, U54_f2m_19_local_IRQHandler, U54_f2m_20_local_IRQHandler, U54_f2m_21_local_IRQHandler, U54_f2m_22_local_IRQHandler, U54_f2m_23_local_IRQHandler, U54_f2m_24_local_IRQHandler, U54_f2m_25_local_IRQHandler, U54_f2m_26_local_IRQHandler, U54_f2m_27_local_IRQHandler, U54_f2m_28_local_IRQHandler, U54_f2m_29_local_IRQHandler, U54_f2m_30_local_IRQHandler, U54_f2m_31_local_IRQHandler }; local_int_p_t *local_int_mux[5] = { E51_local_irq_handler_table, local_irq_handler_1_table, local_irq_handler_2_table, local_irq_handler_3_table, local_irq_handler_4_table }; /*------------------------------------------------------------------------------ * */ void handle_m_ext_interrupt(void) { volatile uint32_t int_num = PLIC_ClaimIRQ(); if (PLIC_INVALID_INT_OFFSET == int_num) { return; } uint8_t disable = EXT_IRQ_KEEP_ENABLED; disable = ext_irq_handler_table[int_num /* + OFFSET_TO_MSS_GLOBAL_INTS Think this was required in early bitfile */](); PLIC_CompleteIRQ(int_num); if(EXT_IRQ_DISABLE == disable) { PLIC_DisableIRQ((PLIC_IRQn_Type)int_num); } } /*------------------------------------------------------------------------------ * */ void handle_local_interrupt(uint8_t interrupt_no) { uint64_t mhart_id = read_csr(mhartid); uint8_t local_interrupt_no = (uint8_t)(interrupt_no - 16U); local_int_p_t *local_int_table = local_int_mux[mhart_id]; (*local_int_table[local_interrupt_no])(); } /*------------------------------------------------------------------------------ * */ void trap_from_machine_mode(uintptr_t * regs, uintptr_t dummy, uintptr_t mepc) { volatile uintptr_t mcause = read_csr(mcause); if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) > 15U)&& ((mcause & MCAUSE_CAUSE) < 64U)) { handle_local_interrupt((uint8_t)(mcause & MCAUSE_CAUSE)); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) { handle_m_ext_interrupt(); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT)) { handle_m_soft_interrupt(); } else if (((mcause & MCAUSE_INT) == MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)) { handle_m_timer_interrupt(); } else { uint32_t i = 0U; while(1) { /* wait for watchdog */ i++; /* added some code as SC debugger hangs if in loop doing nothing */ if(i == 0x1000U) { i = (uint32_t)mcause; /* so mcause is not optimised out */ } } switch(mcause) { case CAUSE_LOAD_PAGE_FAULT: break; case CAUSE_STORE_PAGE_FAULT: break; case CAUSE_FETCH_ACCESS: break; case CAUSE_LOAD_ACCESS: break; case CAUSE_STORE_ACCESS: break; default: bad_trap(regs, dummy, mepc); break; } } } #ifdef __cplusplus } #endif mss_mtrap.h000066400000000000000000000062621432224323300362400ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/* Copyright (c) 2013, The Regents of the University of California (Regents). All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Regents nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*********************************************************************************** * Record of Microchip changes */ #ifndef RISCV_MTRAP_H #define RISCV_MTRAP_H #ifdef __cplusplus extern "C" { #endif #ifndef __ASSEMBLER__ #define read_const_csr(reg) ({ unsigned long __tmp; \ asm ("csrr %0, " #reg : "=r"(__tmp)); \ __tmp; }) #endif #define IPI_SOFT 0x01 #define IPI_FENCE_I 0x02 #define IPI_SFENCE_VMA 0x04 #define MACHINE_STACK_SIZE (RISCV_PGSIZE) /* this is 4k for HLS and 4k for the stack*/ #define MENTRY_HLS_OFFSET (INTEGER_CONTEXT_SIZE + SOFT_FLOAT_CONTEXT_SIZE) #define MENTRY_FRAME_SIZE (MENTRY_HLS_OFFSET + HLS_SIZE) #define MENTRY_IPI_OFFSET (MENTRY_HLS_OFFSET) #define MENTRY_IPI_PENDING_OFFSET (MENTRY_HLS_OFFSET + REGBYTES) #ifdef __riscv_flen # define SOFT_FLOAT_CONTEXT_SIZE (0) #else # define SOFT_FLOAT_CONTEXT_SIZE (8 * 32) #endif #define HLS_SIZE (64) #define INTEGER_CONTEXT_SIZE (32 * REGBYTES) #ifndef __ASSEMBLER__ typedef struct { volatile uint32_t * ipi; volatile int mipi_pending; volatile int padding; volatile uint64_t * timecmp; volatile uint32_t * plic_m_thresh; volatile uintptr_t * plic_m_ie; volatile uint32_t * plic_s_thresh; volatile uintptr_t * plic_s_ie; } hls_t; /* This code relies on the stack being allocated on a 4K boundary */ /* also can not be bigger than 4k */ #define MACHINE_STACK_TOP() ({ \ register uintptr_t sp asm ("sp"); \ (void *)((sp + RISCV_PGSIZE) & -RISCV_PGSIZE); }) // hart-local storage #define HLS() ((hls_t*)(MACHINE_STACK_TOP() - HLS_SIZE)) #define OTHER_HLS(id) ((hls_t*)((void *)HLS() + RISCV_PGSIZE * ((id) - read_const_csr(mhartid)))) #endif #ifdef __cplusplus } #endif #endif /*RISCV_MTRAP_H*/ mss_peripherals.c000066400000000000000000000177341432224323300374340ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_peripherals.c * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS functions related to peripherals. * */ /*=========================================================================*//** *//*=========================================================================*/ #include #include #include "mpfs_hal/mss_hal.h" const uint32_t LIBERO_SETTING_CONTEXT_EN[][2U] = { {LIBERO_SETTING_CONTEXT_A_EN, LIBERO_SETTING_CONTEXT_B_EN}, {LIBERO_SETTING_CONTEXT_A_EN_FIC, LIBERO_SETTING_CONTEXT_B_EN_FIC}, }; /* offsets used in PERIPHERAL_SETUP array */ #define PERIPHERAL_INDEX_OFFSET 0U /* used for sanity check */ #define CONTEXT_EN_INDEX_OFFSET 1U #define CONTEXT_MASK_INDEX_OFFSET 2U #define CONTEXT_SUBCLK_INDEX_OFFSET 3U const uint32_t PERIPHERAL_SETUP[][4U] = { {MSS_PERIPH_MMUART0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMUART0,SUBBLK_CLOCK_CR_MMUART0_MASK}, {MSS_PERIPH_MMUART1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMUART1,SUBBLK_CLOCK_CR_MMUART1_MASK}, {MSS_PERIPH_MMUART2,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMUART2,SUBBLK_CLOCK_CR_MMUART2_MASK}, {MSS_PERIPH_MMUART3,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMUART3,SUBBLK_CLOCK_CR_MMUART3_MASK}, {MSS_PERIPH_MMUART4,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMUART4,SUBBLK_CLOCK_CR_MMUART4_MASK}, {MSS_PERIPH_WDOG0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_WDOG0,SUBBLK_CLOCK_NA_MASK}, {MSS_PERIPH_WDOG1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_WDOG1,SUBBLK_CLOCK_NA_MASK}, {MSS_PERIPH_WDOG2,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_WDOG2,SUBBLK_CLOCK_NA_MASK}, {MSS_PERIPH_WDOG3,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_WDOG3,SUBBLK_CLOCK_NA_MASK}, {MSS_PERIPH_WDOG4,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_WDOG4,SUBBLK_CLOCK_NA_MASK}, {MSS_PERIPH_SPI0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_SPI0,SUBBLK_CLOCK_CR_SPI0_MASK}, {MSS_PERIPH_SPI1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_SPI1,SUBBLK_CLOCK_CR_SPI1_MASK}, {MSS_PERIPH_I2C0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_I2C0,SUBBLK_CLOCK_CR_I2C0_MASK}, {MSS_PERIPH_I2C1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_I2C1,SUBBLK_CLOCK_CR_I2C1_MASK}, {MSS_PERIPH_CAN0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_CAN0,SUBBLK_CLOCK_CR_CAN0_MASK}, {MSS_PERIPH_CAN1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_CAN1,SUBBLK_CLOCK_CR_CAN1_MASK}, {MSS_PERIPH_MAC0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MAC0,SUBBLK_CLOCK_CR_MAC0_MASK}, {MSS_PERIPH_MAC1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MAC1,SUBBLK_CLOCK_CR_MAC1_MASK}, {MSS_PERIPH_TIMER,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_TIMER,SUBBLK_CLOCK_CR_TIMER_MASK}, {MSS_PERIPH_GPIO0,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_GPIO0,SUBBLK_CLOCK_CR_GPIO0_MASK}, {MSS_PERIPH_GPIO1,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_GPIO1,SUBBLK_CLOCK_CR_GPIO1_MASK}, {MSS_PERIPH_GPIO2,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_GPIO2,SUBBLK_CLOCK_CR_GPIO2_MASK}, {MSS_PERIPH_RTC,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_RTC,SUBBLK_CLOCK_CR_RTC_MASK}, {MSS_PERIPH_M2FINT,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_M2FINT, SUBBLK_CLOCK_NA_MASK}, {MSS_PERIPH_CRYPTO,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_CRYPTO,SUBBLK_CLOCK_CR_ATHENA_MASK}, {MSS_PERIPH_USB,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_USB,SUBBLK_CLOCK_CR_USB_MASK}, {MSS_PERIPH_QSPIXIP,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_QSPIXIP,SUBBLK_CLOCK_CR_QSPI_MASK}, {MSS_PERIPH_ATHENA,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_ATHENA,SUBBLK_CLOCK_CR_ATHENA_MASK}, {MSS_PERIPH_TRACE,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMC,SUBBLK_CLOCK_CR_MMC_MASK}, {MSS_PERIPH_MAILBOX_SC,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMC,SUBBLK_CLOCK_CR_MMC_MASK}, {MSS_PERIPH_EMMC,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_MMC,SUBBLK_CLOCK_CR_MMC_MASK}, {MSS_PERIPH_CFM,CONTEXT_EN_INDEX, CONTEXT_EN_MASK_CFM,SUBBLK_CLOCK_CR_CFM_MASK}, {MSS_PERIPH_FIC0,CONTEXT_EN_INDEX_FIC, CONTEXT_EN_MASK_FIC0,SUBBLK_CLOCK_CR_FIC0_MASK}, {MSS_PERIPH_FIC1,CONTEXT_EN_INDEX_FIC, CONTEXT_EN_MASK_FIC1,SUBBLK_CLOCK_CR_FIC1_MASK}, {MSS_PERIPH_FIC2,CONTEXT_EN_INDEX_FIC, CONTEXT_EN_MASK_FIC2,SUBBLK_CLOCK_CR_FIC2_MASK}, {MSS_PERIPH_FIC3,CONTEXT_EN_INDEX_FIC, CONTEXT_EN_MASK_FIC3,SUBBLK_CLOCK_CR_FIC3_MASK} }; /** * If contexts set-up, verify allowed access to peripheral * @param option - Two option, , FIC enables set separately. CONTEXT_EN_INDEX_FIC or CONTEXT_EN_INDEX * @param periph_context_mask See CONTEXT_EN_MASK_ defines for options * @param hart The hart ID of origin of request. * @return */ static inline uint8_t verify_context_enable(uint8_t option, uint32_t periph_context_mask , uint8_t hart) { uint8_t result = 1U; #if ((LIBERO_SETTING_MEM_CONFIGS_ENABLED & PMP_ENABLED_MASK) == PMP_ENABLED_MASK) if (hart != (uint8_t) 0U) { if (LIBERO_SETTING_CONTEXT_A_HART_EN & hart ) { if (LIBERO_SETTING_CONTEXT_EN[option][0U] & periph_context_mask) { result = 0U; } } if (LIBERO_SETTING_CONTEXT_B_HART_EN & hart ) { if (LIBERO_SETTING_CONTEXT_EN[option][1U] & periph_context_mask) { result = 0U; } } } else { hart = 0U; } #else (void)hart; (void)periph_context_mask; (void)option; result = 0U; #endif return result; } /** * Turn on/off mss peripheral as required * @param peripheral_mask * @param req_state */ static inline void peripheral_on_off(uint32_t peripheral_mask , PERIPH_RESET_STATE req_state) { if (req_state == PERIPHERAL_OFF) { /* Turn off clock */ SYSREG->SUBBLK_CLOCK_CR &= (uint32_t)~(peripheral_mask); /* Hold in reset */ SYSREG->SOFT_RESET_CR |= (uint32_t)(peripheral_mask); } else { /* Turn on clock */ SYSREG->SUBBLK_CLOCK_CR |= (peripheral_mask); /* Remove soft reset */ SYSREG->SOFT_RESET_CR &= (uint32_t)~(peripheral_mask); } } /***************************************************************************//** * See mss_peripherals.h for details of how to use this function. */ __attribute__((weak)) uint8_t mss_config_clk_rst(mss_peripherals peripheral, uint8_t hart, PERIPH_RESET_STATE req_state) { uint8_t result = 1U; ASSERT(PERIPHERAL_SETUP[peripheral][PERIPHERAL_INDEX_OFFSET] == peripheral); result = verify_context_enable((uint8_t)PERIPHERAL_SETUP[peripheral][CONTEXT_EN_INDEX_OFFSET], PERIPHERAL_SETUP[peripheral][CONTEXT_MASK_INDEX_OFFSET] , hart); if (result == 0U) { peripheral_on_off(PERIPHERAL_SETUP[peripheral][CONTEXT_SUBCLK_INDEX_OFFSET] , req_state); } return result; } /***************************************************************************//** * See mss_peripherals.h for details of how to use this function. */ __attribute__((weak)) void mss_enable_fabric(void) { /* Remove soft reset */ SYSREG->SOFT_RESET_CR &= (uint32_t)~(SOFT_RESET_CR_FPGA_MASK); } /***************************************************************************//** * See mss_peripherals.h for details of how to use this function. */ __attribute__((weak)) void mss_disable_fabric(void) { /* Apply reset */ SYSREG->SOFT_RESET_CR |= SOFT_RESET_CR_FPGA_MASK; } /***************************************************************************//** * See mss_peripherals.h for details of how to use this function. */ __attribute__((weak)) void mss_set_apb_bus_cr(uint32_t reg_value) { SYSREG->APBBUS_CR = reg_value; } /***************************************************************************//** * See mss_peripherals.h for details of how to use this function. */ __attribute__((weak)) uint32_t mss_get_apb_bus_cr(void) { return (SYSREG->APBBUS_CR); } mss_peripherals.h000066400000000000000000000120061432224323300374240ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_peripherals.h * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS fumnctions related to MSS peripherals. * */ /*=========================================================================*//** *//*=========================================================================*/ #ifndef MSS_PERIPHERALS_H #define MSS_PERIPHERALS_H #include #ifdef __cplusplus extern "C" { #endif #if !defined (LIBERO_SETTING_CONTEXT_A_EN) #define LIBERO_SETTING_CONTEXT_A_EN 0x00000000UL #endif #if !defined (LIBERO_SETTING_CONTEXT_B_EN) #define LIBERO_SETTING_CONTEXT_B_EN 0x00000000UL #endif #if !defined (LIBERO_SETTING_CONTEXT_A_EN_FIC) #define LIBERO_SETTING_CONTEXT_A_EN_FIC 0x0000000FUL #endif #if !defined (LIBERO_SETTING_CONTEXT_B_EN_FIC) #define LIBERO_SETTING_CONTEXT_B_EN_FIC 0x0000000FUL #endif /***************************************************************************//** */ typedef enum PERIPH_RESET_STATE_ { PERIPHERAL_ON = 0x00, /*!< 0 RST and clk ON */ PERIPHERAL_OFF = 0x01, /*!< 1 RST and clk OFF */ } PERIPH_RESET_STATE; #define CONTEXT_EN_INDEX 0x00U #define CONTEXT_EN_INDEX_FIC 0x01U #define SUBBLK_CLOCK_NA_MASK 0x00U typedef enum mss_peripherals_ { MSS_PERIPH_MMUART0 = 0U, MSS_PERIPH_MMUART1 = 1U, MSS_PERIPH_MMUART2 = 2U, MSS_PERIPH_MMUART3 = 3U, MSS_PERIPH_MMUART4 = 4U, MSS_PERIPH_WDOG0 = 5U, MSS_PERIPH_WDOG1 = 6U, MSS_PERIPH_WDOG2 = 7U, MSS_PERIPH_WDOG3 = 8U, MSS_PERIPH_WDOG4 = 9U, MSS_PERIPH_SPI0 = 10U, MSS_PERIPH_SPI1 = 11U, MSS_PERIPH_I2C0 = 12U, MSS_PERIPH_I2C1 = 13U, MSS_PERIPH_CAN0 = 14U, MSS_PERIPH_CAN1 = 15U, MSS_PERIPH_MAC0 = 16U, MSS_PERIPH_MAC1 = 17U, MSS_PERIPH_TIMER = 18U, MSS_PERIPH_GPIO0 = 19U, MSS_PERIPH_GPIO1 = 20U, MSS_PERIPH_GPIO2 = 21U, MSS_PERIPH_RTC = 22U, MSS_PERIPH_M2FINT = 23U, MSS_PERIPH_CRYPTO = 24U, MSS_PERIPH_USB = 25U, MSS_PERIPH_QSPIXIP = 26U, MSS_PERIPH_ATHENA = 27U, MSS_PERIPH_TRACE = 28U, MSS_PERIPH_MAILBOX_SC = 29U, MSS_PERIPH_EMMC = 30U, MSS_PERIPH_CFM = 31U, MSS_PERIPH_FIC0 = 32U, MSS_PERIPH_FIC1 = 33U, MSS_PERIPH_FIC2 = 34U, MSS_PERIPH_FIC3 = 35U } mss_peripherals; /***************************************************************************//** This function is used to turn on or off a peripheral. If contexts have been configured, these will be checked to see if peripheral should be controlled from a particular context. @param peripheral See enum mss_peripherals for list of peripherals @param hart Origin hart of this request @req_state Turn peripheral on or off: - PERIPHERAL_ON - PERIPHERAL_OFF Example: @code uint8_t err_status; err_status = mss_config_clk_rst(MSS_PERIPH_MMUART0, (uint8_t) origin_hart_ID, PERIPHERAL_ON); if(0U != err_status) { print_uart0("\n\r Context not allowed to access UART0 from hart:%d\n\nr", origin_hart_ID); } @endcode */ uint8_t mss_config_clk_rst(mss_peripherals peripheral, uint8_t hart, PERIPH_RESET_STATE req_state); /***************************************************************************//** This function is used to turn on the fabric enable Example: @code (void)mss_config_clk_rst(MSS_PERIPH_FIC3, (uint8_t)MPFS_HAL_FIRST_HART, PERIPHERAL_ON); mss_enable_fabric(); @endcode */ void mss_enable_fabric(void); /***************************************************************************//** This function is used to turn on the fabric enable Example: @code mss_disable_fabric(); @endcode */ void mss_disable_fabric(void); /***************************************************************************//** This function is used to set the apb_bus_cr register value @param reg_value value of the register you want to set. This value is available from the MSS configurator LIBERO_SETTING_APBBUS_CR Example: @code mss_set_apb_bus_cr(LIBERO_SETTING_APBBUS_CR); @endcode */ void mss_set_apb_bus_cr(uint32_t reg_value); /***************************************************************************//** This function is used to get the apb_bus_cr register value @return Return the apb_bus_cr reg value Example: @code uint32_t cr_reg; cr_reg = mss_get_apb_bus_cr(); @endcode */ uint32_t mss_get_apb_bus_cr(void); #ifdef __cplusplus } #endif #endif /* MSS_PERIPHERALS_H */ mss_plic.c000066400000000000000000000012651432224323300360350ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_plic.c * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS PLIC and PRCI access data structures and functions. * * PLIC related data which cannot be placed in mss_plic.h * */ #include "mpfs_hal/mss_hal.h" #ifdef __cplusplus extern "C" { #endif const unsigned long plic_hart_lookup[5U] = {0U, 1U, 3U, 5U, 7U}; #ifdef __cplusplus } #endif mss_plic.h000066400000000000000000001115131432224323300360400ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * @file mss_plic.h * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS PLIC and PRCI access data structures and functions. * * Definitions and functions associated with PLIC interrupts. * */ #ifndef MSS_PLIC_H #define MSS_PLIC_H #include #ifndef CONFIG_OPENSBI #include "encoding.h" #endif //#include "mss_legacy_defines.h" #include "mss_assert.h" #ifdef __cplusplus extern "C" { #endif /* *Return value from External IRQ handler. This will be used to disable the *Return External interrupt. */ #define EXT_IRQ_KEEP_ENABLED 0U #define EXT_IRQ_DISABLE 1U /*------------------------------------------------------------------------------ * */ uint8_t PLIC_Invalid_IRQHandler(void); uint8_t PLIC_l2_metadata_corr_IRQHandler(void); uint8_t PLIC_l2_metadata_uncorr_IRQHandler(void); uint8_t PLIC_l2_data_corr_IRQHandler(void); uint8_t PLIC_l2_data_uncorr_IRQHandler(void); uint8_t PLIC_dma_ch0_DONE_IRQHandler(void); uint8_t PLIC_dma_ch0_ERR_IRQHandler(void); uint8_t PLIC_dma_ch1_DONE_IRQHandler(void); uint8_t PLIC_dma_ch1_ERR_IRQHandler(void); uint8_t PLIC_dma_ch2_DONE_IRQHandler(void); uint8_t PLIC_dma_ch2_ERR_IRQHandler(void); uint8_t PLIC_dma_ch3_DONE_IRQHandler(void); uint8_t PLIC_dma_ch3_ERR_IRQHandler(void); uint8_t PLIC_gpio0_bit0_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit1_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit2_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit3_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit4_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit5_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit6_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit7_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit8_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit9_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit10_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit11_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit12_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio0_bit13_or_gpio2_bit13_IRQHandler(void); uint8_t PLIC_gpio1_bit0_or_gpio2_bit14_IRQHandler(void); uint8_t PLIC_gpio1_bit1_or_gpio2_bit15_IRQHandler(void); uint8_t PLIC_gpio1_bit2_or_gpio2_bit16_IRQHandler(void); uint8_t PLIC_gpio1_bit3_or_gpio2_bit17_IRQHandler(void); uint8_t PLIC_gpio1_bit4_or_gpio2_bit18_IRQHandler(void); uint8_t PLIC_gpio1_bit5_or_gpio2_bit19_IRQHandler(void); uint8_t PLIC_gpio1_bit6_or_gpio2_bit20_IRQHandler(void); uint8_t PLIC_gpio1_bit7_or_gpio2_bit21_IRQHandler(void); uint8_t PLIC_gpio1_bit8_or_gpio2_bit22_IRQHandler(void); uint8_t PLIC_gpio1_bit9_or_gpio2_bit23_IRQHandler(void); uint8_t PLIC_gpio1_bit10_or_gpio2_bit24_IRQHandler(void); uint8_t PLIC_gpio1_bit11_or_gpio2_bit25_IRQHandler(void); uint8_t PLIC_gpio1_bit12_or_gpio2_bit26_IRQHandler(void); uint8_t PLIC_gpio1_bit13_or_gpio2_bit27_IRQHandler(void); uint8_t PLIC_gpio1_bit14_or_gpio2_bit28_IRQHandler(void); uint8_t PLIC_gpio1_bit15_or_gpio2_bit29_IRQHandler(void); uint8_t PLIC_gpio1_bit16_or_gpio2_bit30_IRQHandler(void); uint8_t PLIC_gpio1_bit17_or_gpio2_bit31_IRQHandler(void); uint8_t PLIC_gpio1_bit18_IRQHandler(void); uint8_t PLIC_gpio1_bit19_IRQHandler(void); uint8_t PLIC_gpio1_bit20_IRQHandler(void); uint8_t PLIC_gpio1_bit21_IRQHandler(void); uint8_t PLIC_gpio1_bit22_IRQHandler(void); uint8_t PLIC_gpio1_bit23_IRQHandler(void); uint8_t PLIC_gpio0_non_direct_IRQHandler(void); uint8_t PLIC_gpio1_non_direct_IRQHandler(void); uint8_t PLIC_gpio2_non_direct_IRQHandler(void); uint8_t PLIC_spi0_IRQHandler(void); uint8_t PLIC_spi1_IRQHandler(void); uint8_t PLIC_external_can0_IRQHandler(void); uint8_t PLIC_can1_IRQHandler(void); uint8_t PLIC_External_i2c0_main_IRQHandler(void); uint8_t PLIC_External_i2c0_alert_IRQHandler(void); uint8_t PLIC_i2c0_sus_IRQHandler(void); uint8_t PLIC_i2c1_main_IRQHandler(void); uint8_t PLIC_i2c1_alert_IRQHandler(void); uint8_t PLIC_i2c1_sus_IRQHandler(void); uint8_t PLIC_mac0_int_IRQHandler(void); uint8_t PLIC_mac0_queue1_IRQHandler(void); uint8_t PLIC_mac0_queue2_IRQHandler(void); uint8_t PLIC_mac0_queue3_IRQHandler(void); uint8_t PLIC_mac0_emac_IRQHandler(void); uint8_t PLIC_mac0_mmsl_IRQHandler(void); uint8_t PLIC_mac1_int_IRQHandler(void); uint8_t PLIC_mac1_queue1_IRQHandler(void); uint8_t PLIC_mac1_queue2_IRQHandler(void); uint8_t PLIC_mac1_queue3_IRQHandler(void); uint8_t PLIC_mac1_emac_IRQHandler(void); uint8_t PLIC_mac1_mmsl_IRQHandler(void); uint8_t PLIC_ddrc_train_IRQHandler(void); uint8_t PLIC_scb_interrupt_IRQHandler(void); uint8_t PLIC_ecc_error_IRQHandler(void); uint8_t PLIC_ecc_correct_IRQHandler(void); uint8_t PLIC_rtc_wakeup_IRQHandler(void); uint8_t PLIC_rtc_match_IRQHandler(void); uint8_t PLIC_timer1_IRQHandler(void); uint8_t PLIC_timer2_IRQHandler(void); uint8_t PLIC_envm_IRQHandler(void); uint8_t PLIC_qspi_IRQHandler(void); uint8_t PLIC_usb_dma_IRQHandler(void); uint8_t PLIC_usb_mc_IRQHandler(void); uint8_t PLIC_mmc_main_IRQHandler(void); uint8_t PLIC_mmc_wakeup_IRQHandler(void); uint8_t PLIC_mmuart0_IRQHandler(void); uint8_t PLIC_mmuart1_IRQHandler(void); uint8_t PLIC_mmuart2_IRQHandler(void); uint8_t PLIC_mmuart3_IRQHandler(void); uint8_t PLIC_mmuart4_IRQHandler(void); uint8_t PLIC_devrst_IRQHandler(void); uint8_t PLIC_g5c_message_IRQHandler(void); uint8_t PLIC_usoc_vc_interrupt_IRQHandler(void); uint8_t PLIC_usoc_smb_interrupt_IRQHandler(void); uint8_t PLIC_E51_Maintence_IRQHandler(void); uint8_t PLIC_wdog0_mvrp_IRQHandler(void); uint8_t PLIC_wdog1_mvrp_IRQHandler(void); uint8_t PLIC_wdog2_mvrp_IRQHandler(void); uint8_t PLIC_wdog3_mvrp_IRQHandler(void); uint8_t PLIC_wdog4_mvrp_IRQHandler(void); uint8_t PLIC_wdog0_tout_IRQHandler(void); uint8_t PLIC_wdog1_tout_IRQHandler(void); uint8_t PLIC_wdog2_tout_IRQHandler(void); uint8_t PLIC_wdog3_tout_IRQHandler(void); uint8_t PLIC_wdog4_tout_IRQHandler(void); uint8_t PLIC_g5c_mss_spi_IRQHandler(void); uint8_t PLIC_volt_temp_alarm_IRQHandler(void); uint8_t PLIC_athena_complete_IRQHandler(void); uint8_t PLIC_athena_alarm_IRQHandler(void); uint8_t PLIC_athena_bus_error_IRQHandler(void); uint8_t PLIC_usoc_axic_us_IRQHandler(void); uint8_t PLIC_usoc_axic_ds_IRQHandler(void); uint8_t PLIC_reserved_104_IRQHandler(void); uint8_t PLIC_f2m_0_IRQHandler(void); uint8_t PLIC_f2m_1_IRQHandler(void); uint8_t PLIC_f2m_2_IRQHandler(void); uint8_t PLIC_f2m_3_IRQHandler(void); uint8_t PLIC_f2m_4_IRQHandler(void); uint8_t PLIC_f2m_5_IRQHandler(void); uint8_t PLIC_f2m_6_IRQHandler(void); uint8_t PLIC_f2m_7_IRQHandler(void); uint8_t PLIC_f2m_8_IRQHandler(void); uint8_t PLIC_f2m_9_IRQHandler(void); uint8_t PLIC_f2m_10_IRQHandler(void); uint8_t PLIC_f2m_11_IRQHandler(void); uint8_t PLIC_f2m_12_IRQHandler(void); uint8_t PLIC_f2m_13_IRQHandler(void); uint8_t PLIC_f2m_14_IRQHandler(void); uint8_t PLIC_f2m_15_IRQHandler(void); uint8_t PLIC_f2m_16_IRQHandler(void); uint8_t PLIC_f2m_17_IRQHandler(void); uint8_t PLIC_f2m_18_IRQHandler(void); uint8_t PLIC_f2m_19_IRQHandler(void); uint8_t PLIC_f2m_20_IRQHandler(void); uint8_t PLIC_f2m_21_IRQHandler(void); uint8_t PLIC_f2m_22_IRQHandler(void); uint8_t PLIC_f2m_23_IRQHandler(void); uint8_t PLIC_f2m_24_IRQHandler(void); uint8_t PLIC_f2m_25_IRQHandler(void); uint8_t PLIC_f2m_26_IRQHandler(void); uint8_t PLIC_f2m_27_IRQHandler(void); uint8_t PLIC_f2m_28_IRQHandler(void); uint8_t PLIC_f2m_29_IRQHandler(void); uint8_t PLIC_f2m_30_IRQHandler(void); uint8_t PLIC_f2m_31_IRQHandler(void); uint8_t PLIC_f2m_32_IRQHandler(void); uint8_t PLIC_f2m_33_IRQHandler(void); uint8_t PLIC_f2m_34_IRQHandler(void); uint8_t PLIC_f2m_35_IRQHandler(void); uint8_t PLIC_f2m_36_IRQHandler(void); uint8_t PLIC_f2m_37_IRQHandler(void); uint8_t PLIC_f2m_38_IRQHandler(void); uint8_t PLIC_f2m_39_IRQHandler(void); uint8_t PLIC_f2m_40_IRQHandler(void); uint8_t PLIC_f2m_41_IRQHandler(void); uint8_t PLIC_f2m_42_IRQHandler(void); uint8_t PLIC_f2m_43_IRQHandler(void); uint8_t PLIC_f2m_44_IRQHandler(void); uint8_t PLIC_f2m_45_IRQHandler(void); uint8_t PLIC_f2m_46_IRQHandler(void); uint8_t PLIC_f2m_47_IRQHandler(void); uint8_t PLIC_f2m_48_IRQHandler(void); uint8_t PLIC_f2m_49_IRQHandler(void); uint8_t PLIC_f2m_50_IRQHandler(void); uint8_t PLIC_f2m_51_IRQHandler(void); uint8_t PLIC_f2m_52_IRQHandler(void); uint8_t PLIC_f2m_53_IRQHandler(void); uint8_t PLIC_f2m_54_IRQHandler(void); uint8_t PLIC_f2m_55_IRQHandler(void); uint8_t PLIC_f2m_56_IRQHandler(void); uint8_t PLIC_f2m_57_IRQHandler(void); uint8_t PLIC_f2m_58_IRQHandler(void); uint8_t PLIC_f2m_59_IRQHandler(void); uint8_t PLIC_f2m_60_IRQHandler(void); uint8_t PLIC_f2m_61_IRQHandler(void); uint8_t PLIC_f2m_62_IRQHandler(void); uint8_t PLIC_f2m_63_IRQHandler(void); uint8_t PLIC_E51_bus_error_unit_IRQHandler(void); uint8_t PLIC_U54_1_bus_error_unit_IRQHandler(void); uint8_t PLIC_U54_2_bus_error_unit_IRQHandler(void); uint8_t PLIC_U54_3_bus_error_unit_IRQHandler(void); uint8_t PLIC_U54_4_bus_error_unit_IRQHandler(void); /***************************************************************************//** * PLIC source Interrupt numbers: */ /* See section on PLIC Interrupt Sources in User Guide */ #define OFFSET_TO_MSS_GLOBAL_INTS 13U typedef enum { PLIC_INVALID_INT_OFFSET = 0, PLIC_L2_METADATA_CORR_INT_OFFSET = 1, PLIC_L2_METADAT_UNCORR_INT_OFFSET = 2, PLIC_L2_DATA_CORR_INT_OFFSET = 3, PLIC_L2_DATA_UNCORR_INT_OFFSET = 4, PLIC_DMA_CH0_DONE_INT_OFFSET = 5, PLIC_DMA_CH0_ERR_INT_OFFSET = 6, PLIC_DMA_CH1_DONE_INT_OFFSET = 7, PLIC_DMA_CH1_ERR_INT_OFFSET = 8, PLIC_DMA_CH2_DONE_INT_OFFSET = 9, PLIC_DMA_CH2_ERR_INT_OFFSET = 10, PLIC_DMA_CH3_DONE_INT_OFFSET = 11, PLIC_DMA_CH3_ERR_INT_OFFSET = 12, /* see PLIC_I2C Interrupt Multiplexing in the User Guide */ PLIC_GPIO0_BIT0_or_GPIO2_BIT0_INT_OFFSET = 0 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT1_or_GPIO2_BIT1_INT_OFFSET = 1 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT2_or_GPIO2_BIT2_INT_OFFSET = 2 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT3_or_GPIO2_BIT3_INT_OFFSET = 3 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT4_or_GPIO2_BIT4_INT_OFFSET = 4 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT5_or_GPIO2_BIT5_INT_OFFSET = 5 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT6_or_GPIO2_BIT6_INT_OFFSET = 6 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT7_or_GPIO2_BIT7_INT_OFFSET = 7 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT8_or_GPIO2_BIT8_INT_OFFSET = 8 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT9_or_GPIO2_BIT9_INT_OFFSET = 9 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT10_or_GPIO2_BIT10_INT_OFFSET = 10 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT11_or_GPIO2_BIT11_INT_OFFSET = 11 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT12_or_GPIO2_BIT12_INT_OFFSET = 12 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_BIT13_or_GPIO2_BIT13_INT_OFFSET = 13 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT0_or_GPIO2_BIT14_INT_OFFSET = 14 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT1_or_GPIO2_BIT15_INT_OFFSET = 15 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT2_or_GPIO2_BIT16_INT_OFFSET = 16 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT3_or_GPIO2_BIT17_INT_OFFSET = 17 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT4_or_GPIO2_BIT18_INT_OFFSET = 18 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT5_or_GPIO2_BIT19_INT_OFFSET = 19 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT6_or_GPIO2_BIT20_INT_OFFSET = 20 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT7_or_GPIO2_BIT21_INT_OFFSET = 21 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT8_or_GPIO2_BIT22_INT_OFFSET = 22 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT9_or_GPIO2_BIT23_INT_OFFSET = 23 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT10_or_GPIO2_BIT24_INT_OFFSET = 24 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT11_or_GPIO2_BIT25_INT_OFFSET = 25 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT12_or_GPIO2_BIT26_INT_OFFSET = 26 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT13_or_GPIO2_BIT27_INT_OFFSET = 27 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT14_or_GPIO2_BIT28_INT_OFFSET = 28 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT15_or_GPIO2_BIT29_INT_OFFSET = 29 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT16_or_GPIO2_BIT30_INT_OFFSET = 30 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT17_or_GPIO2_BIT31_INT_OFFSET = 31 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT18_INT_OFFSET = 32 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT19_INT_OFFSET = 33 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT20_INT_OFFSET = 34 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT21_INT_OFFSET = 35 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT22_INT_OFFSET = 36 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_BIT23_INT_OFFSET = 37 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO0_NON_DIRECT_INT_OFFSET = 38 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO1_NON_DIRECT_INT_OFFSET = 39 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_GPIO2_NON_DIRECT_INT_OFFSET = 40 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_SPI0_INT_OFFSET = 41 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_SPI1_INT_OFFSET = 42 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_CAN0_INT_OFFSET = 43 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_CAN1_INT_OFFSET = 44 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_I2C0_MAIN_INT_OFFSET = 45 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_I2C0_ALERT_INT_OFFSET = 46 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_I2C0_SUS_INT_OFFSET = 47 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_I2C1_MAIN_INT_OFFSET = 48 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_I2C1_ALERT_INT_OFFSET = 49 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_I2C1_SUS_INT_OFFSET = 50 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC0_INT_INT_OFFSET = 51 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC0_QUEUE1_INT_OFFSET = 52 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC0_QUEUE2_INT_OFFSET = 53 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC0_QUEUE3_INT_OFFSET = 54 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC0_EMAC_INT_OFFSET = 55 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC0_MMSL_INT_OFFSET = 56 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC1_INT_INT_OFFSET = 57 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC1_QUEUE1_INT_OFFSET = 58 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC1_QUEUE2_INT_OFFSET = 59 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC1_QUEUE3_INT_OFFSET = 60 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC1_EMAC_INT_OFFSET = 61 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MAC1_MMSL_INT_OFFSET = 62 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_DDRC_TRAIN_INT_OFFSET = 63 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_SCB_INTERRUPT_INT_OFFSET = 64 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_ECC_ERROR_INT_OFFSET = 65 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_ECC_CORRECT_INT_OFFSET = 66 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_RTC_WAKEUP_INT_OFFSET = 67 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_RTC_MATCH_INT_OFFSET = 68 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_TIMER1_INT_OFFSET = 69 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_TIMER2_INT_OFFSET = 70 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_ENVM_INT_OFFSET = 71 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_QSPI_INT_OFFSET = 72 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_USB_DMA_INT_OFFSET = 73 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_USB_MC_INT_OFFSET = 74 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMC_main_INT_OFFSET = 75 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMC_wakeup_INT_OFFSET = 76 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMUART0_INT_OFFSET = 77 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMUART1_INT_OFFSET = 78 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMUART2_INT_OFFSET = 79 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMUART3_INT_OFFSET = 80 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_MMUART4_INT_OFFSET = 81 + OFFSET_TO_MSS_GLOBAL_INTS, G5C_DEVRST_INT_OFFSET = 82 + OFFSET_TO_MSS_GLOBAL_INTS, g5c_MESSAGE_INT_OFFSET = 83 + OFFSET_TO_MSS_GLOBAL_INTS, USOC_VC_INTERRUPT_INT_OFFSET = 84 + OFFSET_TO_MSS_GLOBAL_INTS, USOC_SMB_INTERRUPT_INT_OFFSET = 85 + OFFSET_TO_MSS_GLOBAL_INTS, /* contains multiple interrupts- */ E51_0_MAINTENACE_INT_OFFSET = 86 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG0_MRVP_INT_OFFSET = 87 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG1_MRVP_INT_OFFSET = 88 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG2_MRVP_INT_OFFSET = 89 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG3_MRVP_INT_OFFSET = 90 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG4_MRVP_INT_OFFSET = 91 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG0_TOUT_INT_OFFSET = 92 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG1_TOUT_INT_OFFSET = 93 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG2_TOUT_INT_OFFSET = 94 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG3_TOUT_INT_OFFSET = 95 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_WDOG4_TOUT_INT_OFFSET = 96 + OFFSET_TO_MSS_GLOBAL_INTS, G5C_MSS_SPI_INT_OFFSET = 97 + OFFSET_TO_MSS_GLOBAL_INTS, VOLT_TEMP_ALARM_INT_OFFSET = 98 + OFFSET_TO_MSS_GLOBAL_INTS, ATHENA_COMPLETE_INT_OFFSET = 99 + OFFSET_TO_MSS_GLOBAL_INTS, ATHENA_ALARM_INT_OFFSET = 100 + OFFSET_TO_MSS_GLOBAL_INTS, ATHENA_BUS_ERROR_INT_OFFSET = 101 + OFFSET_TO_MSS_GLOBAL_INTS, USOC_AXIC_US_INT_OFFSET = 102 + OFFSET_TO_MSS_GLOBAL_INTS, USOC_AXIC_DS_INT_OFFSET = 103 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_0_INT_OFFSET = 105 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_1_INT_OFFSET = 106 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_2_INT_OFFSET = 107 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_3_INT_OFFSET = 108 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_4_INT_OFFSET = 109 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_5_INT_OFFSET = 110 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_6_INT_OFFSET = 111 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_7_INT_OFFSET = 112 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_8_INT_OFFSET = 113 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_9_INT_OFFSET = 114 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_10_INT_OFFSET = 115 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_11_INT_OFFSET = 116 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_12_INT_OFFSET = 117 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_13_INT_OFFSET = 118 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_14_INT_OFFSET = 119 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_15_INT_OFFSET = 120 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_16_INT_OFFSET = 121 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_17_INT_OFFSET = 122 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_18_INT_OFFSET = 123 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_19_INT_OFFSET = 124 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_20_INT_OFFSET = 125 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_21_INT_OFFSET = 126 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_22_INT_OFFSET = 127 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_23_INT_OFFSET = 128 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_24_INT_OFFSET = 129 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_25_INT_OFFSET = 130 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_26_INT_OFFSET = 131 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_27_INT_OFFSET = 132 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_28_INT_OFFSET = 133 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_29_INT_OFFSET = 134 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_30_INT_OFFSET = 135 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_31_INT_OFFSET = 136 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_32_INT_OFFSET = 137 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_33_INT_OFFSET = 138 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_34_INT_OFFSET = 139 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_35_INT_OFFSET = 140 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_36_INT_OFFSET = 141 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_37_INT_OFFSET = 142 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_38_INT_OFFSET = 143 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_39_INT_OFFSET = 144 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_40_INT_OFFSET = 145 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_41_INT_OFFSET = 146 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_42_INT_OFFSET = 147 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_43_INT_OFFSET = 148 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_44_INT_OFFSET = 149 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_45_INT_OFFSET = 150 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_46_INT_OFFSET = 151 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_47_INT_OFFSET = 152 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_48_INT_OFFSET = 153 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_49_INT_OFFSET = 154 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_50_INT_OFFSET = 155 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_51_INT_OFFSET = 156 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_52_INT_OFFSET = 157 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_53_INT_OFFSET = 158 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_54_INT_OFFSET = 159 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_55_INT_OFFSET = 160 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_56_INT_OFFSET = 161 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_57_INT_OFFSET = 162 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_58_INT_OFFSET = 163 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_59_INT_OFFSET = 164 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_60_INT_OFFSET = 165 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_61_INT_OFFSET = 166 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_62_INT_OFFSET = 167 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_F2M_63_INT_OFFSET = 168 + OFFSET_TO_MSS_GLOBAL_INTS, PLIC_E51_BUS_ERROR_UNIT_OFFSET = 182, PLIC_U54_1_BUS_ERROR_UNIT_OFFSET = 183, PLIC_U54_2_BUS_ERROR_UNIT_OFFSET = 184, PLIC_U54_3_BUS_ERROR_UNIT_OFFSET = 185, PLIC_U54_4_BUS_ERROR_UNIT_OFFSET = 186 } PLIC_IRQn_Type; #define MAX_PLIC_INT PLIC_U54_4_BUS_ERROR_UNIT_OFFSET typedef struct { volatile uint32_t PRIORITY_THRESHOLD; volatile uint32_t CLAIM_COMPLETE; volatile uint32_t reserved[(0x1000/4)-2]; } IRQ_Target_Type; typedef struct { volatile uint32_t ENABLES[32U]; } Target_Enables_Type; #define PLIC_SET_UP_REGISTERS 6U #define PLIC_NUM_SOURCES 187U #define PLIC_NUM_PRIORITIES 7U #define NUM_CLAIM_REGS 9U /* The FU540-C000 has 53 interrupt sources. */ typedef struct { volatile uint32_t RESERVED0; /*-------------------- Source Priority --------------------*/ volatile uint32_t SOURCE_PRIORITY[PLIC_NUM_SOURCES]; volatile uint32_t RESERVED1[(0x1000 / 4) - (PLIC_NUM_SOURCES + 1)]; /*-------------------- Pending array --------------------*/ volatile const uint32_t PENDING_ARRAY[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED2[(0x1000/4) - PLIC_SET_UP_REGISTERS]; /*-----------------Hart0 Mode Enables--------------------*/ volatile uint32_t HART0_MMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED3[(0x80/4) - PLIC_SET_UP_REGISTERS]; /*-----------------Hart1 Mode Enables--------------------*/ volatile uint32_t HART1_MMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED4a[(0x80/4) - PLIC_SET_UP_REGISTERS]; volatile uint32_t HART1_SMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED4[(0x80/4) - PLIC_SET_UP_REGISTERS]; /*-----------------Hart2 Mode Enables--------------------*/ volatile uint32_t HART2_MMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED5a[(0x80/4) - PLIC_SET_UP_REGISTERS]; volatile uint32_t HART2_SMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED5[(0x80/4) - PLIC_SET_UP_REGISTERS]; /*-----------------Hart3 Mode Enables--------------------*/ volatile uint32_t HART3_MMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED6a[(0x80/4) - PLIC_SET_UP_REGISTERS]; volatile uint32_t HART3_SMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED6[(0x80/4) - PLIC_SET_UP_REGISTERS]; /*-----------------Hart4 Mode Enables--------------------*/ volatile uint32_t HART4_MMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED7a[(0x80/4) - PLIC_SET_UP_REGISTERS]; volatile uint32_t HART4_SMODE_ENA[PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED7[(0x80/4) - PLIC_SET_UP_REGISTERS]; volatile uint32_t RESERVED8[(0x0C200000 - 0x0C002480)/4]; /*--- Target Priority threshold and claim/complete---------*/ IRQ_Target_Type TARGET[NUM_CLAIM_REGS]; /* See PLIC Register Map or TARGET_OFFSET defines below for offset details */ } PLIC_Type; #define TARGET_OFFSET_HART0_M 0U #define TARGET_OFFSET_HART1_M 1U #define TARGET_OFFSET_HART1_S 2U #define TARGET_OFFSET_HART2_M 3U #define TARGET_OFFSET_HART2_S 4U #define TARGET_OFFSET_HART3_M 5U #define TARGET_OFFSET_HART3_S 6U #define TARGET_OFFSET_HART4_M 7U #define TARGET_OFFSET_HART4_S 8U extern const unsigned long plic_hart_lookup[5U]; /***************************************************************************//** * PLIC: Platform Level Interrupt Controller */ #define PLIC_BASE_ADDR 0x0C000000UL #define PLIC ((PLIC_Type * const)PLIC_BASE_ADDR) /*-------------------------------------------------------------------------*//** * The function PLIC_init() initializes the PLIC controller and enables the * global external interrupt bit. */ /*-----------------Hart Mode Enables--------------------*/ static inline void PLIC_init(void) { uint32_t inc; uint64_t hart_id = read_csr(mhartid); /* Disable all interrupts for the current hart. */ switch(hart_id) { case 0: for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) { PLIC->HART0_MMODE_ENA[inc] = 0U; } /* Set the threshold to zero. * PLIC provides context based threshold register for the settings of a * interrupt priority threshold of each context. The threshold register * is a WARL field. The PLIC will mask all PLIC interrupts of a priority * less than or equal to threshold. For example, a threshold value of zero * permits all interrupts with non-zero priority.*/ PLIC->TARGET[TARGET_OFFSET_HART0_M].PRIORITY_THRESHOLD = 0U; break; case 1: for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) { PLIC->HART1_MMODE_ENA[inc] = 0U; PLIC->HART1_SMODE_ENA[inc] = 0U; } PLIC->TARGET[TARGET_OFFSET_HART1_M].PRIORITY_THRESHOLD = 0U; /* Disable supervisor level */ PLIC->TARGET[TARGET_OFFSET_HART1_S].PRIORITY_THRESHOLD = 7U; break; case 2: for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) { PLIC->HART2_MMODE_ENA[inc] = 0U; PLIC->HART2_SMODE_ENA[inc] = 0U; } PLIC->TARGET[TARGET_OFFSET_HART2_M].PRIORITY_THRESHOLD = 0U; /* Disable supervisor level */ PLIC->TARGET[TARGET_OFFSET_HART2_S].PRIORITY_THRESHOLD = 7U; break; case 3: for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) { PLIC->HART3_MMODE_ENA[inc] = 0U; PLIC->HART3_SMODE_ENA[inc] = 0U; } PLIC->TARGET[TARGET_OFFSET_HART3_M].PRIORITY_THRESHOLD = 0U; /* Disable supervisor level */ PLIC->TARGET[TARGET_OFFSET_HART3_S].PRIORITY_THRESHOLD = 7U; break; case 4: for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) { PLIC->HART4_MMODE_ENA[inc] = 0U; PLIC->HART4_SMODE_ENA[inc] = 0U; } PLIC->TARGET[TARGET_OFFSET_HART4_M].PRIORITY_THRESHOLD = 0U; /* Disable supervisor level */ PLIC->TARGET[TARGET_OFFSET_HART4_S].PRIORITY_THRESHOLD = 7U; break; default: break; } /* Enable machine external interrupts. */ set_csr(mie, MIP_MEIP); } /***************************************************************************//** * The function PLIC_EnableIRQ() enables the external interrupt for the * interrupt number indicated by the parameter IRQn. */ static inline void PLIC_EnableIRQ(PLIC_IRQn_Type IRQn) { uint32_t current; uint64_t hart_id = read_csr(mhartid); switch(hart_id) { case 0: current = PLIC->HART0_MMODE_ENA[IRQn / 32U]; current |= (uint32_t)1 << (IRQn % 32U); PLIC->HART0_MMODE_ENA[IRQn / 32U] = current; break; case 1: current = PLIC->HART1_MMODE_ENA[IRQn / 32U]; current |= (uint32_t)1 << (IRQn % 32U); PLIC->HART1_MMODE_ENA[IRQn / 32U] = current; break; case 2: current = PLIC->HART2_MMODE_ENA[IRQn / 32U]; current |= (uint32_t)1 << (IRQn % 32U); PLIC->HART2_MMODE_ENA[IRQn / 32U] = current; break; case 3: current = PLIC->HART3_MMODE_ENA[IRQn / 32U]; current |= (uint32_t)1 << (IRQn % 32U); PLIC->HART3_MMODE_ENA[IRQn / 32U] = current; break; case 4: current = PLIC->HART4_MMODE_ENA[IRQn / 32U]; current |= (uint32_t)1 << (IRQn % 32U); PLIC->HART4_MMODE_ENA[IRQn / 32U] = current; break; default: break; } } /***************************************************************************//** * The function PLIC_DisableIRQ() disables the external interrupt for the * interrupt number indicated by the parameter IRQn. * NOTE: * This function can be used to disable the external interrupt from outside * external interrupt handler function. * This function MUST NOT be used from within the External Interrupt * handler. * If you wish to disable the external interrupt while the interrupt handler * for that external interrupt is executing then you must use the return * value EXT_IRQ_DISABLE to return from the extern interrupt handler. */ static inline void PLIC_DisableIRQ(PLIC_IRQn_Type IRQn) { uint32_t current; uint64_t hart_id = read_csr(mhartid); switch(hart_id) { case 0: current = PLIC->HART0_MMODE_ENA[IRQn / 32U]; current &= ~((uint32_t)1 << (IRQn % 32U)); PLIC->HART0_MMODE_ENA[IRQn / 32U] = current; break; case 1: current = PLIC->HART1_MMODE_ENA[IRQn / 32U]; current &= ~((uint32_t)1 << (IRQn % 32U)); PLIC->HART1_MMODE_ENA[IRQn / 32U] = current; break; case 2: current = PLIC->HART2_MMODE_ENA[IRQn / 32U]; current &= ~((uint32_t)1 << (IRQn % 32U)); PLIC->HART2_MMODE_ENA[IRQn / 32U] = current; break; case 3: current = PLIC->HART3_MMODE_ENA[IRQn / 32U]; current &= ~((uint32_t)1 << (IRQn % 32U)); PLIC->HART3_MMODE_ENA[IRQn / 32U] = current; break; case 4: current = PLIC->HART4_MMODE_ENA[IRQn / 32U]; current &= ~((uint32_t)1 << (IRQn % 32U)); PLIC->HART4_MMODE_ENA[IRQn / 32U] = current; break; default: break; } } /***************************************************************************//** * The function PLIC_SetPriority() sets the priority for the external interrupt * for the interrupt number indicated by the parameter IRQn. */ static inline void PLIC_SetPriority(PLIC_IRQn_Type IRQn, uint32_t priority) { if((IRQn > PLIC_INVALID_INT_OFFSET) && (IRQn < PLIC_NUM_SOURCES)) { PLIC->SOURCE_PRIORITY[IRQn-1] = priority; } } /***************************************************************************//** * The function PLIC_GetPriority() returns the priority for the external * interrupt for the interrupt number indicated by the parameter IRQn. */ static inline uint32_t PLIC_GetPriority(PLIC_IRQn_Type IRQn) { uint32_t ret_val = 0U; if((IRQn > PLIC_INVALID_INT_OFFSET) && (IRQn < PLIC_NUM_SOURCES)) { ret_val = PLIC->SOURCE_PRIORITY[IRQn-1]; } return(ret_val); } static inline uint32_t PLIC_pending(PLIC_IRQn_Type IRQn) { return (PLIC->PENDING_ARRAY[IRQn/32U] & (0x01U<<(IRQn%32U))); } /***************************************************************************//** * The function PLIC_ClaimIRQ() claims the interrupt from the PLIC controller. */ static inline uint32_t PLIC_ClaimIRQ(void) { uint64_t hart_id = read_csr(mhartid); return (PLIC->TARGET[plic_hart_lookup[hart_id]].CLAIM_COMPLETE); } /***************************************************************************//** * The function PLIC_CompleteIRQ() indicates to the PLIC controller the * interrupt is processed and claim is complete. */ static inline void PLIC_CompleteIRQ(uint32_t source) { uint64_t hart_id = read_csr(mhartid); ASSERT(source <= MAX_PLIC_INT); PLIC->TARGET[plic_hart_lookup[hart_id]].CLAIM_COMPLETE = source; } /***************************************************************************//** * * The function PLIC_SetPriority_Threshold() sets the threshold for a particular * hart. The default threshold on reset is 0. * The PFSoC Core Complex supports setting of an interrupt priority threshold * via the threshold register. The threshold is a WARL field, where the PFSoC * Core Complex supports a maximum threshold of 7. * The PFSoC Core Complex will mask all PLIC interrupts of a priority less than * or equal to threshold. For example, a threshold value of zero permits all * interrupts with non-zero priority, whereas a value of 7 masks all * interrupts. */ static inline void PLIC_SetPriority_Threshold(uint32_t threshold) { uint64_t hart_id = read_csr(mhartid); ASSERT(threshold <= 7); PLIC->TARGET[plic_hart_lookup[hart_id]].PRIORITY_THRESHOLD = threshold; } /***************************************************************************//** * PLIC_ClearPendingIRQ(void) * This is only called by the startup hart and only once * Clears any pending interrupts as PLIC can be in unknown state on startup */ static inline void PLIC_ClearPendingIRQ(void) { volatile uint32_t int_num = PLIC_ClaimIRQ(); volatile int32_t wait_possible_int; while ( int_num != PLIC_INVALID_INT_OFFSET) { PLIC_CompleteIRQ(int_num); wait_possible_int = 0xFU; while (wait_possible_int) { wait_possible_int--; } int_num = PLIC_ClaimIRQ(); /* obtain interrupt, auto clears */ } } /***************************************************************************//** * This function is only called from one hart on startup */ static inline void PLIC_init_on_reset(void) { uint32_t inc; /* default all priorities so effectively disabled */ for(inc = 0U; inc < PLIC_NUM_SOURCES; ++inc) { /* priority must be greater than threshold to be enabled, so setting to * 7 disables */ PLIC->SOURCE_PRIORITY[inc] = 0U; } for(inc = 0U; inc < NUM_CLAIM_REGS; ++inc) { PLIC->TARGET[inc].PRIORITY_THRESHOLD = 7U; } /* and clear all the enables */ for(inc = 0UL; inc < PLIC_SET_UP_REGISTERS; inc++) { PLIC->HART0_MMODE_ENA[inc] = 0U; PLIC->HART1_MMODE_ENA[inc] = 0U; PLIC->HART1_SMODE_ENA[inc] = 0U; PLIC->HART2_MMODE_ENA[inc] = 0U; PLIC->HART2_SMODE_ENA[inc] = 0U; PLIC->HART3_MMODE_ENA[inc] = 0U; PLIC->HART3_SMODE_ENA[inc] = 0U; PLIC->HART4_MMODE_ENA[inc] = 0U; PLIC->HART4_SMODE_ENA[inc] = 0U; } /* clear any pending interrupts- in case already there */ PLIC_ClearPendingIRQ(); } #ifdef __cplusplus } #endif #endif /* MSS_PLIC_H */ mss_pmp.c000066400000000000000000000221661432224323300357050ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_pmp.c * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS PMP configuration using MSS configurator values. * */ /*=========================================================================*//** *//*=========================================================================*/ #include #include #include "mpfs_hal/mss_hal.h" /** * \brief PMP configuration from Libero * */ const uint64_t pmp_values[][18] = { /* hart 0 */ {LIBERO_SETTING_HART0_CSR_PMPCFG0, LIBERO_SETTING_HART0_CSR_PMPCFG2, LIBERO_SETTING_HART0_CSR_PMPADDR0, LIBERO_SETTING_HART0_CSR_PMPADDR1, LIBERO_SETTING_HART0_CSR_PMPADDR2, LIBERO_SETTING_HART0_CSR_PMPADDR3, LIBERO_SETTING_HART0_CSR_PMPADDR4, LIBERO_SETTING_HART0_CSR_PMPADDR5, LIBERO_SETTING_HART0_CSR_PMPADDR6, LIBERO_SETTING_HART0_CSR_PMPADDR7, LIBERO_SETTING_HART0_CSR_PMPADDR8, LIBERO_SETTING_HART0_CSR_PMPADDR9, LIBERO_SETTING_HART0_CSR_PMPADDR10, LIBERO_SETTING_HART0_CSR_PMPADDR11, LIBERO_SETTING_HART0_CSR_PMPADDR12, LIBERO_SETTING_HART0_CSR_PMPADDR13, LIBERO_SETTING_HART0_CSR_PMPADDR14, LIBERO_SETTING_HART0_CSR_PMPADDR15}, /* hart 1 */ {LIBERO_SETTING_HART1_CSR_PMPCFG0, LIBERO_SETTING_HART1_CSR_PMPCFG2, LIBERO_SETTING_HART1_CSR_PMPADDR0, LIBERO_SETTING_HART1_CSR_PMPADDR1, LIBERO_SETTING_HART1_CSR_PMPADDR2, LIBERO_SETTING_HART1_CSR_PMPADDR3, LIBERO_SETTING_HART1_CSR_PMPADDR4, LIBERO_SETTING_HART1_CSR_PMPADDR5, LIBERO_SETTING_HART1_CSR_PMPADDR6, LIBERO_SETTING_HART1_CSR_PMPADDR7, LIBERO_SETTING_HART1_CSR_PMPADDR8, LIBERO_SETTING_HART1_CSR_PMPADDR9, LIBERO_SETTING_HART1_CSR_PMPADDR10, LIBERO_SETTING_HART1_CSR_PMPADDR11, LIBERO_SETTING_HART1_CSR_PMPADDR12, LIBERO_SETTING_HART1_CSR_PMPADDR13, LIBERO_SETTING_HART1_CSR_PMPADDR14, LIBERO_SETTING_HART1_CSR_PMPADDR15}, /* hart 2 */ {LIBERO_SETTING_HART2_CSR_PMPCFG0, LIBERO_SETTING_HART2_CSR_PMPCFG2, LIBERO_SETTING_HART2_CSR_PMPADDR0, LIBERO_SETTING_HART2_CSR_PMPADDR1, LIBERO_SETTING_HART2_CSR_PMPADDR2, LIBERO_SETTING_HART2_CSR_PMPADDR3, LIBERO_SETTING_HART2_CSR_PMPADDR4, LIBERO_SETTING_HART2_CSR_PMPADDR5, LIBERO_SETTING_HART2_CSR_PMPADDR6, LIBERO_SETTING_HART2_CSR_PMPADDR7, LIBERO_SETTING_HART2_CSR_PMPADDR8, LIBERO_SETTING_HART2_CSR_PMPADDR9, LIBERO_SETTING_HART2_CSR_PMPADDR10, LIBERO_SETTING_HART2_CSR_PMPADDR11, LIBERO_SETTING_HART2_CSR_PMPADDR12, LIBERO_SETTING_HART2_CSR_PMPADDR13, LIBERO_SETTING_HART2_CSR_PMPADDR14, LIBERO_SETTING_HART2_CSR_PMPADDR15}, /* hart 3 */ {LIBERO_SETTING_HART3_CSR_PMPCFG0, LIBERO_SETTING_HART3_CSR_PMPCFG2, LIBERO_SETTING_HART3_CSR_PMPADDR0, LIBERO_SETTING_HART3_CSR_PMPADDR1, LIBERO_SETTING_HART3_CSR_PMPADDR2, LIBERO_SETTING_HART3_CSR_PMPADDR3, LIBERO_SETTING_HART3_CSR_PMPADDR4, LIBERO_SETTING_HART3_CSR_PMPADDR5, LIBERO_SETTING_HART3_CSR_PMPADDR6, LIBERO_SETTING_HART3_CSR_PMPADDR7, LIBERO_SETTING_HART3_CSR_PMPADDR8, LIBERO_SETTING_HART3_CSR_PMPADDR9, LIBERO_SETTING_HART3_CSR_PMPADDR10, LIBERO_SETTING_HART3_CSR_PMPADDR11, LIBERO_SETTING_HART3_CSR_PMPADDR12, LIBERO_SETTING_HART3_CSR_PMPADDR13, LIBERO_SETTING_HART3_CSR_PMPADDR14, LIBERO_SETTING_HART3_CSR_PMPADDR15}, /* hart 4 */ {LIBERO_SETTING_HART4_CSR_PMPCFG0, LIBERO_SETTING_HART4_CSR_PMPCFG2, LIBERO_SETTING_HART4_CSR_PMPADDR0, LIBERO_SETTING_HART4_CSR_PMPADDR1, LIBERO_SETTING_HART4_CSR_PMPADDR2, LIBERO_SETTING_HART4_CSR_PMPADDR3, LIBERO_SETTING_HART4_CSR_PMPADDR4, LIBERO_SETTING_HART4_CSR_PMPADDR5, LIBERO_SETTING_HART4_CSR_PMPADDR6, LIBERO_SETTING_HART4_CSR_PMPADDR7, LIBERO_SETTING_HART4_CSR_PMPADDR8, LIBERO_SETTING_HART4_CSR_PMPADDR9, LIBERO_SETTING_HART4_CSR_PMPADDR10, LIBERO_SETTING_HART4_CSR_PMPADDR11, LIBERO_SETTING_HART4_CSR_PMPADDR12, LIBERO_SETTING_HART4_CSR_PMPADDR13, LIBERO_SETTING_HART4_CSR_PMPADDR14, LIBERO_SETTING_HART4_CSR_PMPADDR15}, }; /** * pmp_configure() * Set PMP's up with configuration from Libero * @param hart_id hart Id * @return */ uint8_t pmp_configure(uint8_t hart_id) /* set-up with settings from Libero */ { #if ((LIBERO_SETTING_MEM_CONFIGS_ENABLED & PMP_ENABLED_MASK) == PMP_ENABLED_MASK) uint64_t pmp0cfg; #endif /* make sure enables are off */ write_csr(pmpcfg0, 0); write_csr(pmpcfg2, 0); /* set required addressing */ write_csr(pmpaddr0, pmp_values[hart_id][2]); write_csr(pmpaddr1, pmp_values[hart_id][3]); write_csr(pmpaddr2, pmp_values[hart_id][4]); write_csr(pmpaddr3, pmp_values[hart_id][5]); write_csr(pmpaddr4, pmp_values[hart_id][6]); write_csr(pmpaddr5, pmp_values[hart_id][7]); write_csr(pmpaddr6, pmp_values[hart_id][8]); write_csr(pmpaddr7, pmp_values[hart_id][9]); write_csr(pmpaddr8, pmp_values[hart_id][10]); write_csr(pmpaddr9, pmp_values[hart_id][11]); write_csr(pmpaddr10, pmp_values[hart_id][12]); write_csr(pmpaddr11, pmp_values[hart_id][13]); write_csr(pmpaddr12, pmp_values[hart_id][14]); write_csr(pmpaddr13, pmp_values[hart_id][15]); write_csr(pmpaddr14, pmp_values[hart_id][16]); write_csr(pmpaddr15, pmp_values[hart_id][17]); #if ((LIBERO_SETTING_MEM_CONFIGS_ENABLED & PMP_ENABLED_MASK) == PMP_ENABLED_MASK) pmp0cfg = pmp_values[hart_id][0]; pmp_master_configs(hart_id, &pmp0cfg); write_csr(pmpcfg0, pmp0cfg); write_csr(pmpcfg2, pmp_values[hart_id][1]); #else write_csr(pmpcfg0, pmp_values[hart_id][0]); #endif return(0); } /*-------------------------------------------------------------------------*//** Please note the first four PMP's are set to zero by MSS Configurator v2021.1 These will need to be set by the HSS. The first three relate to HSS footprint The PMP4 is used to open a hole for debug region. | PMP | cfg | L | XWR | Detail | |-----|-----------|-----|----------------------------------------------------| | 0 | 0x18 | N | | 256KB | Closes access for s and U mode | | 1 | 0x98 | Y | X R | 256KB | Opens up area for m-mode only | | 2 | 0x98 | Y | XRW | 64KB | OpenSBI scratch per scratch | | 3 | 0x98 | Y | XRW | 4KB | Open window for debug | | .. | .. | .. | .. | .. | .. | | 15 | 0x18 | Y | | - | Close everything not opened | @param pmp0cfg return with config for first four PMP's */ __attribute__((weak)) void pmp_master_configs(uint8_t hart_id, uint64_t * pmp0cfg) { if ( hart_id == 0U ) { *pmp0cfg = LIBERO_SETTING_HART0_CSR_PMPCFG0; write_csr(pmpaddr0, pmp_values[hart_id][2]); write_csr(pmpaddr1, pmp_values[hart_id][3]); write_csr(pmpaddr2, pmp_values[hart_id][4]); write_csr(pmpaddr3, pmp_values[hart_id][5]); } else { /* * Example of closed memory map, must be created based on HSS footprint */ #define CLOSE_S_U_ACCESS_HSS_PMP0_LIM_EG0 0x2007FFFULL /* 256K LIM */ #define CLOSE_S_U_ACCESS_HSS_PMP0_LIM_EG1 0x200FFFFULL /* 512K LIM */ #define OPEN_M_ACCESS_HSS_PMP1_LIM_EG0 0x2007FFFULL /* 256K LIM */ #define OPEN_M_ACCESS_HSS_PMP1_LIM_EG1 0x200FFFFULL /* 512K LIM */ #define OPEN_M_ACCESS_HSS_PMP1_SCRATCH_EG 0x280FFFFULL /* 512K SCRATCHPAD */ #define OPEN_CONTEXT_ACCESS_LIM_PMP2_H1 0x2011FFFULL /* 64K LIM */ #define OPEN_CONTEXT_ACCESS_LIM_PMP2_H2 0x2015FFFULL /* 64K LIM */ #define OPEN_DEBUG_ACCESS_PMP3 0x1FFULL #define HSS_CLOSED_CFG_MASK ~0xFFFFFFFFULL #define HSS_CLOSED_CFG 0x9F9F9D18ULL /* * We will open 512K LIM and scratchpad in weak pmp_master_configs() * for all harts. */ #define LIM_512K_FROM_BASE 0x200FFFFULL /* 512K LIM */ #define SCRATCH_512K_FROM_BASE 0x280FFFFULL /* 512K LIM */ *pmp0cfg &= HSS_CLOSED_CFG_MASK; *pmp0cfg |= 0x9F009F9FULL; /* open 0,1 and 3 to allow open access */ write_csr(pmpaddr0, OPEN_M_ACCESS_HSS_PMP1_LIM_EG1); write_csr(pmpaddr1, OPEN_M_ACCESS_HSS_PMP1_SCRATCH_EG); write_csr(pmpaddr2, 0ULL); write_csr(pmpaddr3, OPEN_DEBUG_ACCESS_PMP3); } /* * */ #define LOCAL_PMP_SETTINGS #ifdef LOCAL_PMP_SETTINGS #endif return; } mss_pmp.h000066400000000000000000000061321432224323300357050ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_pmp.h * @author Microchip-FPGA Embedded Systems Solutions * @brief PolarFire SoC MSS PMP configuration using MSS configurator values. * */ /*=========================================================================*//** *//*=========================================================================*/ #ifndef MSS_PMP_H #define MSS_PMP_H #ifdef __cplusplus extern "C" { #endif #if !defined (LIBERO_SETTING_MEM_CONFIGS_ENABLED) #define LIBERO_SETTING_MEM_CONFIGS_ENABLED 0ULL /* Enabled when bit set to 1 */ /* PMP [0:0] RW value= 0x0 */ /* MPU [1:0] RW value= 0x0 */ #endif #define PMP_ENABLED_MASK 1UL #define MPU_ENABLED_MASK 2UL /* * Bit offsets associated with LIBERO_SETTING_CONTEXT_A_HART_EN and * LIBERO_SETTING_CONTEXT_B_HART_EN */ #define CONTEXT_EN_MASK_MMUART0 (1U<<0) #define CONTEXT_EN_MASK_MMUART1 (1U<<1) #define CONTEXT_EN_MASK_MMUART2 (1U<<2) #define CONTEXT_EN_MASK_MMUART3 (1U<<3) #define CONTEXT_EN_MASK_MMUART4 (1U<<4) #define CONTEXT_EN_MASK_WDOG0 (1U<<5) #define CONTEXT_EN_MASK_WDOG1 (1U<<6) #define CONTEXT_EN_MASK_WDOG2 (1U<<7) #define CONTEXT_EN_MASK_WDOG3 (1U<<8) #define CONTEXT_EN_MASK_WDOG4 (1U<<9) #define CONTEXT_EN_MASK_SPI0 (1U<<10) #define CONTEXT_EN_MASK_SPI1 (1U<<11) #define CONTEXT_EN_MASK_I2C0 (1U<<12) #define CONTEXT_EN_MASK_I2C1 (1U<<13) #define CONTEXT_EN_MASK_CAN0 (1U<<14) #define CONTEXT_EN_MASK_CAN1 (1U<<15) #define CONTEXT_EN_MASK_MAC0 (1U<<16) #define CONTEXT_EN_MASK_MAC1 (1U<<17) #define CONTEXT_EN_MASK_TIMER (1U<<18) #define CONTEXT_EN_MASK_GPIO0 (1U<<19) #define CONTEXT_EN_MASK_GPIO1 (1U<<20) #define CONTEXT_EN_MASK_GPIO2 (1U<<21) #define CONTEXT_EN_MASK_RTC (1U<<22) #define CONTEXT_EN_MASK_M2FINT (1U<<23) #define CONTEXT_EN_MASK_CRYPTO (1U<<24) #define CONTEXT_EN_MASK_USB (1U<<25) #define CONTEXT_EN_MASK_QSPIXIP (1U<<26) #define CONTEXT_EN_MASK_ATHENA (1U<<27) #define CONTEXT_EN_MASK_TRACE (1U<<28) #define CONTEXT_EN_MASK_MAILBOX_SC (1U<<29) #define CONTEXT_EN_MASK_MMC (1U<<30) #define CONTEXT_EN_MASK_CFM (1U<<31) /* * Bit offsets associated with LIBERO_SETTING_CONTEXT_A_FIC_EN and * LIBERO_SETTING_CONTEXT_B_FIC_EN */ #define CONTEXT_EN_MASK_FIC0 (1U<<0) #define CONTEXT_EN_MASK_FIC1 (1U<<1) #define CONTEXT_EN_MASK_FIC2 (1U<<2) #define CONTEXT_EN_MASK_FIC3 (1U<<3) uint8_t pmp_configure(uint8_t hart_id); void pmp_master_configs(uint8_t hart_id, uint64_t * pmp0cfg); #ifdef __cplusplus } #endif #endif /* MSS_PMP_H */ mss_seg.h000066400000000000000000000034371432224323300356740ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*************************************************************************** * * @file mss_seg.h * @author Microchip-FPGA Embedded Systems Solutions * @brief segmentation block defines * * These blocks allow the DDR memory to be allocated to cached, non-cached * regions and trace depending on the amount of DDR memory physically connected. * Conceptually an address offset is added/subtracted from the DDR address * provided by the Core Complex to point at a base address in the DDR memory. * * The AXI bus simply passes through the segmentation block, and the address * is modified. * * There are two segmentation blocks, they are grouped into the same address * ranges as the MPU blocks. Each one has seven 32-segmentation registers, but * only two in SEG0 and five in SEG1 are actually implemented. * * DDRC blocker - blocks writes to DDR before it is set-up * SEG0.CFG[7] * Is cleared at reset. When written to '1' disables the blocker function * Is allowing the L2 cache controller to access the DDRC. * Is Once written to '1' the register cannot be written to 0, only an MSS reset * Is will clear the register * */ #ifndef MSS_SEG_H #define MSS_SEG_H #include #ifdef __cplusplus extern "C" { #endif typedef struct { union { struct { volatile int32_t offset : 15; volatile int32_t rsrvd : 16; volatile int32_t locked : 1; } CFG; uint32_t raw; } u[8u]; uint32_t fill[64U-8U]; } seg_t; #define SEG ((seg_t*) 0x20005d00) #ifdef __cplusplus } #endif #endif /*MSS_SEG_H*/ mss_sysreg.h000066400000000000000000006736301432224323300364420ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /************************************************************************** * * @file mss_sysreg.h * @author Microchip-FPGA Embedded Systems Solutions * @brief Hardware register definitions. * */ #ifndef MSS_SYSREG_H #define MSS_SYSREG_H #include #ifdef __cplusplus extern "C" { #endif /* IO definitions (access restrictions to peripheral registers) */ /** \defgroup CMSIS_glob_defs CMSIS Global Defines IO Type Qualifiers are used \li to specify the access to peripheral variables. \li for automatic generation of peripheral register debug information. */ #ifndef __I #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permis sions */ #else #define __I volatile const /*!< Defines 'read only' permis sions */ #endif #endif #ifndef __O #define __O volatile /*!< Defines 'write only' permi ssions */ #endif #ifndef __IO #define __IO volatile /*!< Defines 'read / write' per missions */ #endif /* following defines should be used for structure members */ #ifndef __IM #define __IM volatile const /*! Defines 'read only' structu re member permissions */ #endif #ifndef __OM #define __OM volatile /*! Defines 'write only' struct ure member permissions */ #endif #ifndef __IOM #define __IOM volatile /*! Defines 'read / write' stru cture member permissions */ #endif /* Defines all Top Register offsets*/ /* Date of Source Revision File: 12-Jul-18*/ /* PROTOCOL=MSS; BASE=32'h20012000*/ /* Hardware Base Address*/ #define BASE32_ADDR_MSS_SYSREG 0x20002000 /*Register for software use*/ #define TEMP0_OFFSET 0x0 /* Scratch register for CPUS*/ #define TEMP0_DATA_OFFSET 0x0 #define TEMP0_DATA_MASK (0xFFFFFFFF << 0x0) /*Register for software use*/ #define TEMP1_OFFSET 0x4 /* Scratch register for CPUS*/ #define TEMP1_DATA_OFFSET 0x0 #define TEMP1_DATA_MASK (0xFFFFFFFF << 0x0) /*Master clock configuration*/ #define CLOCK_CONFIG_CR_OFFSET 0x8 /* "Sets the master synchronous clock divider bits [1:0] CPU clock divi der (Reset=/1 =0)bits [3:2] AXI clock divider (Reset=/ 1 =0)bits [5:4] AHB/APB clock divider (Reset=/2 =1)00=/1 01=/2 10=/4 11 =/8 (AHB/APB divider may not be set to /1)Note at reset MSS corner clock i s 80MHz therefore divider is set to divide by 1"*/ #define CLOCK_CONFIG_CR_DIVIDER_OFFSET 0x0 #define CLOCK_CONFIG_CR_DIVIDER_MASK (0x3F << 0x0) /* When '1' requests G5_control to enable the 1mHz (2MHz) on-chip oscil lator*/ #define CLOCK_CONFIG_CR_ENABLE_1MHZ_OFFSET 0x8 #define CLOCK_CONFIG_CR_ENABLE_1MHZ_MASK (0x01 << 0x8) /*RTC clock divider*/ #define RTC_CLOCK_CR_OFFSET 0xC /* "Sets the division ratio to create the internal RTC clock from the reference clock. The defaults sets the reference clock to 1MHz assuming the reference clock is 100Mhz.If the reference clock is 125MHz then 125 will c reate a 1MHz clockMax divider value is 4095 and value must be an integer.RT C clock must be less 2X the AXI clock rate."*/ #define RTC_CLOCK_CR_PERIOD_OFFSET 0x0 #define RTC_CLOCK_CR_PERIOD_MASK (0xFFF << 0x0) /* RTC Clock enable. When chaning the divider the enable should be trur ned off first the divider changed and the enable turned back on.*/ #define RTC_CLOCK_CR_ENABLE_OFFSET 0x10 #define RTC_CLOCK_CR_ENABLE_MASK (0x01 << 0x10) /*Fabric Reset mask*/ #define FABRIC_RESET_CR_OFFSET 0x10 /* Blocks the fabric Reset input preventing the fabric reseting the MSS */ #define FABRIC_RESET_CR_ENABLE_OFFSET 0x0 #define FABRIC_RESET_CR_ENABLE_MASK (0x01 << 0x0) /**/ #define BOOT_FAIL_CR_OFFSET 0x14 /* Written by firmware to indicate that the boot process failed drives the fab_boot_fail signal to the fabric. Is cleared by the fabric asserting fab_boot_fail_clear*/ #define BOOT_FAIL_CR_BOOT_OFFSET 0x0 #define BOOT_FAIL_CR_BOOT_MASK (0x01 << 0x0) /*Configuration lock*/ #define CONFIG_LOCK_CR_OFFSET 0x1C /* When written to '1' will cause all RWC registers to lock until a mas ter reset occurs.*/ #define CONFIG_LOCK_CR_LOCK_OFFSET 0x0 #define CONFIG_LOCK_CR_LOCK_MASK (0x01 << 0x0) /*Indicates which reset caused the last reset. After a reset occurs registe r should be read and then zero written to allow the next reset event to be correctly captured.*/ #define RESET_SR_OFFSET 0x20 /* Reset was caused by the SCB periphery reset signal*/ #define RESET_SR_SCB_PERIPH_RESET_OFFSET 0x0 #define RESET_SR_SCB_PERIPH_RESET_MASK (0x01 << RESET_SR_SCB_PERIPH_RESET_OFFSET) /* Reset was caused by the SCB MSS reset register*/ #define RESET_SR_SCB_MSS_RESET_OFFSET 0x1 #define RESET_SR_SCB_MSS_RESET_MASK (0x01 << RESET_SR_SCB_MSS_RESET_OFFSET) /* Reset was caused by the SCB CPU reset register*/ #define RESET_SR_SCB_CPU_RESET_OFFSET 0x2 #define RESET_SR_SCB_CPU_RESET_MASK (0x01 << RESET_SR_SCB_CPU_RESET_OFFSET) /* Reset was caused by the Risc-V Debugger*/ #define RESET_SR_DEBUGER_RESET_OFFSET 0x3 #define RESET_SR_DEBUGER_RESET_MASK (0x01 << RESET_SR_DEBUGER_RESET_OFFSET) /* Reset was caused by the fabric*/ #define RESET_SR_FABRIC_RESET_OFFSET 0x4 #define RESET_SR_FABRIC_RESET_MASK (0x01 << RESET_SR_FABRIC_RESET_OFFSET) /* Reset was caused by the watchdog*/ #define RESET_SR_WDOG_RESET_OFFSET 0x5 #define RESET_SR_WDOG_RESET_MASK (0x01 << RESET_SR_WDOG_RESET_OFFSET) /* Indicates that fabric asserted the GPIO reset inputs*/ #define RESET_SR_GPIO_RESET_OFFSET 0x6 #define RESET_SR_GPIO_RESET_MASK (0x01 << RESET_SR_GPIO_RESET_OFFSET) /* Indicates that SCB bus reset occurred (which causes warm reset of MS S)*/ #define RESET_SR_SCB_BUS_RESET_OFFSET 0x7 #define RESET_SR_SCB_BUS_RESET_MASK (0x01 << RESET_SR_SCB_BUS_RESET_OFFSET) #define RESET_SR_CPU_SOFT_RESET_OFFSET 0x8 #define RESET_SR_CPU_SOFTCB_BUS_RESET_MASK (0x01 << RESET_SR_CPU_SOFT_RESET_OFFSET) /*Indicates the device status in particular the state of the FPGA fabric an d the MSS IO banks*/ #define DEVICE_STATUS_OFFSET 0x24 /* Indicates the status of the core_up input from G5 Control.*/ #define DEVICE_STATUS_CORE_UP_OFFSET 0x0 #define DEVICE_STATUS_CORE_UP_MASK (0x01 << 0x0) /* Indicates the status of the lp_state input from G5 Control.*/ #define DEVICE_STATUS_LP_STATE_OFFSET 0x1 #define DEVICE_STATUS_LP_STATE_MASK (0x01 << 0x1) /* Indicates the status of the ff_in_progress input from G5 Control.*/ #define DEVICE_STATUS_FF_IN_PROGRESS_OFFSET 0x2 #define DEVICE_STATUS_FF_IN_PROGRESS_MASK (0x01 << 0x2) /* Indicates the status of the flash_valid input from G5 Control.*/ #define DEVICE_STATUS_FLASH_VALID_OFFSET 0x3 #define DEVICE_STATUS_FLASH_VALID_MASK (0x01 << 0x3) /* Power status of IO bank 2*/ #define DEVICE_STATUS_IO_BANK_B2_STATUS_OFFSET 0x8 #define DEVICE_STATUS_IO_BANK_B2_STATUS_MASK (0x01 << 0x8) /* Power status of IO bank 4*/ #define DEVICE_STATUS_IO_BANK_B4_STATUS_OFFSET 0x9 #define DEVICE_STATUS_IO_BANK_B4_STATUS_MASK (0x01 << 0x9) /* Power status of IO bank 5*/ #define DEVICE_STATUS_IO_BANK_B5_STATUS_OFFSET 0xA #define DEVICE_STATUS_IO_BANK_B5_STATUS_MASK (0x01 << 0xA) /* Power status of IO bank 6*/ #define DEVICE_STATUS_IO_BANK_B6_STATUS_OFFSET 0xB #define DEVICE_STATUS_IO_BANK_B6_STATUS_MASK (0x01 << 0xB) /* Indicates the status of the io_en input from G5 Control.*/ #define DEVICE_STATUS_IO_EN_OFFSET 0xC #define DEVICE_STATUS_IO_EN_MASK (0x01 << 0xC) /*MSS Build Info*/ #define MSS_BUILD_OFFSET 0x28 #define MSS_BUILD_REVISION_OFFSET 0x0 #define MSS_BUILD_REVISION_MASK (0xFFFFFFFF << 0x0) /*U54-1 Fabric interrupt enable*/ #define FAB_INTEN_U54_1_OFFSET 0x40 /* Enables the F2M_interrupts[31:0] to interrupt U54_1 directly*/ #define FAB_INTEN_U54_1_ENABLE_OFFSET 0x0 #define FAB_INTEN_U54_1_ENABLE_MASK (0xFFFFFFFF << 0x0) /*U54-2 Fabric interrupt enable*/ #define FAB_INTEN_U54_2_OFFSET 0x44 /* Enables the F2M_interrupts[31:0] to interrupt U54_1 directly*/ #define FAB_INTEN_U54_2_ENABLE_OFFSET 0x0 #define FAB_INTEN_U54_2_ENABLE_MASK (0xFFFFFFFF << 0x0) /*U54-3 Fabric interrupt enable*/ #define FAB_INTEN_U54_3_OFFSET 0x48 /* Enables the F2M_interrupts[31:0] to interrupt U54_1 directly*/ #define FAB_INTEN_U54_3_ENABLE_OFFSET 0x0 #define FAB_INTEN_U54_3_ENABLE_MASK (0xFFFFFFFF << 0x0) /*U54-4 Fabric interrupt enable*/ #define FAB_INTEN_U54_4_OFFSET 0x4C /* Enables the F2M_interrupts[31:0] to interrupt U54_1 directly*/ #define FAB_INTEN_U54_4_ENABLE_OFFSET 0x0 #define FAB_INTEN_U54_4_ENABLE_MASK (0xFFFFFFFF << 0x0) /*Allows the Ethernat interrupts to be directly routed to the U54 CPUS.*/ #define FAB_INTEN_MISC_OFFSET 0x50 /* Enables the Ethernet MAC0 to interrupt U54_1 directly*/ #define FAB_INTEN_MISC_MAC0_U54_1_OFFSET 0x0 #define FAB_INTEN_MISC_MAC0_U54_1_MASK (0x01 << 0x0) /* Enables the Ethernet MAC0 to interrupt U54_1 directly*/ #define FAB_INTEN_MISC_MAC0_U54_2_OFFSET 0x1 #define FAB_INTEN_MISC_MAC0_U54_2_MASK (0x01 << 0x1) /* Enables the Ethernet MAC1 to interrupt U54_1 directly*/ #define FAB_INTEN_MISC_MAC1_U54_3_OFFSET 0x2 #define FAB_INTEN_MISC_MAC1_U54_3_MASK (0x01 << 0x2) /* Enables the Ethernet MAC1 to interrupt U54_1 directly*/ #define FAB_INTEN_MISC_MAC1_U54_4_OFFSET 0x3 #define FAB_INTEN_MISC_MAC1_U54_4_MASK (0x01 << 0x3) /*Switches GPIO interrupt from PAD to Fabric GPIO*/ #define GPIO_INTERRUPT_FAB_CR_OFFSET 0x54 /* Setting these bits will disable the Pad interrupt and enable the fabric GPIO interrupt for bits 31:0. When the bit is set the Pad interrupt will be ORED into the GPIO0 & GPIO1 non-direct interrupts. When the bit is not set the Fabric interrupt is ORED into the GPIO2 non-direct interrupt. To prevent ORING then the interrupt should not be enabled in the GPIO block */ #define GPIO_INTERRUPT_FAB_CR_SELECT_OFFSET 0x0 #define GPIO_INTERRUPT_FAB_CR_SELECT_MASK (0xFFFFFFFF << 0x0) /*"AMP Mode peripheral mapping register. When the register bit is '0' the p eripheral is mapped into the 0x2000000 address range using AXI bus 5 from t he Coreplex. When the register bit is '1' the peripheral is mapped into the 0x28000000 address range using AXI bus 6 from the Coreplex."*/ #define APBBUS_CR_OFFSET 0x80 /* */ #define APBBUS_CR_MMUART0_OFFSET 0x0 #define APBBUS_CR_MMUART0_MASK (0x01 << 0x0) /* */ #define APBBUS_CR_MMUART1_OFFSET 0x1 #define APBBUS_CR_MMUART1_MASK (0x01 << 0x1) /* */ #define APBBUS_CR_MMUART2_OFFSET 0x2 #define APBBUS_CR_MMUART2_MASK (0x01 << 0x2) /* */ #define APBBUS_CR_MMUART3_OFFSET 0x3 #define APBBUS_CR_MMUART3_MASK (0x01 << 0x3) /* */ #define APBBUS_CR_MMUART4_OFFSET 0x4 #define APBBUS_CR_MMUART4_MASK (0x01 << 0x4) /* */ #define APBBUS_CR_WDOG0_OFFSET 0x5 #define APBBUS_CR_WDOG0_MASK (0x01 << 0x5) /* */ #define APBBUS_CR_WDOG1_OFFSET 0x6 #define APBBUS_CR_WDOG1_MASK (0x01 << 0x6) /* */ #define APBBUS_CR_WDOG2_OFFSET 0x7 #define APBBUS_CR_WDOG2_MASK (0x01 << 0x7) /* */ #define APBBUS_CR_WDOG3_OFFSET 0x8 #define APBBUS_CR_WDOG3_MASK (0x01 << 0x8) /* */ #define APBBUS_CR_WDOG4_OFFSET 0x9 #define APBBUS_CR_WDOG4_MASK (0x01 << 0x9) /* */ #define APBBUS_CR_SPI0_OFFSET 0xA #define APBBUS_CR_SPI0_MASK (0x01 << 0xA) /* */ #define APBBUS_CR_SPI1_OFFSET 0xB #define APBBUS_CR_SPI1_MASK (0x01 << 0xB) /* */ #define APBBUS_CR_I2C0_OFFSET 0xC #define APBBUS_CR_I2C0_MASK (0x01 << 0xC) /* */ #define APBBUS_CR_I2C1_OFFSET 0xD #define APBBUS_CR_I2C1_MASK (0x01 << 0xD) /* */ #define APBBUS_CR_CAN0_OFFSET 0xE #define APBBUS_CR_CAN0_MASK (0x01 << 0xE) /* */ #define APBBUS_CR_CAN1_OFFSET 0xF #define APBBUS_CR_CAN1_MASK (0x01 << 0xF) /* */ #define APBBUS_CR_GEM0_OFFSET 0x10 #define APBBUS_CR_GEM0_MASK (0x01 << 0x10) /* */ #define APBBUS_CR_GEM1_OFFSET 0x11 #define APBBUS_CR_GEM1_MASK (0x01 << 0x11) /* */ #define APBBUS_CR_TIMER_OFFSET 0x12 #define APBBUS_CR_TIMER_MASK (0x01 << 0x12) /* */ #define APBBUS_CR_GPIO0_OFFSET 0x13 #define APBBUS_CR_GPIO0_MASK (0x01 << 0x13) /* */ #define APBBUS_CR_GPIO1_OFFSET 0x14 #define APBBUS_CR_GPIO1_MASK (0x01 << 0x14) /* */ #define APBBUS_CR_GPIO2_OFFSET 0x15 #define APBBUS_CR_GPIO2_MASK (0x01 << 0x15) /* */ #define APBBUS_CR_RTC_OFFSET 0x16 #define APBBUS_CR_RTC_MASK (0x01 << 0x16) /* */ #define APBBUS_CR_M2FINT_OFFSET 0x17 #define APBBUS_CR_M2FINT_MASK (0x01 << 0x17) /*"Enables the clock to the MSS peripheral. By turning clocks off dynamic power can be saved. When the clock is off the peripheral should not be accessed the access may be ignored return unspecified data or result in bus response error."*/ #define SUBBLK_CLOCK_CR_OFFSET 0x84 /* */ #define SUBBLK_CLOCK_CR_ENVM_OFFSET 0x0 #define SUBBLK_CLOCK_CR_ENVM_MASK (0x01 << 0x0) /* */ #define SUBBLK_CLOCK_CR_MAC0_OFFSET 0x1 #define SUBBLK_CLOCK_CR_MAC0_MASK (0x01 << 0x1) /* */ #define SUBBLK_CLOCK_CR_MAC1_OFFSET 0x2 #define SUBBLK_CLOCK_CR_MAC1_MASK (0x01 << 0x2) /* */ #define SUBBLK_CLOCK_CR_MMC_OFFSET 0x3 #define SUBBLK_CLOCK_CR_MMC_MASK (0x01 << 0x3) /* */ #define SUBBLK_CLOCK_CR_TIMER_OFFSET 0x4 #define SUBBLK_CLOCK_CR_TIMER_MASK (0x01 << 0x4) /* */ #define SUBBLK_CLOCK_CR_MMUART0_OFFSET 0x5 #define SUBBLK_CLOCK_CR_MMUART0_MASK (0x01 << 0x5) /* */ #define SUBBLK_CLOCK_CR_MMUART1_OFFSET 0x6 #define SUBBLK_CLOCK_CR_MMUART1_MASK (0x01 << 0x6) /* */ #define SUBBLK_CLOCK_CR_MMUART2_OFFSET 0x7 #define SUBBLK_CLOCK_CR_MMUART2_MASK (0x01 << 0x7) /* */ #define SUBBLK_CLOCK_CR_MMUART3_OFFSET 0x8 #define SUBBLK_CLOCK_CR_MMUART3_MASK (0x01 << 0x8) /* */ #define SUBBLK_CLOCK_CR_MMUART4_OFFSET 0x9 #define SUBBLK_CLOCK_CR_MMUART4_MASK (0x01 << 0x9) /* */ #define SUBBLK_CLOCK_CR_SPI0_OFFSET 0xA #define SUBBLK_CLOCK_CR_SPI0_MASK (0x01 << 0xA) /* */ #define SUBBLK_CLOCK_CR_SPI1_OFFSET 0xB #define SUBBLK_CLOCK_CR_SPI1_MASK (0x01 << 0xB) /* */ #define SUBBLK_CLOCK_CR_I2C0_OFFSET 0xC #define SUBBLK_CLOCK_CR_I2C0_MASK (0x01 << 0xC) /* */ #define SUBBLK_CLOCK_CR_I2C1_OFFSET 0xD #define SUBBLK_CLOCK_CR_I2C1_MASK (0x01 << 0xD) /* */ #define SUBBLK_CLOCK_CR_CAN0_OFFSET 0xE #define SUBBLK_CLOCK_CR_CAN0_MASK (0x01 << 0xE) /* */ #define SUBBLK_CLOCK_CR_CAN1_OFFSET 0xF #define SUBBLK_CLOCK_CR_CAN1_MASK (0x01 << 0xF) /* */ #define SUBBLK_CLOCK_CR_USB_OFFSET 0x10 #define SUBBLK_CLOCK_CR_USB_MASK (0x01 << 0x10) /* */ #define SUBBLK_CLOCK_CR_RSVD_OFFSET 0x11 #define SUBBLK_CLOCK_CR_RSVD_MASK (0x01 << 0x11) /* */ #define SUBBLK_CLOCK_CR_RTC_OFFSET 0x12 #define SUBBLK_CLOCK_CR_RTC_MASK (0x01 << 0x12) /* */ #define SUBBLK_CLOCK_CR_QSPI_OFFSET 0x13 #define SUBBLK_CLOCK_CR_QSPI_MASK (0x01 << 0x13) /* */ #define SUBBLK_CLOCK_CR_GPIO0_OFFSET 0x14 #define SUBBLK_CLOCK_CR_GPIO0_MASK (0x01 << 0x14) /* */ #define SUBBLK_CLOCK_CR_GPIO1_OFFSET 0x15 #define SUBBLK_CLOCK_CR_GPIO1_MASK (0x01 << 0x15) /* */ #define SUBBLK_CLOCK_CR_GPIO2_OFFSET 0x16 #define SUBBLK_CLOCK_CR_GPIO2_MASK (0x01 << 0x16) /* */ #define SUBBLK_CLOCK_CR_DDRC_OFFSET 0x17 #define SUBBLK_CLOCK_CR_DDRC_MASK (0x01 << 0x17) /* */ #define SUBBLK_CLOCK_CR_FIC0_OFFSET 0x18 #define SUBBLK_CLOCK_CR_FIC0_MASK (0x01 << 0x18) /* */ #define SUBBLK_CLOCK_CR_FIC1_OFFSET 0x19 #define SUBBLK_CLOCK_CR_FIC1_MASK (0x01 << 0x19) /* */ #define SUBBLK_CLOCK_CR_FIC2_OFFSET 0x1A #define SUBBLK_CLOCK_CR_FIC2_MASK (0x01 << 0x1A) /* */ #define SUBBLK_CLOCK_CR_FIC3_OFFSET 0x1B #define SUBBLK_CLOCK_CR_FIC3_MASK (0x01 << 0x1B) /* */ #define SUBBLK_CLOCK_CR_ATHENA_OFFSET 0x1C #define SUBBLK_CLOCK_CR_ATHENA_MASK (0x01 << 0x1C) /* */ #define SUBBLK_CLOCK_CR_CFM_OFFSET 0x1D #define SUBBLK_CLOCK_CR_CFM_MASK (0x01 << 0x1D) /*"Holds the MSS peripherals in reset. When in reset the peripheral should not be accessed the acess may be ignored return unspecified data or result in bus response error."*/ #define SOFT_RESET_CR_OFFSET 0x88 /* */ #define SOFT_RESET_CR_ENVM_OFFSET 0x0 #define SOFT_RESET_CR_ENVM_MASK (0x01 << 0x0) /* */ #define SOFT_RESET_CR_MAC0_OFFSET 0x1 #define SOFT_RESET_CR_MAC0_MASK (0x01 << 0x1) /* */ #define SOFT_RESET_CR_MAC1_OFFSET 0x2 #define SOFT_RESET_CR_MAC1_MASK (0x01 << 0x2) /* */ #define SOFT_RESET_CR_MMC_OFFSET 0x3 #define SOFT_RESET_CR_MMC_MASK (0x01 << 0x3) /* */ #define SOFT_RESET_CR_TIMER_OFFSET 0x4 #define SOFT_RESET_CR_TIMER_MASK (0x01 << 0x4) /* */ #define SOFT_RESET_CR_MMUART0_OFFSET 0x5 #define SOFT_RESET_CR_MMUART0_MASK (0x01 << 0x5) /* */ #define SOFT_RESET_CR_MMUART1_OFFSET 0x6 #define SOFT_RESET_CR_MMUART1_MASK (0x01 << 0x6) /* */ #define SOFT_RESET_CR_MMUART2_OFFSET 0x7 #define SOFT_RESET_CR_MMUART2_MASK (0x01 << 0x7) /* */ #define SOFT_RESET_CR_MMUART3_OFFSET 0x8 #define SOFT_RESET_CR_MMUART3_MASK (0x01 << 0x8) /* */ #define SOFT_RESET_CR_MMUART4_OFFSET 0x9 #define SOFT_RESET_CR_MMUART4_MASK (0x01 << 0x9) /* */ #define SOFT_RESET_CR_SPI0_OFFSET 0xA #define SOFT_RESET_CR_SPI0_MASK (0x01 << 0xA) /* */ #define SOFT_RESET_CR_SPI1_OFFSET 0xB #define SOFT_RESET_CR_SPI1_MASK (0x01 << 0xB) /* */ #define SOFT_RESET_CR_I2C0_OFFSET 0xC #define SOFT_RESET_CR_I2C0_MASK (0x01 << 0xC) /* */ #define SOFT_RESET_CR_I2C1_OFFSET 0xD #define SOFT_RESET_CR_I2C1_MASK (0x01 << 0xD) /* */ #define SOFT_RESET_CR_CAN0_OFFSET 0xE #define SOFT_RESET_CR_CAN0_MASK (0x01 << 0xE) /* */ #define SOFT_RESET_CR_CAN1_OFFSET 0xF #define SOFT_RESET_CR_CAN1_MASK (0x01 << 0xF) /* */ #define SOFT_RESET_CR_USB_OFFSET 0x10 #define SOFT_RESET_CR_USB_MASK (0x01 << 0x10) /* */ #define SOFT_RESET_CR_FPGA_OFFSET 0x11 #define SOFT_RESET_CR_FPGA_MASK (0x01 << 0x11) /* */ #define SOFT_RESET_CR_RTC_OFFSET 0x12 #define SOFT_RESET_CR_RTC_MASK (0x01 << 0x12) /* */ #define SOFT_RESET_CR_QSPI_OFFSET 0x13 #define SOFT_RESET_CR_QSPI_MASK (0x01 << 0x13) /* */ #define SOFT_RESET_CR_GPIO0_OFFSET 0x14 #define SOFT_RESET_CR_GPIO0_MASK (0x01 << 0x14) /* */ #define SOFT_RESET_CR_GPIO1_OFFSET 0x15 #define SOFT_RESET_CR_GPIO1_MASK (0x01 << 0x15) /* */ #define SOFT_RESET_CR_GPIO2_OFFSET 0x16 #define SOFT_RESET_CR_GPIO2_MASK (0x01 << 0x16) /* */ #define SOFT_RESET_CR_DDRC_OFFSET 0x17 #define SOFT_RESET_CR_DDRC_MASK (0x01 << 0x17) /* */ #define SOFT_RESET_CR_FIC0_OFFSET 0x18 #define SOFT_RESET_CR_FIC0_MASK (0x01 << 0x18) /* */ #define SOFT_RESET_CR_FIC1_OFFSET 0x19 #define SOFT_RESET_CR_FIC1_MASK (0x01 << 0x19) /* */ #define SOFT_RESET_CR_FIC2_OFFSET 0x1A #define SOFT_RESET_CR_FIC2_MASK (0x01 << 0x1A) /* */ #define SOFT_RESET_CR_FIC3_OFFSET 0x1B #define SOFT_RESET_CR_FIC3_MASK (0x01 << 0x1B) /* */ #define SOFT_RESET_CR_ATHENA_OFFSET 0x1C #define SOFT_RESET_CR_ATHENA_MASK (0x01 << 0x1C) /* */ #define SOFT_RESET_CR_CFM_OFFSET 0x1D #define SOFT_RESET_CR_CFM_MASK (0x01 << 0x1D) /* Reset to Corner SGMII block*/ #define SOFT_RESET_CR_SGMII_OFFSET 0x1E #define SOFT_RESET_CR_SGMII_MASK (0x01 << 0x1E) /*Configures how many outstanding transfers the AXI-AHB bridges in front of f the USB and Crypto blocks should allow. (See Synopsys AXI-AHB bridge docu mentation)*/ #define AHBAXI_CR_OFFSET 0x8C /* Number of outstanding write transactions to USB block*/ #define AHBAXI_CR_USB_WBCNT_OFFSET 0x0 #define AHBAXI_CR_USB_WBCNT_MASK (0x0F << 0x0) /* Number of outstanding read transactions to USB block*/ #define AHBAXI_CR_USB_RBCNT_OFFSET 0x4 #define AHBAXI_CR_USB_RBCNT_MASK (0x0F << 0x4) /* Number of outstanding write transactions to Athena block*/ #define AHBAXI_CR_ATHENA_WBCNT_OFFSET 0x8 #define AHBAXI_CR_ATHENA_WBCNT_MASK (0x0F << 0x8) /* Number of outstanding read transactions to Athena block*/ #define AHBAXI_CR_ATHENA_RBCNT_OFFSET 0xC #define AHBAXI_CR_ATHENA_RBCNT_MASK (0x0F << 0xC) /*Configures the two AHB-APB bridges on S5 and S6*/ #define AHBAPB_CR_OFFSET 0x90 /* Enables posted mode on the AHB-APB bridge when set the AHB write cyc le will complete before the APB write cycle completes.*/ #define AHBAPB_CR_APB0_POSTED_OFFSET 0x0 #define AHBAPB_CR_APB0_POSTED_MASK (0x01 << 0x0) /* Enables posted mode on the AHB-APB bridge when set the AHB write cyc le will complete before the APB write cycle completes.*/ #define AHBAPB_CR_APB1_POSTED_OFFSET 0x1 #define AHBAPB_CR_APB1_POSTED_MASK (0x01 << 0x1) /*MSS Corner APB interface controls*/ #define DFIAPB_CR_OFFSET 0x98 /* Turns on the APB clock to the MSS Corner is off at reset. Once corne r blocks is configured the firmware may turn off the clock but periodically should turn back on to allow refresh of TMR registers inside the corner bl ock. */ #define DFIAPB_CR_CLOCKON_OFFSET 0x0 #define DFIAPB_CR_CLOCKON_MASK (0x01 << 0x0) /* Asserts the APB reset to the MSS corner is asserted at MSS reset.*/ #define DFIAPB_CR_RESET_OFFSET 0x1 #define DFIAPB_CR_RESET_MASK (0x01 << 0x1) /*GPIO Blocks reset control*/ #define GPIO_CR_OFFSET 0x9C /* "This signal selects whether the associated byte is reset by soft re set or the the MSS_GPIO_RESET_N signal from the FPGA fabric. The allowed va lues are:* 0: Selects MSS_GPIO_RESET_N signal from the FPGA fabric.* 1 : Selects the GPIO to be reset by the GPIO block soft reset signal .Bit 0 controls GPIO0 [7:0] and bit 1 GPIO[15:8]The master MSS reset will also r eset the GPIO register if not configured to use fabric reset."*/ #define GPIO_CR_GPIO0_SOFT_RESET_SELECT_OFFSET 0x0 #define GPIO_CR_GPIO0_SOFT_RESET_SELECT_MASK (0x03 << 0x0) /* "Sets the reset value off the GPIO0 per byteBit 0 controls GPIO0 [7: 0] and bit 1 GPIO[15:8]"*/ #define GPIO_CR_GPIO0_DEFAULT_OFFSET 0x4 #define GPIO_CR_GPIO0_DEFAULT_MASK (0x03 << 0x4) /* "This signal selects whether the associated byte is reset by soft re set or the the MSS_GPIO_RESET_N signal from the FPGA fabric. The allowed va lues are:* 0: Selects MSS_GPIO_RESET_N signal from the FPGA fabric.* 1 : Selects the GPIO to be reset by the GPIO block soft reset signal .Bit 0 controls GPIO0 [7:0] bit 1 GPIO[15:8] and bit 2 GPIO[23:16]The master MSS reset will also reset the GPIO register if not configured to use fabric res et."*/ #define GPIO_CR_GPIO1_SOFT_RESET_SELECT_OFFSET 0x8 #define GPIO_CR_GPIO1_SOFT_RESET_SELECT_MASK (0x07 << 0x8) /* "Sets the reset value off the GPIO0 per byteBit 0 controls GPIO0 [7: 0] bit 1 GPIO[15:8] and bit 2 GPIO[23:16]"*/ #define GPIO_CR_GPIO1_DEFAULT_OFFSET 0xC #define GPIO_CR_GPIO1_DEFAULT_MASK (0x07 << 0xC) /* "This signal selects whether the associated byte is reset by soft re set or the the MSS_GPIO_RESET_N signal from the FPGA fabric. The allowed va lues are:* 0: Selects MSS_GPIO_RESET_N signal from the FPGA fabric.* 1 : Selects the GPIO to be reset by the GPIO block soft reset signal .Bit 0 controls GPIO0 [7:0] bit 1 GPIO[15:8] and bit 1 GPIO[23:16] and bit 3 GPIO [31:24]The master MSS reset will also reset the GPIO register if not config ured to use fabric reset."*/ #define GPIO_CR_GPIO2_SOFT_RESET_SELECT_OFFSET 0x10 #define GPIO_CR_GPIO2_SOFT_RESET_SELECT_MASK (0x0F << 0x10) /* "Sets the reset value off the GPIO0 per byteBit 0 controls GPIO0 [7: 0] bit 1 GPIO[15:8] and bit 1 GPIO[23:16] and bit 3 GPIO[31:24]"*/ #define GPIO_CR_GPIO2_DEFAULT_OFFSET 0x14 #define GPIO_CR_GPIO2_DEFAULT_MASK (0x0F << 0x14) /*MAC0 configuration register*/ #define MAC0_CR_OFFSET 0xA4 /* Current speed mode on the MAC*/ #define MAC0_CR_SPEED_MODE_OFFSET 0x0 #define MAC0_CR_SPEED_MODE_MASK (0x0F << 0x0) /*MAC1 configuration register*/ #define MAC1_CR_OFFSET 0xA8 /* Current speed mode on the MAC*/ #define MAC1_CR_SPEED_MODE_OFFSET 0x0 #define MAC1_CR_SPEED_MODE_MASK (0x0F << 0x0) /*USB Configuration register*/ #define USB_CR_OFFSET 0xAC /* "Configures USB for Single-Data Rate(SDR) mode or Double-Data Rate(D DR) mode. 0 - SDR Mode is selected1 - DDR Mode is selected (Not supported i n G5 or G5)"*/ #define USB_CR_DDR_SELECT_OFFSET 0x0 #define USB_CR_DDR_SELECT_MASK (0x01 << 0x0) /* When '1' will stops the clock to the USB core when the core asserts its POWERDOWN output. For G4 compatibility this bit defaults to 0.*/ #define USB_CR_POWERDOWN_ENABLE_OFFSET 0x1 #define USB_CR_POWERDOWN_ENABLE_MASK (0x01 << 0x1) /* Indicates that the USB CLK may be stopped to save power. Derived fro m combination of signals from CLK & XCLK flip-flops AVALID VBUSVALID and LI NESTATE. When asserted the USB clock into the core is stopped.*/ #define USB_CR_POWERDOWN_OFFSET 0x2 #define USB_CR_POWERDOWN_MASK (0x01 << 0x2) /* Set when entry is made into CarKit mode and cleared on exit from Car Kit mode.*/ #define USB_CR_LPI_CARKIT_EN_OFFSET 0x3 #define USB_CR_LPI_CARKIT_EN_MASK (0x01 << 0x3) /*Crypto Mesh control and status register*/ #define MESH_CR_OFFSET 0xB0 /* Writing a 1 will start the Mesh System*/ #define MESH_CR_START_OFFSET 0x0 #define MESH_CR_START_MASK (0x01 << 0x0) /* "Sets the amount of time that the mesh is held active for actual hol d time includes up to 256 us of random variation.Minimum Time = 1 + 256 * v alue usMaximum Time = 1 + 256 * (1+value) usValue must be greater than 0"*/ #define MESH_CR_HOLD_OFFSET 0x1 #define MESH_CR_HOLD_MASK (0xFFF << 0x1) /* When set will inject an error in the mesh*/ #define MESH_CR_INJECT_ERROR_OFFSET 0x10 #define MESH_CR_INJECT_ERROR_MASK (0x01 << 0x10) /* Indicates that Mesh detected an error. Cleared by writing a '1'*/ #define MESH_CR_MESH_ERROR_OFFSET 0x18 #define MESH_CR_MESH_ERROR_MASK (0x01 << 0x18) /* Indicates that the Mesh is functioning correctly. Will be set approx imately 520 clock cycles after mesh started and stay set as long as the me sh is not detecting any errors.*/ #define MESH_CR_OKAY_OFFSET 0x19 #define MESH_CR_OKAY_MASK (0x01 << 0x19) /*Crypto mesh seed and update rate*/ #define MESH_SEED_CR_OFFSET 0xB4 /* Sets the mesh seed value any value may be used zero should be avoide d*/ #define MESH_SEED_CR_SEED_OFFSET 0x0 #define MESH_SEED_CR_SEED_MASK (0x7FFFFF << 0x0) /* Sets the rate that the mesh value is changed. Rate = AHBCLK/(clkrate +1). Rate must be less than 1MHz setting slower will reduce power consumpti on.*/ #define MESH_SEED_CR_CLKRATE_OFFSET 0x18 #define MESH_SEED_CR_CLKRATE_MASK (0xFF << 0x18) /*ENVM AHB Controller setup*/ #define ENVM_CR_OFFSET 0xB8 /* "Sets the number of AHB cycles used to generate the PNVM clockClock period = (Value+1) * (1000/AHBFREQMHZ) Value must be 1 to 63 (0 defaults to 15)e.g.11 will generate a 40ns period 25MHz clock if the AHB clock is 250MHz15 will generate a 40ns period 25MHz clock if the AHB cloc k is 400MHz"*/ #define ENVM_CR_CLOCK_PERIOD_OFFSET 0x0 #define ENVM_CR_CLOCK_PERIOD_MASK (0x3F << 0x0) /* Indicates the eNVM is running at the configured divider rate. */ #define ENVM_CR_CLOCK_OKAY_OFFSET 0x6 #define ENVM_CR_CLOCK_OKAY_MASK (0x01 << 0x6) /* When '1' the PNVM clock will be always generated and not stopped bet ween access cycles. Setting this will increase access latency but mean that the PNVM clock operates at a stable rate.*/ #define ENVM_CR_CLOCK_CONTINUOUS_OFFSET 0x8 #define ENVM_CR_CLOCK_CONTINUOUS_MASK (0x01 << 0x8) /* When set suppresses clock edge between C-Bus access cycles so that t hey appear as consecutive access cycles.*/ #define ENVM_CR_CLOCK_SUPPRESS_OFFSET 0x9 #define ENVM_CR_CLOCK_SUPPRESS_MASK (0x01 << 0x9) /* "Enables ""read-ahead"" on the ENVM controller. The controller will automatically read the next PNVM location as soon as possible ahead of the AHB request. This will improve read performance when incrementing though memory as the NVM reads and AHB cycles are pipelined. When set non incrementing accesses will take longer as the controller may be in the process of reading the next address and the PNVM cycle needs to complete prior to starting the required read"*/ #define ENVM_CR_READAHEAD_OFFSET 0x10 #define ENVM_CR_READAHEAD_MASK (0x01 << 0x10) /* When '1' the controller will initiate separate ENVM reads for all reads. No buffering or speculative operations will be carried out. When performing word reads incrementing through PNVM each location will be read twice (intended for test use)*/ #define ENVM_CR_SLOWREAD_OFFSET 0x11 #define ENVM_CR_SLOWREAD_MASK (0x01 << 0x11) /* Enable the ENVM interrupt*/ #define ENVM_CR_INTERRUPT_ENABLE_OFFSET 0x12 #define ENVM_CR_INTERRUPT_ENABLE_MASK (0x01 << 0x12) /* "Sets the duration of the timer used to detect a non response of slow response from the PNVM on C and R bus accesses.Timer Duration = Value * (1000/AHBFREQMHZ) 0x00: Timer disabled. If the timer expires the AHB cycle is terminates using the HRESP protocol"*/ #define ENVM_CR_TIMER_OFFSET 0x18 #define ENVM_CR_TIMER_MASK (0xFF << 0x18) /*Reserved*/ #define RESERVED_BC_OFFSET 0xBC /* Reserved register address*/ #define RESERVED_BC_RESERVED_OFFSET 0x0 #define RESERVED_BC_RESERVED_MASK (0x01 << 0x0) /*QOS Athena USB & MMC Configuration*/ #define QOS_PERIPHERAL_CR_OFFSET 0xC0 /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_ATHENA_READ_OFFSET 0x0 #define QOS_PERIPHERAL_CR_ATHENA_READ_MASK (0x0F << 0x0) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_ATHENA_WRITE_OFFSET 0x4 #define QOS_PERIPHERAL_CR_ATHENA_WRITE_MASK (0x0F << 0x4) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_USB_READ_OFFSET 0x8 #define QOS_PERIPHERAL_CR_USB_READ_MASK (0x0F << 0x8) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_USB_WRITE_OFFSET 0xC #define QOS_PERIPHERAL_CR_USB_WRITE_MASK (0x0F << 0xC) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_MMC_READ_OFFSET 0x10 #define QOS_PERIPHERAL_CR_MMC_READ_MASK (0x0F << 0x10) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_MMC_WRITE_OFFSET 0x14 #define QOS_PERIPHERAL_CR_MMC_WRITE_MASK (0x0F << 0x14) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_TRACE_READ_OFFSET 0x18 #define QOS_PERIPHERAL_CR_TRACE_READ_MASK (0x0F << 0x18) /* Sets the QOS value from the specified device into the switch*/ #define QOS_PERIPHERAL_CR_TRACE_WRITE_OFFSET 0x1C #define QOS_PERIPHERAL_CR_TRACE_WRITE_MASK (0x0F << 0x1C) /*QOS Configuration Coreplex*/ #define QOS_CPLEXIO_CR_OFFSET 0xC4 /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_DEVICE0_READ_OFFSET 0x0 #define QOS_CPLEXIO_CR_DEVICE0_READ_MASK (0x0F << 0x0) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_DEVICE0_WRITE_OFFSET 0x4 #define QOS_CPLEXIO_CR_DEVICE0_WRITE_MASK (0x0F << 0x4) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_DEVICE1_READ_OFFSET 0x8 #define QOS_CPLEXIO_CR_DEVICE1_READ_MASK (0x0F << 0x8) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_DEVICE1_WRITE_OFFSET 0xC #define QOS_CPLEXIO_CR_DEVICE1_WRITE_MASK (0x0F << 0xC) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_FABRIC0_READ_OFFSET 0x10 #define QOS_CPLEXIO_CR_FABRIC0_READ_MASK (0x0F << 0x10) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_FABRIC0_WRITE_OFFSET 0x14 #define QOS_CPLEXIO_CR_FABRIC0_WRITE_MASK (0x0F << 0x14) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_FABRIC1_READ_OFFSET 0x18 #define QOS_CPLEXIO_CR_FABRIC1_READ_MASK (0x0F << 0x18) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXIO_CR_FABRIC1_WRITE_OFFSET 0x1C #define QOS_CPLEXIO_CR_FABRIC1_WRITE_MASK (0x0F << 0x1C) /*QOS configuration DDRC*/ #define QOS_CPLEXDDR_CR_OFFSET 0xC8 /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXDDR_CR_CACHE_READ_OFFSET 0x0 #define QOS_CPLEXDDR_CR_CACHE_READ_MASK (0x0F << 0x0) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXDDR_CR_CACHE_WRITE_OFFSET 0x4 #define QOS_CPLEXDDR_CR_CACHE_WRITE_MASK (0x0F << 0x4) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXDDR_CR_NCACHE_READ_OFFSET 0x8 #define QOS_CPLEXDDR_CR_NCACHE_READ_MASK (0x0F << 0x8) /* Sets the QOS value from the specified device into the switch*/ #define QOS_CPLEXDDR_CR_NCACHE_WRITE_OFFSET 0xC #define QOS_CPLEXDDR_CR_NCACHE_WRITE_MASK (0x0F << 0xC) /*Indicates that a master caused a MPU violation. Interrupts via maintenanc e interrupt.*/ #define MPU_VIOLATION_SR_OFFSET 0xF0 /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_FIC0_OFFSET 0x0 #define MPU_VIOLATION_SR_FIC0_MASK (0x01 << 0x0) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_FIC1_OFFSET 0x1 #define MPU_VIOLATION_SR_FIC1_MASK (0x01 << 0x1) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_FIC2_OFFSET 0x2 #define MPU_VIOLATION_SR_FIC2_MASK (0x01 << 0x2) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_ATHENA_OFFSET 0x3 #define MPU_VIOLATION_SR_ATHENA_MASK (0x01 << 0x3) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_GEM0_OFFSET 0x4 #define MPU_VIOLATION_SR_GEM0_MASK (0x01 << 0x4) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_GEM1_OFFSET 0x5 #define MPU_VIOLATION_SR_GEM1_MASK (0x01 << 0x5) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_USB_OFFSET 0x6 #define MPU_VIOLATION_SR_USB_MASK (0x01 << 0x6) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_MMC_OFFSET 0x7 #define MPU_VIOLATION_SR_MMC_MASK (0x01 << 0x7) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_SCB_OFFSET 0x8 #define MPU_VIOLATION_SR_SCB_MASK (0x01 << 0x8) /* Bit is set on violation. Cleared by writing '1'*/ #define MPU_VIOLATION_SR_TRACE_OFFSET 0x9 #define MPU_VIOLATION_SR_TRACE_MASK (0x01 << 0x9) /*Enables interrupts on MPU violations*/ #define MPU_VIOLATION_INTEN_CR_OFFSET 0xF4 /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_FIC0_OFFSET 0x0 #define MPU_VIOLATION_INTEN_CR_FIC0_MASK (0x01 << 0x0) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_FIC1_OFFSET 0x1 #define MPU_VIOLATION_INTEN_CR_FIC1_MASK (0x01 << 0x1) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_FIC2_OFFSET 0x2 #define MPU_VIOLATION_INTEN_CR_FIC2_MASK (0x01 << 0x2) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_ATHENA_OFFSET 0x3 #define MPU_VIOLATION_INTEN_CR_ATHENA_MASK (0x01 << 0x3) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_GEM0_OFFSET 0x4 #define MPU_VIOLATION_INTEN_CR_GEM0_MASK (0x01 << 0x4) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_GEM1_OFFSET 0x5 #define MPU_VIOLATION_INTEN_CR_GEM1_MASK (0x01 << 0x5) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_USB_OFFSET 0x6 #define MPU_VIOLATION_INTEN_CR_USB_MASK (0x01 << 0x6) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_MMC_OFFSET 0x7 #define MPU_VIOLATION_INTEN_CR_MMC_MASK (0x01 << 0x7) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_SCB_OFFSET 0x8 #define MPU_VIOLATION_INTEN_CR_SCB_MASK (0x01 << 0x8) /* Enables the interrupt*/ #define MPU_VIOLATION_INTEN_CR_TRACE_OFFSET 0x9 #define MPU_VIOLATION_INTEN_CR_TRACE_MASK (0x01 << 0x9) /*AXI switch decode fail*/ #define SW_FAIL_ADDR0_CR_OFFSET 0xF8 /* The address (bits 31:0) that failed. Reading this address as 64-bits will return the 38-bit address in a single read combined with additional i nformation in the next register*/ #define SW_FAIL_ADDR0_CR_ADDR_OFFSET 0x0 #define SW_FAIL_ADDR0_CR_ADDR_MASK (0xFFFFFFFF << 0x0) /*AXI switch decode fail*/ #define SW_FAIL_ADDR1_CR_OFFSET 0xFC /* Upper 6 bits off address [37:32]*/ #define SW_FAIL_ADDR1_CR_ADDR_OFFSET 0x0 #define SW_FAIL_ADDR1_CR_ADDR_MASK (0x3F << 0x0) /* AXI ID off failure*/ #define SW_FAIL_ADDR1_CR_ID_OFFSET 0x8 #define SW_FAIL_ADDR1_CR_ID_MASK (0xFF << 0x8) /* AXI write=1 or read=0*/ #define SW_FAIL_ADDR1_CR_WRITE_OFFSET 0x10 #define SW_FAIL_ADDR1_CR_WRITE_MASK (0x01 << 0x10) /* */ #define SW_FAIL_ADDR1_CR_FAILED_OFFSET 0x11 #define SW_FAIL_ADDR1_CR_FAILED_MASK (0x01 << 0x11) /*Set when an ECC event happens*/ #define EDAC_SR_OFFSET 0x100 /* */ #define EDAC_SR_MMC_1E_OFFSET 0x0 #define EDAC_SR_MMC_1E_MASK (0x01 << 0x0) /* */ #define EDAC_SR_MMC_2E_OFFSET 0x1 #define EDAC_SR_MMC_2E_MASK (0x01 << 0x1) /* */ #define EDAC_SR_DDRC_1E_OFFSET 0x2 #define EDAC_SR_DDRC_1E_MASK (0x01 << 0x2) /* */ #define EDAC_SR_DDRC_2E_OFFSET 0x3 #define EDAC_SR_DDRC_2E_MASK (0x01 << 0x3) /* */ #define EDAC_SR_MAC0_1E_OFFSET 0x4 #define EDAC_SR_MAC0_1E_MASK (0x01 << 0x4) /* */ #define EDAC_SR_MAC0_2E_OFFSET 0x5 #define EDAC_SR_MAC0_2E_MASK (0x01 << 0x5) /* */ #define EDAC_SR_MAC1_1E_OFFSET 0x6 #define EDAC_SR_MAC1_1E_MASK (0x01 << 0x6) /* */ #define EDAC_SR_MAC1_2E_OFFSET 0x7 #define EDAC_SR_MAC1_2E_MASK (0x01 << 0x7) /* */ #define EDAC_SR_USB_1E_OFFSET 0x8 #define EDAC_SR_USB_1E_MASK (0x01 << 0x8) /* */ #define EDAC_SR_USB_2E_OFFSET 0x9 #define EDAC_SR_USB_2E_MASK (0x01 << 0x9) /* */ #define EDAC_SR_CAN0_1E_OFFSET 0xA #define EDAC_SR_CAN0_1E_MASK (0x01 << 0xA) /* */ #define EDAC_SR_CAN0_2E_OFFSET 0xB #define EDAC_SR_CAN0_2E_MASK (0x01 << 0xB) /* */ #define EDAC_SR_CAN1_1E_OFFSET 0xC #define EDAC_SR_CAN1_1E_MASK (0x01 << 0xC) /* */ #define EDAC_SR_CAN1_2E_OFFSET 0xD #define EDAC_SR_CAN1_2E_MASK (0x01 << 0xD) /*Enables ECC interrupt on event*/ #define EDAC_INTEN_CR_OFFSET 0x104 /* */ #define EDAC_INTEN_CR_MMC_1E_OFFSET 0x0 #define EDAC_INTEN_CR_MMC_1E_MASK (0x01 << 0x0) /* */ #define EDAC_INTEN_CR_MMC_2E_OFFSET 0x1 #define EDAC_INTEN_CR_MMC_2E_MASK (0x01 << 0x1) /* */ #define EDAC_INTEN_CR_DDRC_1E_OFFSET 0x2 #define EDAC_INTEN_CR_DDRC_1E_MASK (0x01 << 0x2) /* */ #define EDAC_INTEN_CR_DDRC_2E_OFFSET 0x3 #define EDAC_INTEN_CR_DDRC_2E_MASK (0x01 << 0x3) /* */ #define EDAC_INTEN_CR_MAC0_1E_OFFSET 0x4 #define EDAC_INTEN_CR_MAC0_1E_MASK (0x01 << 0x4) /* */ #define EDAC_INTEN_CR_MAC0_2E_OFFSET 0x5 #define EDAC_INTEN_CR_MAC0_2E_MASK (0x01 << 0x5) /* */ #define EDAC_INTEN_CR_MAC1_1E_OFFSET 0x6 #define EDAC_INTEN_CR_MAC1_1E_MASK (0x01 << 0x6) /* */ #define EDAC_INTEN_CR_MAC1_2E_OFFSET 0x7 #define EDAC_INTEN_CR_MAC1_2E_MASK (0x01 << 0x7) /* */ #define EDAC_INTEN_CR_USB_1E_OFFSET 0x8 #define EDAC_INTEN_CR_USB_1E_MASK (0x01 << 0x8) /* */ #define EDAC_INTEN_CR_USB_2E_OFFSET 0x9 #define EDAC_INTEN_CR_USB_2E_MASK (0x01 << 0x9) /* */ #define EDAC_INTEN_CR_CAN0_1E_OFFSET 0xA #define EDAC_INTEN_CR_CAN0_1E_MASK (0x01 << 0xA) /* */ #define EDAC_INTEN_CR_CAN0_2E_OFFSET 0xB #define EDAC_INTEN_CR_CAN0_2E_MASK (0x01 << 0xB) /* */ #define EDAC_INTEN_CR_CAN1_1E_OFFSET 0xC #define EDAC_INTEN_CR_CAN1_1E_MASK (0x01 << 0xC) /* */ #define EDAC_INTEN_CR_CAN1_2E_OFFSET 0xD #define EDAC_INTEN_CR_CAN1_2E_MASK (0x01 << 0xD) /*Count off single bit errors*/ #define EDAC_CNT_MMC_OFFSET 0x108 /* */ #define EDAC_CNT_MMC_COUNT_OFFSET 0x0 #define EDAC_CNT_MMC_COUNT_MASK (0x3FF << 0x0) /*Count off single bit errors*/ #define EDAC_CNT_DDRC_OFFSET 0x10C /* */ #define EDAC_CNT_DDRC_COUNT_OFFSET 0x0 #define EDAC_CNT_DDRC_COUNT_MASK (0x3FF << 0x0) /*Count off single bit errors*/ #define EDAC_CNT_MAC0_OFFSET 0x110 /* */ #define EDAC_CNT_MAC0_COUNT_OFFSET 0x0 #define EDAC_CNT_MAC0_COUNT_MASK (0x3FF << 0x0) /*Count off single bit errors*/ #define EDAC_CNT_MAC1_OFFSET 0x114 /* */ #define EDAC_CNT_MAC1_COUNT_OFFSET 0x0 #define EDAC_CNT_MAC1_COUNT_MASK (0x3FF << 0x0) /*Count off single bit errors*/ #define EDAC_CNT_USB_OFFSET 0x118 /* */ #define EDAC_CNT_USB_COUNT_OFFSET 0x0 #define EDAC_CNT_USB_COUNT_MASK (0x3FF << 0x0) /*Count off single bit errors*/ #define EDAC_CNT_CAN0_OFFSET 0x11C /* */ #define EDAC_CNT_CAN0_COUNT_OFFSET 0x0 #define EDAC_CNT_CAN0_COUNT_MASK (0x3FF << 0x0) /*Count off single bit errors*/ #define EDAC_CNT_CAN1_OFFSET 0x120 /* */ #define EDAC_CNT_CAN1_COUNT_OFFSET 0x0 #define EDAC_CNT_CAN1_COUNT_MASK (0x3FF << 0x0) /*"Will Corrupt write data to rams 1E corrupts bit 0 2E bits 1 and 2.Inject s Errors into all RAMS in the block as long as the bits are set. Setting 1E and 2E will inject a 3-bit error"*/ #define EDAC_INJECT_CR_OFFSET 0x124 /* */ #define EDAC_INJECT_CR_MMC_1E_OFFSET 0x0 #define EDAC_INJECT_CR_MMC_1E_MASK (0x01 << 0x0) /* */ #define EDAC_INJECT_CR_MMC_2E_OFFSET 0x1 #define EDAC_INJECT_CR_MMC_2E_MASK (0x01 << 0x1) /* */ #define EDAC_INJECT_CR_DDRC_1E_OFFSET 0x2 #define EDAC_INJECT_CR_DDRC_1E_MASK (0x01 << 0x2) /* */ #define EDAC_INJECT_CR_DDRC_2E_OFFSET 0x3 #define EDAC_INJECT_CR_DDRC_2E_MASK (0x01 << 0x3) /* */ #define EDAC_INJECT_CR_MAC0_1E_OFFSET 0x4 #define EDAC_INJECT_CR_MAC0_1E_MASK (0x01 << 0x4) /* */ #define EDAC_INJECT_CR_MAC0_2E_OFFSET 0x5 #define EDAC_INJECT_CR_MAC0_2E_MASK (0x01 << 0x5) /* */ #define EDAC_INJECT_CR_MAC1_1E_OFFSET 0x6 #define EDAC_INJECT_CR_MAC1_1E_MASK (0x01 << 0x6) /* */ #define EDAC_INJECT_CR_MAC1_2E_OFFSET 0x7 #define EDAC_INJECT_CR_MAC1_2E_MASK (0x01 << 0x7) /* */ #define EDAC_INJECT_CR_USB_1E_OFFSET 0x8 #define EDAC_INJECT_CR_USB_1E_MASK (0x01 << 0x8) /* */ #define EDAC_INJECT_CR_USB_2E_OFFSET 0x9 #define EDAC_INJECT_CR_USB_2E_MASK (0x01 << 0x9) /* */ #define EDAC_INJECT_CR_CAN0_1E_OFFSET 0xA #define EDAC_INJECT_CR_CAN0_1E_MASK (0x01 << 0xA) /* */ #define EDAC_INJECT_CR_CAN0_2E_OFFSET 0xB #define EDAC_INJECT_CR_CAN0_2E_MASK (0x01 << 0xB) /* */ #define EDAC_INJECT_CR_CAN1_1E_OFFSET 0xC #define EDAC_INJECT_CR_CAN1_1E_MASK (0x01 << 0xC) /* */ #define EDAC_INJECT_CR_CAN1_2E_OFFSET 0xD #define EDAC_INJECT_CR_CAN1_2E_MASK (0x01 << 0xD) /*Maintenance Interrupt Enable.*/ #define MAINTENANCE_INTEN_CR_OFFSET 0x140 /* Enables interrupt on a PLL event PLL_STATUS_INTEN_CR should also be set*/ #define MAINTENANCE_INTEN_CR_PLL_OFFSET 0x0 #define MAINTENANCE_INTEN_CR_PLL_MASK (0x01 << 0x0) /* Enables interrupt on a MPU access violation */ #define MAINTENANCE_INTEN_CR_MPU_OFFSET 0x1 #define MAINTENANCE_INTEN_CR_MPU_MASK (0x01 << 0x1) /* Enables interrupt on a AXI switch decode error*/ #define MAINTENANCE_INTEN_CR_DECODE_OFFSET 0x2 #define MAINTENANCE_INTEN_CR_DECODE_MASK (0x01 << 0x2) /* Enables interrupt as lp_state goes high*/ #define MAINTENANCE_INTEN_CR_LP_STATE_ENTER_OFFSET 0x3 #define MAINTENANCE_INTEN_CR_LP_STATE_ENTER_MASK (0x01 << 0x3) /* Enables interrupt as lp_state goes low*/ #define MAINTENANCE_INTEN_CR_LP_STATE_EXIT_OFFSET 0x4 #define MAINTENANCE_INTEN_CR_LP_STATE_EXIT_MASK (0x01 << 0x4) /* Enables interrupt as flash_freeze goes high*/ #define MAINTENANCE_INTEN_CR_FF_START_OFFSET 0x5 #define MAINTENANCE_INTEN_CR_FF_START_MASK (0x01 << 0x5) /* Enables interrupt as flash_freeze goes low*/ #define MAINTENANCE_INTEN_CR_FF_END_OFFSET 0x6 #define MAINTENANCE_INTEN_CR_FF_END_MASK (0x01 << 0x6) /* Enables interrupt when FPGA turned on*/ #define MAINTENANCE_INTEN_CR_FPGA_ON_OFFSET 0x7 #define MAINTENANCE_INTEN_CR_FPGA_ON_MASK (0x01 << 0x7) /* Enables interrupt when FPGA turned off*/ #define MAINTENANCE_INTEN_CR_FPGA_OFF_OFFSET 0x8 #define MAINTENANCE_INTEN_CR_FPGA_OFF_MASK (0x01 << 0x8) /* Enables interrupt on SCB error*/ #define MAINTENANCE_INTEN_CR_SCB_ERROR_OFFSET 0x9 #define MAINTENANCE_INTEN_CR_SCB_ERROR_MASK (0x01 << 0x9) /* Enables interrupt on SCB failure*/ #define MAINTENANCE_INTEN_CR_SCB_FAULT_OFFSET 0xA #define MAINTENANCE_INTEN_CR_SCB_FAULT_MASK (0x01 << 0xA) /* Enables interrupt on Mesh violation detection */ #define MAINTENANCE_INTEN_CR_MESH_ERROR_OFFSET 0xB #define MAINTENANCE_INTEN_CR_MESH_ERROR_MASK (0x01 << 0xB) /* Enables interrupt on bank2 powered on*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B2_ON_OFFSET 0xC #define MAINTENANCE_INTEN_CR_IO_BANK_B2_ON_MASK (0x01 << 0xC) /* Enables interrupt on bank4 powered on*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B4_ON_OFFSET 0xD #define MAINTENANCE_INTEN_CR_IO_BANK_B4_ON_MASK (0x01 << 0xD) /* Enables interrupt on bank5 powered on*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B5_ON_OFFSET 0xE #define MAINTENANCE_INTEN_CR_IO_BANK_B5_ON_MASK (0x01 << 0xE) /* Enables interrupt on bank6 powered on*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B6_ON_OFFSET 0xF #define MAINTENANCE_INTEN_CR_IO_BANK_B6_ON_MASK (0x01 << 0xF) /* Enables interrupt on bank2 powered off*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B2_OFF_OFFSET 0x10 #define MAINTENANCE_INTEN_CR_IO_BANK_B2_OFF_MASK (0x01 << 0x10) /* Enables interrupt on bank4 powered off*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B4_OFF_OFFSET 0x11 #define MAINTENANCE_INTEN_CR_IO_BANK_B4_OFF_MASK (0x01 << 0x11) /* Enables interrupt on bank5 powered off*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B5_OFF_OFFSET 0x12 #define MAINTENANCE_INTEN_CR_IO_BANK_B5_OFF_MASK (0x01 << 0x12) /* Enables interrupt on bank6 powered off*/ #define MAINTENANCE_INTEN_CR_IO_BANK_B6_OFF_OFFSET 0x13 #define MAINTENANCE_INTEN_CR_IO_BANK_B6_OFF_MASK (0x01 << 0x13) /* Enables interrupt on a DLL event DLL_STATUS_INTEN_CR should also be set*/ #define MAINTENANCE_INTEN_CR_DLL_OFFSET 0x14 #define MAINTENANCE_INTEN_CR_DLL_MASK (0x01 << 0x14) /*PLL Status interrupt enables*/ #define PLL_STATUS_INTEN_CR_OFFSET 0x144 /* Enables interrupt on CPU PLL locking*/ #define PLL_STATUS_INTEN_CR_CPU_LOCK_OFFSET 0x0 #define PLL_STATUS_INTEN_CR_CPU_LOCK_MASK (0x01 << 0x0) /* Enables interrupt on DFT PLL locking*/ #define PLL_STATUS_INTEN_CR_DFI_LOCK_OFFSET 0x1 #define PLL_STATUS_INTEN_CR_DFI_LOCK_MASK (0x01 << 0x1) /* Enables interrupt on SGMII PLL locking*/ #define PLL_STATUS_INTEN_CR_SGMII_LOCK_OFFSET 0x2 #define PLL_STATUS_INTEN_CR_SGMII_LOCK_MASK (0x01 << 0x2) /* Enables interrupt on CPU PLL unlocking*/ #define PLL_STATUS_INTEN_CR_CPU_UNLOCK_OFFSET 0x4 #define PLL_STATUS_INTEN_CR_CPU_UNLOCK_MASK (0x01 << 0x4) /* Enables interrupt on DFT PLL unlocking*/ #define PLL_STATUS_INTEN_CR_DFI_UNLOCK_OFFSET 0x5 #define PLL_STATUS_INTEN_CR_DFI_UNLOCK_MASK (0x01 << 0x5) /* Enables interrupt on SGMII PLL unlocking*/ #define PLL_STATUS_INTEN_CR_SGMII_UNLOCK_OFFSET 0x6 #define PLL_STATUS_INTEN_CR_SGMII_UNLOCK_MASK (0x01 << 0x6) /*Maintenance interrupt indicates fault and status events.*/ #define MAINTENANCE_INT_SR_OFFSET 0x148 /* Indicates that one off the PLLs whent into the lock or unlock state. Cleared via PLL status register*/ #define MAINTENANCE_INT_SR_PLL_OFFSET 0x0 #define MAINTENANCE_INT_SR_PLL_MASK (0x01 << 0x0) /* Indicates that one off the MPUS signaled a MPU violation. Cleared vi a MPU Violation Register*/ #define MAINTENANCE_INT_SR_MPU_OFFSET 0x1 #define MAINTENANCE_INT_SR_MPU_MASK (0x01 << 0x1) /* Indicates that the AXI switch detected an illegal address. Cleared w hen SREG.SW_FAIL.ADDR1_CR_FAILED is cleared.*/ #define MAINTENANCE_INT_SR_DECODE_OFFSET 0x2 #define MAINTENANCE_INT_SR_DECODE_MASK (0x01 << 0x2) /* Indicates the device has entered the lower power state cleared by wr iting '1'*/ #define MAINTENANCE_INT_SR_LP_STATE_ENTER_OFFSET 0x3 #define MAINTENANCE_INT_SR_LP_STATE_ENTER_MASK (0x01 << 0x3) /* Indicates the device has exited the lower power state cleared by wri ting '1'*/ #define MAINTENANCE_INT_SR_LP_STATE_EXIT_OFFSET 0x4 #define MAINTENANCE_INT_SR_LP_STATE_EXIT_MASK (0x01 << 0x4) /* Indicates the device has entered the flash freezer state cleared by writing '1'*/ #define MAINTENANCE_INT_SR_FF_START_OFFSET 0x5 #define MAINTENANCE_INT_SR_FF_START_MASK (0x01 << 0x5) /* Indicates the device has exited the flash freezer state cleared by w riting '1'*/ #define MAINTENANCE_INT_SR_FF_END_OFFSET 0x6 #define MAINTENANCE_INT_SR_FF_END_MASK (0x01 << 0x6) /* Indicates that the FPGA array has been turned on cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_FPGA_ON_OFFSET 0x7 #define MAINTENANCE_INT_SR_FPGA_ON_MASK (0x01 << 0x7) /* Indicates that the FPGA array has been turned off cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_FPGA_OFF_OFFSET 0x8 #define MAINTENANCE_INT_SR_FPGA_OFF_MASK (0x01 << 0x8) /* Indicates that the SCB slave reported an error cleared via SCB contr oller*/ #define MAINTENANCE_INT_SR_SCB_ERROR_OFFSET 0x9 #define MAINTENANCE_INT_SR_SCB_ERROR_MASK (0x01 << 0x9) /* Indicates that the SCB bus fault occurred cleared via SCB controller */ #define MAINTENANCE_INT_SR_SCB_FAULT_OFFSET 0xA #define MAINTENANCE_INT_SR_SCB_FAULT_MASK (0x01 << 0xA) /* Indicates that the mesh over the Crypto triggered cleared via Mesh s ystem error*/ #define MAINTENANCE_INT_SR_MESH_ERROR_OFFSET 0xB #define MAINTENANCE_INT_SR_MESH_ERROR_MASK (0x01 << 0xB) /* Indicates that IO bank 2 has turned on cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B2_ON_OFFSET 0xC #define MAINTENANCE_INT_SR_IO_BANK_B2_ON_MASK (0x01 << 0xC) /* Indicates that IO bank 4 has turned on cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B4_ON_OFFSET 0xD #define MAINTENANCE_INT_SR_IO_BANK_B4_ON_MASK (0x01 << 0xD) /* Indicates that IO bank 5 has turned on cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B5_ON_OFFSET 0xE #define MAINTENANCE_INT_SR_IO_BANK_B5_ON_MASK (0x01 << 0xE) /* Indicates that IO bank 6 has turned on cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B6_ON_OFFSET 0xF #define MAINTENANCE_INT_SR_IO_BANK_B6_ON_MASK (0x01 << 0xF) /* Indicates that IO bank 2 has turned off cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B2_OFF_OFFSET 0x10 #define MAINTENANCE_INT_SR_IO_BANK_B2_OFF_MASK (0x01 << 0x10) /* Indicates that IO bank 4 has turned off cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B4_OFF_OFFSET 0x11 #define MAINTENANCE_INT_SR_IO_BANK_B4_OFF_MASK (0x01 << 0x11) /* Indicates that IO bank 5 has turned off cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_IO_BANK_B5_OFF_OFFSET 0x12 #define MAINTENANCE_INT_SR_IO_BANK_B5_OFF_MASK (0x01 << 0x12) /* Indicates that one off the DLLs when into the lock or unlock state. Cleared via DLL status register*/ #define MAINTENANCE_INT_SR_IO_BANK_B6_OFF_OFFSET 0x13 #define MAINTENANCE_INT_SR_IO_BANK_B6_OFF_MASK (0x01 << 0x13) /* Indicates that IO bank 6 has turned off cleared by writing a '1'*/ #define MAINTENANCE_INT_SR_DLL_OFFSET 0x14 #define MAINTENANCE_INT_SR_DLL_MASK (0x01 << 0x14) /*PLL interrupt register*/ #define PLL_STATUS_SR_OFFSET 0x14C /* Indicates that the CPU PLL has locked cleared by writing a '1'*/ #define PLL_STATUS_SR_CPU_LOCK_OFFSET 0x0 #define PLL_STATUS_SR_CPU_LOCK_MASK (0x01 << 0x0) /* Indicates that the DFI PLL has locked cleared by writing a '1'*/ #define PLL_STATUS_SR_DFI_LOCK_OFFSET 0x1 #define PLL_STATUS_SR_DFI_LOCK_MASK (0x01 << 0x1) /* Indicates that the SGMII PLL has locked cleared by writing a '1'*/ #define PLL_STATUS_SR_SGMII_LOCK_OFFSET 0x2 #define PLL_STATUS_SR_SGMII_LOCK_MASK (0x01 << 0x2) /* Indicates that the CPU PLL has unlocked cleared by writing a '1'*/ #define PLL_STATUS_SR_CPU_UNLOCK_OFFSET 0x4 #define PLL_STATUS_SR_CPU_UNLOCK_MASK (0x01 << 0x4) /* Indicates that the DFI PLL has unlocked cleared by writing a '1'*/ #define PLL_STATUS_SR_DFI_UNLOCK_OFFSET 0x5 #define PLL_STATUS_SR_DFI_UNLOCK_MASK (0x01 << 0x5) /* Indicates that the SGMII PLL has unlocked cleared by writing a '1'*/ #define PLL_STATUS_SR_SGMII_UNLOCK_OFFSET 0x6 #define PLL_STATUS_SR_SGMII_UNLOCK_MASK (0x01 << 0x6) /* Current state off CPU PLL locked signal*/ #define PLL_STATUS_SR_CPU_LOCK_NOW_OFFSET 0x8 #define PLL_STATUS_SR_CPU_LOCK_NOW_MASK (0x01 << 0x8) /* Current state off DFI PLL locked signal*/ #define PLL_STATUS_SR_DFI_LOCK_NOW_OFFSET 0x9 #define PLL_STATUS_SR_DFI_LOCK_NOW_MASK (0x01 << 0x9) /* Current state off SGMII PLL locked signal*/ #define PLL_STATUS_SR_SGMII_LOCK_NOW_OFFSET 0xA #define PLL_STATUS_SR_SGMII_LOCK_NOW_MASK (0x01 << 0xA) /*Enable to CFM Timer */ #define CFM_TIMER_CR_OFFSET 0x150 /* When set and the CFM channel is in timer mode and CFM channel is set to 2 (Group C) this register allows the timet to count. Allows software to start and stop the timers.*/ #define CFM_TIMER_CR_ENABLE_OFFSET 0x0 #define CFM_TIMER_CR_ENABLE_MASK (0x1F << 0x0) /*Miscellaneous Register*/ #define MISC_SR_OFFSET 0x154 /* Indicates that Interrupt from the G5C MSS SCB SPI controller is acti ve*/ #define MISC_SR_CONT_SPI_INTERRUPT_OFFSET 0x0 #define MISC_SR_CONT_SPI_INTERRUPT_MASK (0x01 << 0x0) /* Indicates that the user voltage or temperature detectors are signali ng an alarm condition.*/ #define MISC_SR_VOLT_TEMP_ALARM_OFFSET 0x1 #define MISC_SR_VOLT_TEMP_ALARM_MASK (0x01 << 0x1) /*DLL Interrupt enables*/ #define DLL_STATUS_CR_OFFSET 0x158 /* Enables the DLL0 lock interrupt*/ #define DLL_STATUS_CR_FIC0_LOCK_OFFSET 0x0 #define DLL_STATUS_CR_FIC0_LOCK_MASK (0x01 << 0x0) /* Enables the DLL1 lock interrupt*/ #define DLL_STATUS_CR_FIC1_LOCK_OFFSET 0x1 #define DLL_STATUS_CR_FIC1_LOCK_MASK (0x01 << 0x1) /* Enables the DLL2 lock interrupt*/ #define DLL_STATUS_CR_FIC2_LOCK_OFFSET 0x2 #define DLL_STATUS_CR_FIC2_LOCK_MASK (0x01 << 0x2) /* Enables the DLL3 lock interrupt*/ #define DLL_STATUS_CR_FIC3_LOCK_OFFSET 0x4 #define DLL_STATUS_CR_FIC3_LOCK_MASK (0x01 << 0x4) /* Enables the DLL4 (Crypto) lock interrupt*/ #define DLL_STATUS_CR_FIC4_LOCK_OFFSET 0x5 #define DLL_STATUS_CR_FIC4_LOCK_MASK (0x01 << 0x5) /* Enables the DLL0 unlock interrupt*/ #define DLL_STATUS_CR_FIC0_UNLOCK_OFFSET 0x8 #define DLL_STATUS_CR_FIC0_UNLOCK_MASK (0x01 << 0x8) /* Enables the DLL1 unlock interrupt*/ #define DLL_STATUS_CR_FIC1_UNLOCK_OFFSET 0x9 #define DLL_STATUS_CR_FIC1_UNLOCK_MASK (0x01 << 0x9) /* Enables the DLL2 unlock interrupt*/ #define DLL_STATUS_CR_FIC2_UNLOCK_OFFSET 0xA #define DLL_STATUS_CR_FIC2_UNLOCK_MASK (0x01 << 0xA) /* Enables the DLL3 unlock interrupt*/ #define DLL_STATUS_CR_FIC3_UNLOCK_OFFSET 0xB #define DLL_STATUS_CR_FIC3_UNLOCK_MASK (0x01 << 0xB) /* Enables the DLL4 (crypto) unlock interrupt*/ #define DLL_STATUS_CR_FIC4_UNLOCK_OFFSET 0xC #define DLL_STATUS_CR_FIC4_UNLOCK_MASK (0x01 << 0xC) /*DLL interrupt register*/ #define DLL_STATUS_SR_OFFSET 0x15C /* Indicates that the FIC0 DLL has locked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC0_LOCK_OFFSET 0x0 #define DLL_STATUS_SR_FIC0_LOCK_MASK (0x01 << 0x0) /* Indicates that the FIC1 DLL has locked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC1_LOCK_OFFSET 0x1 #define DLL_STATUS_SR_FIC1_LOCK_MASK (0x01 << 0x1) /* Indicates that the FIC2 DLL has locked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC2_LOCK_OFFSET 0x2 #define DLL_STATUS_SR_FIC2_LOCK_MASK (0x01 << 0x2) /* Indicates that the FIC3 DLL has locked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC3_LOCK_OFFSET 0x4 #define DLL_STATUS_SR_FIC3_LOCK_MASK (0x01 << 0x4) /* Indicates that the FIC4 (Crypto) DLL has locked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC4_LOCK_OFFSET 0x5 #define DLL_STATUS_SR_FIC4_LOCK_MASK (0x01 << 0x5) /* Indicates that the FIC0 DLL has unlocked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC0_UNLOCK_OFFSET 0x8 #define DLL_STATUS_SR_FIC0_UNLOCK_MASK (0x01 << 0x8) /* Indicates that the FIC1 DLL has unlocked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC1_UNLOCK_OFFSET 0x9 #define DLL_STATUS_SR_FIC1_UNLOCK_MASK (0x01 << 0x9) /* Indicates that the FIC2 DLL has unlocked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC2_UNLOCK_OFFSET 0xA #define DLL_STATUS_SR_FIC2_UNLOCK_MASK (0x01 << 0xA) /* Indicates that the FIC3 DLL has unlocked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC3_UNLOCK_OFFSET 0xB #define DLL_STATUS_SR_FIC3_UNLOCK_MASK (0x01 << 0xB) /* Indicates that the FIC4 (Crypto) DLL has unlocked cleared by writing a '1'*/ #define DLL_STATUS_SR_FIC4_UNLOCK_OFFSET 0xC #define DLL_STATUS_SR_FIC4_UNLOCK_MASK (0x01 << 0xC) /* Current state off FIC0 DLL locked signal*/ #define DLL_STATUS_SR_FIC0_LOCK_NOW_OFFSET 0x10 #define DLL_STATUS_SR_FIC0_LOCK_NOW_MASK (0x01 << 0x10) /* Current state off FIC1 DLL locked signal*/ #define DLL_STATUS_SR_FIC1_LOCK_NOW_OFFSET 0x11 #define DLL_STATUS_SR_FIC1_LOCK_NOW_MASK (0x01 << 0x11) /* Current state off FIC2 DLL locked signal*/ #define DLL_STATUS_SR_FIC2_LOCK_NOW_OFFSET 0x12 #define DLL_STATUS_SR_FIC2_LOCK_NOW_MASK (0x01 << 0x12) /* Current state off FIC3 DLL locked signal*/ #define DLL_STATUS_SR_FIC3_LOCK_NOW_OFFSET 0x13 #define DLL_STATUS_SR_FIC3_LOCK_NOW_MASK (0x01 << 0x13) /* Current state off FIC4 DLL locked signal*/ #define DLL_STATUS_SR_FIC4_LOCK_NOW_OFFSET 0x14 #define DLL_STATUS_SR_FIC4_LOCK_NOW_MASK (0x01 << 0x14) /*Puts all the RAMS in that block into low leakage mode. RAM contents and Q value preserved.*/ #define RAM_LIGHTSLEEP_CR_OFFSET 0x168 /* */ #define RAM_LIGHTSLEEP_CR_CAN0_OFFSET 0x0 #define RAM_LIGHTSLEEP_CR_CAN0_MASK (0x01 << 0x0) /* */ #define RAM_LIGHTSLEEP_CR_CAN1_OFFSET 0x1 #define RAM_LIGHTSLEEP_CR_CAN1_MASK (0x01 << 0x1) /* */ #define RAM_LIGHTSLEEP_CR_USB_OFFSET 0x2 #define RAM_LIGHTSLEEP_CR_USB_MASK (0x01 << 0x2) /* */ #define RAM_LIGHTSLEEP_CR_GEM0_OFFSET 0x3 #define RAM_LIGHTSLEEP_CR_GEM0_MASK (0x01 << 0x3) /* */ #define RAM_LIGHTSLEEP_CR_GEM1_OFFSET 0x4 #define RAM_LIGHTSLEEP_CR_GEM1_MASK (0x01 << 0x4) /* */ #define RAM_LIGHTSLEEP_CR_MMC_OFFSET 0x5 #define RAM_LIGHTSLEEP_CR_MMC_MASK (0x01 << 0x5) /* */ #define RAM_LIGHTSLEEP_CR_ATHENA_OFFSET 0x6 #define RAM_LIGHTSLEEP_CR_ATHENA_MASK (0x01 << 0x6) /* */ #define RAM_LIGHTSLEEP_CR_DDRC_OFFSET 0x7 #define RAM_LIGHTSLEEP_CR_DDRC_MASK (0x01 << 0x7) /* */ #define RAM_LIGHTSLEEP_CR_E51_OFFSET 0x8 #define RAM_LIGHTSLEEP_CR_E51_MASK (0x01 << 0x8) /* */ #define RAM_LIGHTSLEEP_CR_U54_1_OFFSET 0x9 #define RAM_LIGHTSLEEP_CR_U54_1_MASK (0x01 << 0x9) /* */ #define RAM_LIGHTSLEEP_CR_U54_2_OFFSET 0xA #define RAM_LIGHTSLEEP_CR_U54_2_MASK (0x01 << 0xA) /* */ #define RAM_LIGHTSLEEP_CR_U54_3_OFFSET 0xB #define RAM_LIGHTSLEEP_CR_U54_3_MASK (0x01 << 0xB) /* */ #define RAM_LIGHTSLEEP_CR_U54_4_OFFSET 0xC #define RAM_LIGHTSLEEP_CR_U54_4_MASK (0x01 << 0xC) /* */ #define RAM_LIGHTSLEEP_CR_L2_OFFSET 0xD #define RAM_LIGHTSLEEP_CR_L2_MASK (0x01 << 0xD) /*Puts all the RAMS in that block into deep sleep mode. RAM contents preser ved. Powers down the periphery circuits.*/ #define RAM_DEEPSLEEP_CR_OFFSET 0x16C /* */ #define RAM_DEEPSLEEP_CR_CAN0_OFFSET 0x0 #define RAM_DEEPSLEEP_CR_CAN0_MASK (0x01 << 0x0) /* */ #define RAM_DEEPSLEEP_CR_CAN1_OFFSET 0x1 #define RAM_DEEPSLEEP_CR_CAN1_MASK (0x01 << 0x1) /* */ #define RAM_DEEPSLEEP_CR_USB_OFFSET 0x2 #define RAM_DEEPSLEEP_CR_USB_MASK (0x01 << 0x2) /* */ #define RAM_DEEPSLEEP_CR_GEM0_OFFSET 0x3 #define RAM_DEEPSLEEP_CR_GEM0_MASK (0x01 << 0x3) /* */ #define RAM_DEEPSLEEP_CR_GEM1_OFFSET 0x4 #define RAM_DEEPSLEEP_CR_GEM1_MASK (0x01 << 0x4) /* */ #define RAM_DEEPSLEEP_CR_MMC_OFFSET 0x5 #define RAM_DEEPSLEEP_CR_MMC_MASK (0x01 << 0x5) /* */ #define RAM_DEEPSLEEP_CR_ATHENA_OFFSET 0x6 #define RAM_DEEPSLEEP_CR_ATHENA_MASK (0x01 << 0x6) /* */ #define RAM_DEEPSLEEP_CR_DDRC_OFFSET 0x7 #define RAM_DEEPSLEEP_CR_DDRC_MASK (0x01 << 0x7) /* */ #define RAM_DEEPSLEEP_CR_E51_OFFSET 0x8 #define RAM_DEEPSLEEP_CR_E51_MASK (0x01 << 0x8) /* */ #define RAM_DEEPSLEEP_CR_U54_1_OFFSET 0x9 #define RAM_DEEPSLEEP_CR_U54_1_MASK (0x01 << 0x9) /* */ #define RAM_DEEPSLEEP_CR_U54_2_OFFSET 0xA #define RAM_DEEPSLEEP_CR_U54_2_MASK (0x01 << 0xA) /* */ #define RAM_DEEPSLEEP_CR_U54_3_OFFSET 0xB #define RAM_DEEPSLEEP_CR_U54_3_MASK (0x01 << 0xB) /* */ #define RAM_DEEPSLEEP_CR_U54_4_OFFSET 0xC #define RAM_DEEPSLEEP_CR_U54_4_MASK (0x01 << 0xC) /* */ #define RAM_DEEPSLEEP_CR_L2_OFFSET 0xD #define RAM_DEEPSLEEP_CR_L2_MASK (0x01 << 0xD) /*Puts all the RAMS in that block into shut down mode. RAM contents not pre served. Powers down the RAM and periphery circuits.*/ #define RAM_SHUTDOWN_CR_OFFSET 0x170 /* */ #define RAM_SHUTDOWN_CR_CAN0_OFFSET 0x0 #define RAM_SHUTDOWN_CR_CAN0_MASK (0x01 << 0x0) /* */ #define RAM_SHUTDOWN_CR_CAN1_OFFSET 0x1 #define RAM_SHUTDOWN_CR_CAN1_MASK (0x01 << 0x1) /* */ #define RAM_SHUTDOWN_CR_USB_OFFSET 0x2 #define RAM_SHUTDOWN_CR_USB_MASK (0x01 << 0x2) /* */ #define RAM_SHUTDOWN_CR_GEM0_OFFSET 0x3 #define RAM_SHUTDOWN_CR_GEM0_MASK (0x01 << 0x3) /* */ #define RAM_SHUTDOWN_CR_GEM1_OFFSET 0x4 #define RAM_SHUTDOWN_CR_GEM1_MASK (0x01 << 0x4) /* */ #define RAM_SHUTDOWN_CR_MMC_OFFSET 0x5 #define RAM_SHUTDOWN_CR_MMC_MASK (0x01 << 0x5) /* */ #define RAM_SHUTDOWN_CR_ATHENA_OFFSET 0x6 #define RAM_SHUTDOWN_CR_ATHENA_MASK (0x01 << 0x6) /* */ #define RAM_SHUTDOWN_CR_DDRC_OFFSET 0x7 #define RAM_SHUTDOWN_CR_DDRC_MASK (0x01 << 0x7) /* */ #define RAM_SHUTDOWN_CR_E51_OFFSET 0x8 #define RAM_SHUTDOWN_CR_E51_MASK (0x01 << 0x8) /* */ #define RAM_SHUTDOWN_CR_U54_1_OFFSET 0x9 #define RAM_SHUTDOWN_CR_U54_1_MASK (0x01 << 0x9) /* */ #define RAM_SHUTDOWN_CR_U54_2_OFFSET 0xA #define RAM_SHUTDOWN_CR_U54_2_MASK (0x01 << 0xA) /* */ #define RAM_SHUTDOWN_CR_U54_3_OFFSET 0xB #define RAM_SHUTDOWN_CR_U54_3_MASK (0x01 << 0xB) /* */ #define RAM_SHUTDOWN_CR_U54_4_OFFSET 0xC #define RAM_SHUTDOWN_CR_U54_4_MASK (0x01 << 0xC) /* */ #define RAM_SHUTDOWN_CR_L2_OFFSET 0xD #define RAM_SHUTDOWN_CR_L2_MASK (0x01 << 0xD) /*Allows each bank of the L2 Cache to be powered down ORed with global shut down */ #define L2_SHUTDOWN_CR_OFFSET 0x174 /* */ #define L2_SHUTDOWN_CR_L2_RAMS_OFFSET 0x0 #define L2_SHUTDOWN_CR_L2_RAMS_MASK (0x0F << 0x0) /*Selects whether the peripheral is connected to the Fabric or IOMUX struct ure.*/ #define IOMUX0_CR_OFFSET 0x200 /* */ #define IOMUX0_CR_SPI0_FABRIC_OFFSET 0x0 #define IOMUX0_CR_SPI0_FABRIC_MASK (0x01 << 0x0) /* */ #define IOMUX0_CR_SPI1_FABRIC_OFFSET 0x1 #define IOMUX0_CR_SPI1_FABRIC_MASK (0x01 << 0x1) /* */ #define IOMUX0_CR_I2C0_FABRIC_OFFSET 0x2 #define IOMUX0_CR_I2C0_FABRIC_MASK (0x01 << 0x2) /* */ #define IOMUX0_CR_I2C1_FABRIC_OFFSET 0x3 #define IOMUX0_CR_I2C1_FABRIC_MASK (0x01 << 0x3) /* */ #define IOMUX0_CR_CAN0_FABRIC_OFFSET 0x4 #define IOMUX0_CR_CAN0_FABRIC_MASK (0x01 << 0x4) /* */ #define IOMUX0_CR_CAN1_FABRIC_OFFSET 0x5 #define IOMUX0_CR_CAN1_FABRIC_MASK (0x01 << 0x5) /* */ #define IOMUX0_CR_QSPI_FABRIC_OFFSET 0x6 #define IOMUX0_CR_QSPI_FABRIC_MASK (0x01 << 0x6) /* */ #define IOMUX0_CR_MMUART0_FABRIC_OFFSET 0x7 #define IOMUX0_CR_MMUART0_FABRIC_MASK (0x01 << 0x7) /* */ #define IOMUX0_CR_MMUART1_FABRIC_OFFSET 0x8 #define IOMUX0_CR_MMUART1_FABRIC_MASK (0x01 << 0x8) /* */ #define IOMUX0_CR_MMUART2_FABRIC_OFFSET 0x9 #define IOMUX0_CR_MMUART2_FABRIC_MASK (0x01 << 0x9) /* */ #define IOMUX0_CR_MMUART3_FABRIC_OFFSET 0xA #define IOMUX0_CR_MMUART3_FABRIC_MASK (0x01 << 0xA) /* */ #define IOMUX0_CR_MMUART4_FABRIC_OFFSET 0xB #define IOMUX0_CR_MMUART4_FABRIC_MASK (0x01 << 0xB) /* */ #define IOMUX0_CR_MDIO0_FABRIC_OFFSET 0xC #define IOMUX0_CR_MDIO0_FABRIC_MASK (0x01 << 0xC) /* */ #define IOMUX0_CR_MDIO1_FABRIC_OFFSET 0xD #define IOMUX0_CR_MDIO1_FABRIC_MASK (0x01 << 0xD) /*Configures the IO Mux structure for each IO pad. See the MSS MAS specific ation for for description.*/ #define IOMUX1_CR_OFFSET 0x204 /* */ #define IOMUX1_CR_PAD0_OFFSET 0x0 #define IOMUX1_CR_PAD0_MASK (0x0F << 0x0) /* */ #define IOMUX1_CR_PAD1_OFFSET 0x4 #define IOMUX1_CR_PAD1_MASK (0x0F << 0x4) /* */ #define IOMUX1_CR_PAD2_OFFSET 0x8 #define IOMUX1_CR_PAD2_MASK (0x0F << 0x8) /* */ #define IOMUX1_CR_PAD3_OFFSET 0xC #define IOMUX1_CR_PAD3_MASK (0x0F << 0xC) /* */ #define IOMUX1_CR_PAD4_OFFSET 0x10 #define IOMUX1_CR_PAD4_MASK (0x0F << 0x10) /* */ #define IOMUX1_CR_PAD5_OFFSET 0x14 #define IOMUX1_CR_PAD5_MASK (0x0F << 0x14) /* */ #define IOMUX1_CR_PAD6_OFFSET 0x18 #define IOMUX1_CR_PAD6_MASK (0x0F << 0x18) /* */ #define IOMUX1_CR_PAD7_OFFSET 0x1C #define IOMUX1_CR_PAD7_MASK (0x0F << 0x1C) /*Configures the IO Mux structure for each IO pad. See the MSS MAS specific ation for for description.*/ #define IOMUX2_CR_OFFSET 0x208 /* */ #define IOMUX2_CR_PAD8_OFFSET 0x0 #define IOMUX2_CR_PAD8_MASK (0x0F << 0x0) /* */ #define IOMUX2_CR_PAD9_OFFSET 0x4 #define IOMUX2_CR_PAD9_MASK (0x0F << 0x4) /* */ #define IOMUX2_CR_PAD10_OFFSET 0x8 #define IOMUX2_CR_PAD10_MASK (0x0F << 0x8) /* */ #define IOMUX2_CR_PAD11_OFFSET 0xC #define IOMUX2_CR_PAD11_MASK (0x0F << 0xC) /* */ #define IOMUX2_CR_PAD12_OFFSET 0x10 #define IOMUX2_CR_PAD12_MASK (0x0F << 0x10) /* */ #define IOMUX2_CR_PAD13_OFFSET 0x14 #define IOMUX2_CR_PAD13_MASK (0x0F << 0x14) /*Configures the IO Mux structure for each IO pad. See the MSS MAS specific ation for for description.*/ #define IOMUX3_CR_OFFSET 0x20C /* */ #define IOMUX3_CR_PAD14_OFFSET 0x0 #define IOMUX3_CR_PAD14_MASK (0x0F << 0x0) /* */ #define IOMUX3_CR_PAD15_OFFSET 0x4 #define IOMUX3_CR_PAD15_MASK (0x0F << 0x4) /* */ #define IOMUX3_CR_PAD16_OFFSET 0x8 #define IOMUX3_CR_PAD16_MASK (0x0F << 0x8) /* */ #define IOMUX3_CR_PAD17_OFFSET 0xC #define IOMUX3_CR_PAD17_MASK (0x0F << 0xC) /* */ #define IOMUX3_CR_PAD18_OFFSET 0x10 #define IOMUX3_CR_PAD18_MASK (0x0F << 0x10) /* */ #define IOMUX3_CR_PAD19_OFFSET 0x14 #define IOMUX3_CR_PAD19_MASK (0x0F << 0x14) /* */ #define IOMUX3_CR_PAD20_OFFSET 0x18 #define IOMUX3_CR_PAD20_MASK (0x0F << 0x18) /* */ #define IOMUX3_CR_PAD21_OFFSET 0x1C #define IOMUX3_CR_PAD21_MASK (0x0F << 0x1C) /*Configures the IO Mux structure for each IO pad. See the MSS MAS specific ation for for description.*/ #define IOMUX4_CR_OFFSET 0x210 /* */ #define IOMUX4_CR_PAD22_OFFSET 0x0 #define IOMUX4_CR_PAD22_MASK (0x0F << 0x0) /* */ #define IOMUX4_CR_PAD23_OFFSET 0x4 #define IOMUX4_CR_PAD23_MASK (0x0F << 0x4) /* */ #define IOMUX4_CR_PAD24_OFFSET 0x8 #define IOMUX4_CR_PAD24_MASK (0x0F << 0x8) /* */ #define IOMUX4_CR_PAD25_OFFSET 0xC #define IOMUX4_CR_PAD25_MASK (0x0F << 0xC) /* */ #define IOMUX4_CR_PAD26_OFFSET 0x10 #define IOMUX4_CR_PAD26_MASK (0x0F << 0x10) /* */ #define IOMUX4_CR_PAD27_OFFSET 0x14 #define IOMUX4_CR_PAD27_MASK (0x0F << 0x14) /* */ #define IOMUX4_CR_PAD28_OFFSET 0x18 #define IOMUX4_CR_PAD28_MASK (0x0F << 0x18) /* */ #define IOMUX4_CR_PAD29_OFFSET 0x1C #define IOMUX4_CR_PAD29_MASK (0x0F << 0x1C) /*Configures the IO Mux structure for each IO pad. See the MSS MAS specific ation for for description.*/ #define IOMUX5_CR_OFFSET 0x214 /* */ #define IOMUX5_CR_PAD30_OFFSET 0x0 #define IOMUX5_CR_PAD30_MASK (0x0F << 0x0) /* */ #define IOMUX5_CR_PAD31_OFFSET 0x4 #define IOMUX5_CR_PAD31_MASK (0x0F << 0x4) /* */ #define IOMUX5_CR_PAD32_OFFSET 0x8 #define IOMUX5_CR_PAD32_MASK (0x0F << 0x8) /* */ #define IOMUX5_CR_PAD33_OFFSET 0xC #define IOMUX5_CR_PAD33_MASK (0x0F << 0xC) /* */ #define IOMUX5_CR_PAD34_OFFSET 0x10 #define IOMUX5_CR_PAD34_MASK (0x0F << 0x10) /* */ #define IOMUX5_CR_PAD35_OFFSET 0x14 #define IOMUX5_CR_PAD35_MASK (0x0F << 0x14) /* */ #define IOMUX5_CR_PAD36_OFFSET 0x18 #define IOMUX5_CR_PAD36_MASK (0x0F << 0x18) /* */ #define IOMUX5_CR_PAD37_OFFSET 0x1C #define IOMUX5_CR_PAD37_MASK (0x0F << 0x1C) /*Sets whether the MMC/SD Voltage select lines are inverted on entry to the IOMUX structure*/ #define IOMUX6_CR_OFFSET 0x218 /* */ #define IOMUX6_CR_VLT_SEL_OFFSET 0x0 #define IOMUX6_CR_VLT_SEL_MASK (0x01 << 0x0) /* */ #define IOMUX6_CR_VLT_EN_OFFSET 0x1 #define IOMUX6_CR_VLT_EN_MASK (0x01 << 0x1) /* */ #define IOMUX6_CR_VLT_CMD_DIR_OFFSET 0x2 #define IOMUX6_CR_VLT_CMD_DIR_MASK (0x01 << 0x2) /* */ #define IOMUX6_CR_VLT_DIR_0_OFFSET 0x3 #define IOMUX6_CR_VLT_DIR_0_MASK (0x01 << 0x3) /* */ #define IOMUX6_CR_VLT_DIR_1_3_OFFSET 0x4 #define IOMUX6_CR_VLT_DIR_1_3_MASK (0x01 << 0x4) /* */ #define IOMUX6_CR_SD_LED_OFFSET 0x5 #define IOMUX6_CR_SD_LED_MASK (0x01 << 0x5) /* */ #define IOMUX6_CR_SD_VOLT_0_OFFSET 0x6 #define IOMUX6_CR_SD_VOLT_0_MASK (0x01 << 0x6) /* */ #define IOMUX6_CR_SD_VOLT_1_OFFSET 0x7 #define IOMUX6_CR_SD_VOLT_1_MASK (0x01 << 0x7) /* */ #define IOMUX6_CR_SD_VOLT_2_OFFSET 0x8 #define IOMUX6_CR_SD_VOLT_2_MASK (0x01 << 0x8) /*Configures the MSSIO block*/ #define MSSIO_BANK4_CFG_CR_OFFSET 0x230 /* Sets the PCODE value*/ #define MSSIO_BANK4_CFG_CR_BANK_PCODE_OFFSET 0x0 #define MSSIO_BANK4_CFG_CR_BANK_PCODE_MASK (0x3F << 0x0) /* Sets the NCODE value*/ #define MSSIO_BANK4_CFG_CR_BANK_NCODE_OFFSET 0x6 #define MSSIO_BANK4_CFG_CR_BANK_NCODE_MASK (0x3F << 0x6) /* Sets the voltage controls.*/ #define MSSIO_BANK4_CFG_CR_VS_OFFSET 0xC #define MSSIO_BANK4_CFG_CR_VS_MASK (0x0F << 0xC) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_0_1_CR_OFFSET 0x234 /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_2_3_CR_OFFSET 0x238 /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_4_5_CR_OFFSET 0x23C /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_6_7_CR_OFFSET 0x240 /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_8_9_CR_OFFSET 0x244 /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_10_11_CR_OFFSET 0x248 /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK4_IO_CFG_12_13_CR_OFFSET 0x24C /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_0_OFFSET 0x3 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_1_OFFSET 0x4 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_2_OFFSET 0x5 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_3_OFFSET 0x6 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_CLAMP_OFFSET 0x7 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_ENHYST_OFFSET 0x8 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPD_OFFSET 0xA #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPU_OFFSET 0xB #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_ATP_EN_OFFSET 0xC #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_0_OFFSET 0x13 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_1_OFFSET 0x14 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_2_OFFSET 0x15 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_3_OFFSET 0x16 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_CLAMP_OFFSET 0x17 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_ENHYST_OFFSET 0x18 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPD_OFFSET 0x1A #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPU_OFFSET 0x1B #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_ATP_EN_OFFSET 0x1C #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK4_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*Configures the MSSIO block*/ #define MSSIO_BANK2_CFG_CR_OFFSET 0x250 /* Sets the PCODE value*/ #define MSSIO_BANK2_CFG_CR_BANK_PCODE_OFFSET 0x0 #define MSSIO_BANK2_CFG_CR_BANK_PCODE_MASK (0x3F << 0x0) /* Sets the NCODE value*/ #define MSSIO_BANK2_CFG_CR_BANK_NCODE_OFFSET 0x6 #define MSSIO_BANK2_CFG_CR_BANK_NCODE_MASK (0x3F << 0x6) /* Sets the voltage controls.*/ #define MSSIO_BANK2_CFG_CR_VS_OFFSET 0xC #define MSSIO_BANK2_CFG_CR_VS_MASK (0x0F << 0xC) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_0_1_CR_OFFSET 0x254 /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_0_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_0_1_CR_RPC_IO_CFG_1_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_2_3_CR_OFFSET 0x258 /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_2_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_2_3_CR_RPC_IO_CFG_3_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_4_5_CR_OFFSET 0x25C /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_4_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_4_5_CR_RPC_IO_CFG_5_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_6_7_CR_OFFSET 0x260 /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_6_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_6_7_CR_RPC_IO_CFG_7_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_8_9_CR_OFFSET 0x264 /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_8_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_8_9_CR_RPC_IO_CFG_9_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_10_11_CR_OFFSET 0x268 /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_10_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_10_11_CR_RPC_IO_CFG_11_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_12_13_CR_OFFSET 0x26C /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_12_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_12_13_CR_RPC_IO_CFG_13_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_14_15_CR_OFFSET 0x270 /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_14_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_14_15_CR_RPC_IO_CFG_15_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_16_17_CR_OFFSET 0x274 /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_16_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_16_17_CR_RPC_IO_CFG_17_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_18_19_CR_OFFSET 0x278 /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_18_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_18_19_CR_RPC_IO_CFG_19_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_20_21_CR_OFFSET 0x27C /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_20_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_20_21_CR_RPC_IO_CFG_21_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*IO electrical configuration for MSSIO pad*/ #define MSSIO_BANK2_IO_CFG_22_23_CR_OFFSET 0x280 /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_IBUFMD_0_OFFSET 0x0 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_IBUFMD_0_MASK (0x01 << 0x0) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_IBUFMD_1_OFFSET 0x1 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_IBUFMD_1_MASK (0x01 << 0x1) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_IBUFMD_2_OFFSET 0x2 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_IBUFMD_2_MASK (0x01 << 0x2) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_0_OFFSET 0x3 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_0_MASK (0x01 << 0x3) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_1_OFFSET 0x4 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_1_MASK (0x01 << 0x4) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_2_OFFSET 0x5 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_2_MASK (0x01 << 0x5) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_3_OFFSET 0x6 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_DRV_3_MASK (0x01 << 0x6) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_CLAMP_OFFSET 0x7 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_CLAMP_MASK (0x01 << 0x7) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_ENHYST_OFFSET 0x8 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_ENHYST_MASK (0x01 << 0x8) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_LOCKDN_EN_OFFSET 0x9 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_LOCKDN_EN_MASK (0x01 << 0x9) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_WPD_OFFSET 0xA #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_WPD_MASK (0x01 << 0xA) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_WPU_OFFSET 0xB #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_WPU_MASK (0x01 << 0xB) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_ATP_EN_OFFSET 0xC #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_ATP_EN_MASK (0x01 << 0xC) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_LP_PERSIST_EN_OFFSET 0xD #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_LP_PERSIST_EN_MASK (0x01 << 0xD) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_LP_BYPASS_EN_OFFSET 0xE #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_22_LP_BYPASS_EN_MASK (0x01 << 0xE) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_IBUFMD_0_OFFSET 0x10 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_IBUFMD_0_MASK (0x01 << 0x10) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_IBUFMD_1_OFFSET 0x11 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_IBUFMD_1_MASK (0x01 << 0x11) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_IBUFMD_2_OFFSET 0x12 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_IBUFMD_2_MASK (0x01 << 0x12) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_0_OFFSET 0x13 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_0_MASK (0x01 << 0x13) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_1_OFFSET 0x14 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_1_MASK (0x01 << 0x14) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_2_OFFSET 0x15 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_2_MASK (0x01 << 0x15) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_3_OFFSET 0x16 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_DRV_3_MASK (0x01 << 0x16) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_CLAMP_OFFSET 0x17 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_CLAMP_MASK (0x01 << 0x17) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_ENHYST_OFFSET 0x18 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_ENHYST_MASK (0x01 << 0x18) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_LOCKDN_EN_OFFSET 0x19 #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_LOCKDN_EN_MASK (0x01 << 0x19) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_WPD_OFFSET 0x1A #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_WPD_MASK (0x01 << 0x1A) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_WPU_OFFSET 0x1B #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_WPU_MASK (0x01 << 0x1B) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_ATP_EN_OFFSET 0x1C #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_ATP_EN_MASK (0x01 << 0x1C) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_LP_PERSIST_EN_OFFSET 0x1D #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_LP_PERSIST_EN_MASK (0x01 << 0x1D) /* */ #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_LP_BYPASS_EN_OFFSET 0x1E #define MSSIO_BANK2_IO_CFG_22_23_CR_RPC_IO_CFG_23_LP_BYPASS_EN_MASK (0x01 << 0x1E) /*Sets M2F [31:0] Spares out signals*/ #define MSS_SPARE0_CR_OFFSET 0x2A8 /* See MSS MAS specification for full description*/ #define MSS_SPARE0_CR_DATA_OFFSET 0x0 #define MSS_SPARE0_CR_DATA_MASK (0xFFFFFFFF << 0x0) /*Sets M2F [37:32] Spares out signals*/ #define MSS_SPARE1_CR_OFFSET 0x2AC /* See MSS MAS specification for full description*/ #define MSS_SPARE1_CR_DATA_OFFSET 0x0 #define MSS_SPARE1_CR_DATA_MASK (0x3F << 0x0) /*Read M2F [31:0] Spares out signals*/ #define MSS_SPARE0_SR_OFFSET 0x2B0 /* See MSS MAS specification for full description*/ #define MSS_SPARE0_SR_DATA_OFFSET 0x0 #define MSS_SPARE0_SR_DATA_MASK (0xFFFFFFFF << 0x0) /*Read M2F [37:32] Spares out signals*/ #define MSS_SPARE1_SR_OFFSET 0x2B4 /* See MSS MAS specification for full description*/ #define MSS_SPARE1_SR_DATA_OFFSET 0x0 #define MSS_SPARE1_SR_DATA_MASK (0x3F << 0x0) /*Read F2M [31:0] Spares in1 signals*/ #define MSS_SPARE2_SR_OFFSET 0x2B8 /* See MSS MAS specification for full description*/ #define MSS_SPARE2_SR_DATA_OFFSET 0x0 #define MSS_SPARE2_SR_DATA_MASK (0xFFFFFFFF << 0x0) /*Read F2M [37:32] Spares in1 signals*/ #define MSS_SPARE3_SR_OFFSET 0x2BC /* See MSS MAS specification for full description*/ #define MSS_SPARE3_SR_DATA_OFFSET 0x0 #define MSS_SPARE3_SR_DATA_MASK (0x3F << 0x0) /*Read F2M [31:0] Spares in2 signals*/ #define MSS_SPARE4_SR_OFFSET 0x2C0 /* See MSS MAS specification for full description*/ #define MSS_SPARE4_SR_DATA_OFFSET 0x0 #define MSS_SPARE4_SR_DATA_MASK (0xFFFFFFFF << 0x0) /*Read F2M [37:32] Spares in2 signals*/ #define MSS_SPARE5_SR_OFFSET 0x2C4 /* See MSS MAS specification for full description*/ #define MSS_SPARE5_SR_DATA_OFFSET 0x0 #define MSS_SPARE5_SR_DATA_MASK (0x3F << 0x0) /*Register for ECO usage*/ #define SPARE_REGISTER_RW_OFFSET 0x2D0 /* No function provided for future ECO use*/ #define SPARE_REGISTER_RW_DATA_OFFSET 0x0 #define SPARE_REGISTER_RW_DATA_MASK (0xFF << 0x0) /*Register for ECO usage*/ #define SPARE_REGISTER_W1P_OFFSET 0x2D4 /* No function provided for future ECO use*/ #define SPARE_REGISTER_W1P_DATA_OFFSET 0x0 #define SPARE_REGISTER_W1P_DATA_MASK (0xFF << 0x0) /*Register for ECO usage*/ #define SPARE_REGISTER_RO_OFFSET 0x2D8 /* Provides read-back of { W1P RW } registers. No function provided for future ECO use.*/ #define SPARE_REGISTER_RO_DATA_OFFSET 0x0 #define SPARE_REGISTER_RO_DATA_MASK (0xFFFF << 0x0) /*Spare signal back to G5C*/ #define SPARE_PERIM_RW_OFFSET 0x2DC /* Allows the MSS to control the perim_spare_out bits [2] & [6]. No fun ction provided for future ECO use.*/ #define SPARE_PERIM_RW_DATA_OFFSET 0x0 #define SPARE_PERIM_RW_DATA_MASK (0x03 << 0x0) /*Unused FIC resets*/ #define SPARE_FIC_OFFSET 0x2E0 /* Connected to spare FIC 0-3 Reset inputs to provide simple RO bits. N o defined use*/ #define SPARE_FIC_RESET_OFFSET 0x0 #define SPARE_FIC_RESET_MASK (0x0F << 0x0) /************************************************************************** ******* ********************TOP LEVEL REGISTER STRUCTURE*************************** ******* *************************************************************************** *******/ typedef struct _mss_sysreg { /*Register for software use*/ __IO uint32_t TEMP0; /*Register for software use*/ __IO uint32_t TEMP1; /*Master clock configuration*/ __IO uint32_t CLOCK_CONFIG_CR; /*RTC clock divider*/ __IO uint32_t RTC_CLOCK_CR; /*Fabric Reset mask*/ __IO uint32_t FABRIC_RESET_CR; /**/ __IO uint32_t BOOT_FAIL_CR; /* Allows the CPU to fully reset the MSS. When written to 16'hDEAD will cause a full MSS reset. The Reset wil clear this register. The register may be writtent to any value but only a value off 16'hDEAD will cause the reset to happen */ __IO uint32_t MSS_RESET_CR; /*Configuration lock*/ __IO uint32_t CONFIG_LOCK_CR; /*Indicates which reset caused the last reset. After a reset occurs reg ister should be read and then zero written to allow the next reset event to be correctly captured.*/ __IO uint32_t RESET_SR; /*Indicates the device status in particular the state of the FPGA fabri c and the MSS IO banks*/ __IO uint32_t DEVICE_STATUS ; /*MSS Build Info*/ __I uint32_t MSS_BUILD; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_1; __I uint32_t RESERVEDREG32B_2; __I uint32_t RESERVEDREG32B_3; __I uint32_t RESERVEDREG32B_4; __I uint32_t RESERVEDREG32B_5; /*U54-1 Fabric interrupt enable*/ __IO uint32_t FAB_INTEN_U54_1; /*U54-2 Fabric interrupt enable*/ __IO uint32_t FAB_INTEN_U54_2; /*U54-3 Fabric interrupt enable*/ __IO uint32_t FAB_INTEN_U54_3; /*U54-4 Fabric interrupt enable*/ __IO uint32_t FAB_INTEN_U54_4; /*Allows the Ethernet interrupts to be directly routed to the U54 CPUS. */ __IO uint32_t FAB_INTEN_MISC; /* Enables the Ethernet MAC0 to interrupt U54_1 directly */ #define FAB_INTEN_MAC0_U54_1_EN_OFFSET 0x01U /* Enables the Ethernet MAC0 to interrupt U54_2 directly */ #define FAB_INTEN_MAC0_U54_2_EN_OFFSET 0x02U /* Enables the Ethernet MAC1 to interrupt U54_3 directly */ #define FAB_INTEN_MAC1_U54_3_EN_OFFSET 0x03U /* Enables the Ethernet MAC1 to interrupt U54_4 directly */ #define FAB_INTEN_MAC1_U54_4_EN_OFFSET 0x04U #define FAB_INTEN_MAC0_U54_1_EN_MASK 0x01U #define FAB_INTEN_MAC0_U54_2_EN_MASK 0x02U #define FAB_INTEN_MAC1_U54_3_EN_MASK 0x04U #define FAB_INTEN_MAC1_U54_4_EN_MASK 0x08U /*Switches GPIO interrupt from PAD to Fabric GPIO*/ __IO uint32_t GPIO_INTERRUPT_FAB_CR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_6; __I uint32_t RESERVEDREG32B_7; __I uint32_t RESERVEDREG32B_8; __I uint32_t RESERVEDREG32B_9; __I uint32_t RESERVEDREG32B_10; __I uint32_t RESERVEDREG32B_11; __I uint32_t RESERVEDREG32B_12; __I uint32_t RESERVEDREG32B_13; __I uint32_t RESERVEDREG32B_14; __I uint32_t RESERVEDREG32B_15; /*"AMP Mode peripheral mapping register. When the register bit is '0' t he peripheral is mapped into the 0x2000000 address range using AXI bus 5 fr om the Coreplex. When the register bit is '1' the peripheral is mapped into the 0x28000000 address range using AXI bus 6 from the Coreplex."*/ __IO uint32_t APBBUS_CR; /*"Enables the clock to the MSS peripheral. By turning clocks off dynam ic power can be saved. When the clock is off the peripheral should not be accessed*/ __IO uint32_t SUBBLK_CLOCK_CR; /*"Holds the MSS peripherals in reset. When in reset the peripheral sho uld not be accessed*/ __IO uint32_t SOFT_RESET_CR; /*Configures how many outstanding transfers the AXI-AHB bridges in fron t off the USB and Crypto blocks should allow. (See Synopsys AXI-AHB bridge documentation)*/ __IO uint32_t AHBAXI_CR; /*Configures the two AHB-APB bridges on S5 and S6*/ __IO uint32_t AHBAPB_CR; /* Padding reserved 32-bit registers.*/ uint32_t reservedReg32b_16; /*MSS Corner APB interface controls*/ __IO uint32_t DFIAPB_CR; /*GPIO Blocks reset control*/ __IO uint32_t GPIO_CR; /* Padding reserved 32-bit registers.*/ uint32_t reservedReg32b_17; /*MAC0 configuration register*/ __IO uint32_t MAC0_CR; /*MAC1 configuration register*/ __IO uint32_t MAC1_CR; /*USB Configuration register*/ __IO uint32_t USB_CR; /*Crypto Mesh control and status register*/ __IO uint32_t MESH_CR; /*Crypto mesh seed and update rate*/ __IO uint32_t MESH_SEED_CR; /*ENVM AHB Controller setup*/ __IO uint32_t ENVM_CR; /*Reserved*/ __I uint32_t RESERVED_BC; /*QOS Athena USB & MMC Configuration*/ __IO uint32_t QOS_PERIPHERAL_CR; /*QOS Configuration Coreplex*/ __IO uint32_t QOS_CPLEXIO_CR; /*QOS configuration DDRC*/ __IO uint32_t QOS_CPLEXDDR_CR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_18; __I uint32_t RESERVEDREG32B_19; __I uint32_t RESERVEDREG32B_20; __I uint32_t RESERVEDREG32B_21; __I uint32_t RESERVEDREG32B_22; __I uint32_t RESERVEDREG32B_23; __I uint32_t RESERVEDREG32B_24; __I uint32_t RESERVEDREG32B_25; __I uint32_t RESERVEDREG32B_26; /*Indicates that a master caused a MPU violation. Interrupts via mainte nance interrupt.*/ __IO uint32_t MPU_VIOLATION_SR; /*Enables interrupts on MPU violations*/ __IO uint32_t MPU_VIOLATION_INTEN_CR; /*AXI switch decode fail*/ __IO uint32_t SW_FAIL_ADDR0_CR; /*AXI switch decode fail*/ __IO uint32_t SW_FAIL_ADDR1_CR; /*Set when an ECC event happens*/ __IO uint32_t EDAC_SR; /*Enables ECC interrupt on event*/ __IO uint32_t EDAC_INTEN_CR; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_MMC; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_DDRC; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_MAC0; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_MAC1; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_USB; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_CAN0; /*Count off single bit errors*/ __IO uint32_t EDAC_CNT_CAN1; /*"Will Corrupt write data to rams 1E corrupts bit 0 2E bits 1 and 2.In jects Errors into all RAMS in the block as long as the bits are set. Settin g 1E and 2E will inject a 3-bit error"*/ __IO uint32_t EDAC_INJECT_CR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_27; __I uint32_t RESERVEDREG32B_28; __I uint32_t RESERVEDREG32B_29; __I uint32_t RESERVEDREG32B_30; __I uint32_t RESERVEDREG32B_31; __I uint32_t RESERVEDREG32B_32; /*Maintenance Interrupt Enable.*/ __IO uint32_t MAINTENANCE_INTEN_CR; /*PLL Status interrupt enables*/ __IO uint32_t PLL_STATUS_INTEN_CR; /*Maintenance interrupt indicates fault and status events.*/ __IO uint32_t MAINTENANCE_INT_SR; /*PLL interrupt register*/ __IO uint32_t PLL_STATUS_SR; /*Enable to CFM Timer */ __IO uint32_t CFM_TIMER_CR; /*Miscellaneous Register*/ uint32_t MISC_SR; /*DLL Interrupt enables*/ __IO uint32_t DLL_STATUS_CR; /*DLL interrupt register*/ __IO uint32_t DLL_STATUS_SR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_33; __I uint32_t RESERVEDREG32B_34; /*Puts all the RAMS in that block into low leakage mode. RAM contents a nd Q value preserved.*/ __IO uint32_t RAM_LIGHTSLEEP_CR; /*Puts all the RAMS in that block into deep sleep mode. RAM contents pr eserved. Powers down the periphery circuits.*/ __IO uint32_t RAM_DEEPSLEEP_CR; /*Puts all the RAMS in that block into shut down mode. RAM contents not preserved. Powers down the RAM and periphery circuits.*/ __IO uint32_t RAM_SHUTDOWN_CR; /*Allows each bank of the L2 Cache to be powered down ORed with global shutdown */ __IO uint32_t L2_SHUTDOWN_CR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_35; __I uint32_t RESERVEDREG32B_36; __I uint32_t RESERVEDREG32B_37; __I uint32_t RESERVEDREG32B_38; __I uint32_t RESERVEDREG32B_39; __I uint32_t RESERVEDREG32B_40; __I uint32_t RESERVEDREG32B_41; __I uint32_t RESERVEDREG32B_42; __I uint32_t RESERVEDREG32B_43; __I uint32_t RESERVEDREG32B_44; __I uint32_t RESERVEDREG32B_45; __I uint32_t RESERVEDREG32B_46; __I uint32_t RESERVEDREG32B_47; __I uint32_t RESERVEDREG32B_48; __I uint32_t RESERVEDREG32B_49; __I uint32_t RESERVEDREG32B_50; __I uint32_t RESERVEDREG32B_51; __I uint32_t RESERVEDREG32B_52; __I uint32_t RESERVEDREG32B_53; __I uint32_t RESERVEDREG32B_54; __I uint32_t RESERVEDREG32B_55; __I uint32_t RESERVEDREG32B_56; __I uint32_t RESERVEDREG32B_57; __I uint32_t RESERVEDREG32B_58; __I uint32_t RESERVEDREG32B_59; __I uint32_t RESERVEDREG32B_60; __I uint32_t RESERVEDREG32B_61; __I uint32_t RESERVEDREG32B_62; __I uint32_t RESERVEDREG32B_63; __I uint32_t RESERVEDREG32B_64; __I uint32_t RESERVEDREG32B_65; __I uint32_t RESERVEDREG32B_66; __I uint32_t RESERVEDREG32B_67; __I uint32_t RESERVEDREG32B_68; /*Selects whether the peripheral is connected to the Fabric or IOMUX st ructure.*/ __IO uint32_t IOMUX0_CR; /*Configures the IO Mux structure for each IO pad. See the MSS MAS spec ification for for description.*/ __IO uint32_t IOMUX1_CR; /*Configures the IO Mux structure for each IO pad. See the MSS MAS spec ification for for description.*/ __IO uint32_t IOMUX2_CR; /*Configures the IO Mux structure for each IO pad. See the MSS MAS spec ification for for description.*/ __IO uint32_t IOMUX3_CR; /*Configures the IO Mux structure for each IO pad. See the MSS MAS spec ification for for description.*/ __IO uint32_t IOMUX4_CR; /*Configures the IO Mux structure for each IO pad. See the MSS MAS spec ification for for description.*/ __IO uint32_t IOMUX5_CR; /*Sets whether the MMC/SD Voltage select lines are inverted on entry to the IOMUX structure*/ __IO uint32_t IOMUX6_CR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_69; __I uint32_t RESERVEDREG32B_70; __I uint32_t RESERVEDREG32B_71; __I uint32_t RESERVEDREG32B_72; __I uint32_t RESERVEDREG32B_73; /*Configures the MSSIO block*/ __IO uint32_t MSSIO_BANK4_CFG_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_0_1_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_2_3_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_4_5_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_6_7_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_8_9_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_10_11_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK4_IO_CFG_12_13_CR; /*Configures the MSSIO block*/ __IO uint32_t MSSIO_BANK2_CFG_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_0_1_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_2_3_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_4_5_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_6_7_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_8_9_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_10_11_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_12_13_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_14_15_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_16_17_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_18_19_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_20_21_CR; /*IO electrical configuration for MSSIO pad*/ __IO uint32_t MSSIO_BANK2_IO_CFG_22_23_CR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_74; __I uint32_t RESERVEDREG32B_75; __I uint32_t RESERVEDREG32B_76; __I uint32_t RESERVEDREG32B_77; __I uint32_t RESERVEDREG32B_78; __I uint32_t RESERVEDREG32B_79; __I uint32_t RESERVEDREG32B_80; __I uint32_t RESERVEDREG32B_81; __I uint32_t RESERVEDREG32B_82; /*Sets M2F [31:0] Spares out signals*/ __IO uint32_t MSS_SPARE0_CR; /*Sets M2F [37:32] Spares out signals*/ __IO uint32_t MSS_SPARE1_CR; /*Read M2F [31:0] Spares out signals*/ __IO uint32_t MSS_SPARE0_SR; /*Read M2F [37:32] Spares out signals*/ __IO uint32_t MSS_SPARE1_SR; /*Read F2M [31:0] Spares in1 signals*/ __IO uint32_t MSS_SPARE2_SR; /*Read F2M [37:32] Spares in1 signals*/ __IO uint32_t MSS_SPARE3_SR; /*Read F2M [31:0] Spares in2 signals*/ __IO uint32_t MSS_SPARE4_SR; /*Read F2M [37:32] Spares in2 signals*/ __IO uint32_t MSS_SPARE5_SR; /* Padding reserved 32-bit registers.*/ __I uint32_t RESERVEDREG32B_83; __I uint32_t RESERVEDREG32B_84; /*Register for ECO usage*/ __IO uint32_t SPARE_REGISTER_RW; /*Register for ECO usage*/ __IO uint32_t SPARE_REGISTER_W1P; /*Register for ECO usage*/ __I uint32_t SPARE_REGISTER_RO; /*Spare signal back to G5C*/ __IO uint32_t SPARE_PERIM_RW; /*Unused FIC resets*/ __I uint32_t SPARE_FIC; } mss_sysreg_t; #define SYSREG_ATHENACR_RESET (1U << 0U) #define SYSREG_ATHENACR_PURGE (1U << 1U) #define SYSREG_ATHENACR_GO (1U << 2U) #define SYSREG_ATHENACR_RINGOSCON (1U << 3U) #define SYSREG_ATHENACR_COMPLETE (1U << 8U) #define SYSREG_ATHENACR_ALARM (1U << 9U) #define SYSREG_ATHENACR_BUSERROR (1U << 10U) #define SYSREG_SOFTRESET_ENVM (1U << 0U) #define SYSREG_SOFTRESET_TIMER (1U << 4U) #define SYSREG_SOFTRESET_MMUART0 (1U << 5U) #define SYSREG_SOFTRESET_DDRC (1U << 23U) #define SYSREG_SOFTRESET_FIC3 (1U << 27U) #define SYSREG_SOFTRESET_ATHENA (1U << 28U) #define SYSREG ((volatile mss_sysreg_t * const) BASE32_ADDR_MSS_SYSREG) #ifdef __cplusplus } #endif #endif /*MSS_SYSREG_H*/ mss_util.c000066400000000000000000000134741432224323300360700ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*************************************************************************** * @file mss_util.c * @author Microchip-FPGA Embedded Systems Solutions * @brief Utility functions * */ #include #include #include "mpfs_hal/mss_hal.h" #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------------ * */ void enable_interrupts(void) { __enable_irq(); } /*------------------------------------------------------------------------------ * */ uint64_t disable_interrupts(void) { uint64_t psr; psr = read_csr(mstatus); __disable_irq(); return(psr); } /*------------------------------------------------------------------------------ * */ void restore_interrupts(uint64_t saved_psr) { write_csr(mstatus, saved_psr); } /*------------------------------------------------------------------------------ * Disable all interrupts. */ void __disable_irq(void) { clear_csr(mstatus, MSTATUS_MIE); clear_csr(mstatus, MSTATUS_MPIE); } void __disable_all_irqs(void) { __disable_irq(); write_csr(mie, 0x00U); write_csr(mip, 0x00); } /*------------------------------------------------------------------------------ * Enable all interrupts. */ void __enable_irq(void) { set_csr(mstatus, MSTATUS_MIE); /* mstatus Register- Machine Interrupt Enable */ } /*------------------------------------------------------------------------------ * Enable particular local interrupt */ void __enable_local_irq(uint8_t local_interrupt) { ASSERT(local_interrupt > (int8_t)0); ASSERT( (local_interrupt <= LOCAL_INT_MAX)); uint8_t mhart_id = (uint8_t)read_csr(mhartid); if((local_interrupt > (int8_t)0) && (local_interrupt <= LOCAL_INT_MAX)) { set_csr(mie, (0x1LLU << (int8_t)(local_interrupt + LOCAL_INT_OFFSET_IN_MIE))); /* mie Register- Machine Interrupt Enable Register */ /* Enable F2M interrupts as local instead of PLIC interrupts */ if (local_interrupt >= LOCAL_INT_F2M_OFFSET) { if (mhart_id == 1) { SYSREG->FAB_INTEN_U54_1 |= (1u << (local_interrupt - LOCAL_INT_F2M_OFFSET)); } else if (mhart_id == 2) { SYSREG->FAB_INTEN_U54_2 |= (1u << (local_interrupt - LOCAL_INT_F2M_OFFSET)); } else if (mhart_id == 3) { SYSREG->FAB_INTEN_U54_3 |= (1u << (local_interrupt - LOCAL_INT_F2M_OFFSET)); } else if (mhart_id == 4) { SYSREG->FAB_INTEN_U54_4 |= (1u << (local_interrupt - LOCAL_INT_F2M_OFFSET)); } } } } /*------------------------------------------------------------------------------ * Disable particular local interrupt */ void __disable_local_irq(uint8_t local_interrupt) { ASSERT(local_interrupt > (int8_t)0); ASSERT( (local_interrupt <= LOCAL_INT_MAX)); if((local_interrupt > (int8_t)0) && (local_interrupt <= LOCAL_INT_MAX)) { clear_csr(mie, (0x1LLU << (int8_t)(local_interrupt + LOCAL_INT_OFFSET_IN_MIE))); /* mie Register- Machine Interrupt Enable Register */ } } /** * readmcycle(void) * @return returns the mcycle count from hart CSR */ uint64_t readmcycle(void) { return (read_csr(mcycle)); } void sleep_ms(uint64_t msecs) { uint64_t starttime = readmtime(); volatile uint64_t endtime = 0U; while(endtime < (starttime+msecs)) { endtime = readmtime(); } } /** * sleep_cycles(uint64_t ncycles) * @param number of cycles to sleep */ void sleep_cycles(uint64_t ncycles) { uint64_t starttime = readmcycle(); volatile uint64_t endtime = 0U; while(endtime < (starttime + ncycles)) { endtime = readmcycle(); } } /** * get_program_counter(void) * @return returns the program counter */ __attribute__((aligned(16))) uint64_t get_program_counter(void) { uint64_t prog_counter; asm volatile ("auipc %0, 0" : "=r"(prog_counter)); return (prog_counter); } /** * get_stack_pointer(void) * @return Return the stack pointer */ uint64_t get_stack_pointer(void) { uint64_t stack_pointer; asm volatile ("addi %0, sp, 0" : "=r"(stack_pointer)); return (stack_pointer); } /** * Return the tp register * The tp register holds the value of the Hart Common memory HLS once not in an * interrupt. If the tp value is used in an interrupt, it is saved first and * restored on exit. This conforms to OpenSBI implementation. * * @return returns the tp register value */ uint64_t get_tp_reg(void) { uint64_t tp_reg_val; asm volatile ("addi %0, tp, 0" : "=r"(tp_reg_val)); return (tp_reg_val); } #ifdef PRINTF_DEBUG_SUPPORTED void display_address_of_interest(uint64_t * address_of_interest, int nb_locations) { uint64_t * p_addr_of_interest = address_of_interest; int inc; mpfs_printf(" Displaying address of interest: 0x%lx\n", p_addr_of_interest); for (inc = 0U; inc < nb_locations; ++inc) { mpfs_printf(" address of interest: 0x%lx: 0x%lx\n", p_addr_of_interest, *p_addr_of_interest); p_addr_of_interest = p_addr_of_interest + 8; } } #endif /*------------------------------------------------------------------------------ * This function disables dynamic branch prediction on the hart from which it * executes. It is enabled by default. */ void disable_branch_prediction(void) { write_csr(0x7C0, 0x1u); } /*------------------------------------------------------------------------------ * This function enables dynamic branch prediction on the hart from which it * executes. */ void enable_branch_prediction(void) { write_csr(0x7C0, 0x0u); } #ifdef __cplusplus } #endif mss_util.h000066400000000000000000000044541432224323300360730ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*************************************************************************** * @file mss_util.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MACROs defines and prototypes associated with utility functions * */ #ifndef MSS_UTIL_H #define MSS_UTIL_H #include #include #include "encoding.h" #include "mss_hart_ints.h" #ifdef __cplusplus extern "C" { #endif /* * Useful macros */ #define WRITE_REG8(x, y) (*((volatile uint8_t *)(x)) = (y)) #define READ_REG8(x) (*((volatile uint8_t *)(x))) #define WRITE_REG32(x, y) (*((volatile uint32_t *)(x)) = (y)) #define READ_REG32(x) (*((volatile uint32_t *)(x))) #define WRITE_REG64(x, y) (*((volatile uint64_t *)(x)) = (y)) #define READ_REG64(x) (*((volatile uint64_t *)(x))) /* * Local defines */ #define LOCAL_INT_OFFSET_IN_MIE 16U /* Offset from start of MIE for local irq enables */ #define LOCAL_INT_F2M_OFFSET 16U /* Offset from 0 for fabric to MSS local interrupts */ /* * return mcycle */ uint64_t readmcycle(void); void sleep_ms(uint64_t msecs); void sleep_cycles(uint64_t ncycles); uint64_t get_stack_pointer(void); uint64_t get_tp_reg(void); uint64_t get_program_counter(void) __attribute__((aligned(16))); #ifdef MPFS_PRINTF_DEBUG_SUPPORTED void display_address_of_interest(uint64_t * address_of_interest, int nb_locations); #endif void exit_simulation(void); void enable_interrupts(void); uint64_t disable_interrupts(void); void restore_interrupts(uint64_t saved_psr); void __disable_irq(void); void __disable_all_irqs(void); void __enable_irq(void); void __enable_local_irq(uint8_t local_interrupt); void __disable_local_irq(uint8_t local_interrupt); void disable_branch_prediction(void); void enable_branch_prediction(void); static inline void spinunlock(volatile long *pLock) { __sync_lock_release(pLock); } static inline void spinlock(volatile long *pLock) { while(__sync_lock_test_and_set(pLock, 1)) { /* add yield if OS */ #if defined USING_FREERTOS taskYIELD(); #endif } } #ifdef __cplusplus } #endif #endif /* MSS_UTIL_H */ nwc/000077500000000000000000000000001432224323300346435ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/commonmss_cfm.c000066400000000000000000000100271432224323300364360ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * */ #include #include #include #include #include #include #include #include "mpfs_hal/mss_hal.h" #include "mss_cfm.h" /***************************************************************************//** * See mss_cfm.h for description of this function. */ uint8_t MSS_CFM_control_start(void) { /* Writing a 1, to this causes measurement circuitry to start. */ CFM_REG->controlReg |= 1; return (CFM_REG->controlReg & CFM_CONTROL_REG_START_MASK); } uint8_t MSS_CFM_control_stop(void) { /* Writing a 1, to this causes measurement circuitry to start. */ CFM_REG->controlReg |= (1 << CFM_CONTROL_REG_STOP_BITS_SHIFT); return (CFM_REG->controlReg & CFM_CONTROL_REG_START_MASK); } cfm_error_id_t MSS_CLF_clk_configuration( uint8_t clkSel, uint8_t refsel0, uint8_t refsel1, uint8_t monSEL, uint8_t monEN ) { /* Reset the register. */ CFM_REG->clkselReg = 0; /* Some error checking on configuration values. */ if(clkSel > CFM_CLK_SEL_MASK) return ERROR_INVALID_CLK_SELECTION_GROUP; if(refsel0 > CFM_CLK_REFSEL0_MASK) return ERROR_INVALID_REF_SEL0; if(refsel1 > CFM_CLK_REFSEL1_MASK) return ERROR_INVALID_REF_SEL1; if(monSEL > CFM_CLK_MONSEL_MASK) return ERROR_INVALID_CHANNEL_DRIVE_CLK_MONITOR; CFM_REG->clkselReg |= (clkSel & CFM_CLK_SEL_MASK); if(refsel0) CFM_REG->clkselReg |= (uint32_t)(refsel0 << CFM_CLK_REFSEL0SHIFT); if(refsel1) CFM_REG->clkselReg |= (uint32_t)(refsel1 << CFM_CLK_REFSEL1SHIFT); if(monSEL) CFM_REG->clkselReg |= (uint32_t)(monSEL << CFM_CLK_MONSEL_SHIFT); if(monEN) CFM_REG->clkselReg |= (uint32_t)(monEN << CFM_CLK_MONEN_SHIFT); return CFM_OK; } void MSS_CFM_runtime_register(uint32_t referenceCount) { /*Sets how many runtime reference clock cycles the frequency and time * measurement shold be made for.. */ CFM_REG->runtimeReg = (referenceCount & CFM_RUNTIME_REG_MASK); return; } void MSS_CFM_channel_mode(cfmChannelMode chMode) { uint32_t chConfiguration = 0; chConfiguration |= (chMode.channel0 & CFM_CHANNEL_MODE_MASK) << CFM_CH0_SHIFT_MASK; chConfiguration |= (chMode.channel1 & CFM_CHANNEL_MODE_MASK) << CFM_CH1_SHIFT_MASK; chConfiguration |= (chMode.channel2 & CFM_CHANNEL_MODE_MASK) << CFM_CH2_SHIFT_MASK; chConfiguration |= (chMode.channel3 & CFM_CHANNEL_MODE_MASK) << CFM_CH3_SHIFT_MASK; chConfiguration |= (chMode.channel4 & CFM_CHANNEL_MODE_MASK) << CFM_CH4_SHIFT_MASK; chConfiguration |= (chMode.channel5 & CFM_CHANNEL_MODE_MASK) << CFM_CH5_SHIFT_MASK; chConfiguration |= (chMode.channel6 & CFM_CHANNEL_MODE_MASK) << CFM_CH6_SHIFT_MASK; chConfiguration |= (chMode.channel7 & CFM_CHANNEL_MODE_MASK) << CFM_CH7_SHIFT_MASK; CFM_REG->modelReg = chConfiguration; return; } cfm_error_id_t MSS_CFM_get_count(cfm_count_id_t ch, uint32_t *count) { if(count == NULL) return ERROR_NULL_VALUE; *count = 0; if(CFM_REG->controlReg & CFM_CONTROL_REG_BUSY_MASK) return ERROR_INVALID_CFM_BUSY; switch(ch) { case CFM_COUNT_0: *count = CFM_REG->count0; break; case CFM_COUNT_1: *count = CFM_REG->count1; break; case CFM_COUNT_2: *count = CFM_REG->count2; break; case CFM_COUNT_3: *count = CFM_REG->count3; break; case CFM_COUNT_4: *count = CFM_REG->count4; break; case CFM_COUNT_5: *count = CFM_REG->count5; break; case CFM_COUNT_6: *count = CFM_REG->count6; break; case CFM_COUNT_7: *count = CFM_REG->count7; break; default: return 11; } return CFM_OK; } mss_cfm.h000066400000000000000000000171261432224323300364520ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * */ /*=========================================================================*//** @mainpage PolarFire MSS Frequency Meter Bare Metal Driver. The MSS Clock Frequency Meter (CFM) block is used to support test of the DLL's within the MSS. All functional clocks are connected to the CFM block. The frequency meter can be configured to measure time or frequency, time allowing items such as PLL lock times to be tested and frequency to test oscillator frequencies. Upto 8 circuit counters are implemented. @section intro_sec Introduction *//*=========================================================================*/ #ifndef __COREPLEX_PLATFORM_CFM_H_ #define __COREPLEX_PLATFORM_CFM_H_ #ifdef __cplusplus extern "C" { #endif /* CFM Register base address. */ #define CFM_REG_BASE 0x20006000 /***************************************************************************//** The __cfm_count_id_t enumeration is used to identify the channel used. */ typedef enum __cfm_count_id { CFM_COUNT_0 = 0, CFM_COUNT_1, CFM_COUNT_2, CFM_COUNT_3, CFM_COUNT_4, CFM_COUNT_5, CFM_COUNT_6, CFM_COUNT_7, cfm_lastCH, } cfm_count_id_t; /***************************************************************************//** The cfm_channel_mode enumeration is used to specify the channel mode. */ typedef enum __cfm_channel_mode { CFM_CH_DISABLED = 0, CFM_CH_FREQUENCY_MODE, CFM_CH_RESERVER, CFM_CH_TIMER_MODE, CFM_CH_lastmd } cfm_channel_mode; typedef enum __cfm_error_id_t { CFM_OK = 0, ERROR_INVALID_CLK_SELECTION_GROUP, ERROR_INVALID_REF_SEL0, ERROR_INVALID_REF_SEL1, ERROR_INVALID_CHANNEL_DRIVE_CLK_MONITOR, ERROR_INVALID_CFM_BUSY, ERROR_NULL_VALUE, ERROR_CFMLAST_ID } cfm_error_id_t; typedef struct _cfmRegs { __IO uint32_t controlReg; /* CFM Control Register */ __IO uint32_t clkselReg; /* Clock Selection Register */ __IO uint32_t runtimeReg; /* Reference Count Value */ __IO uint32_t modelReg; /* Sets the measurement mode */ __I uint32_t count0; /* Count x value */ __I uint32_t count1; __I uint32_t count2; __I uint32_t count3; __I uint32_t count4; __I uint32_t count5; __I uint32_t count6; __I uint32_t count7; __I uint32_t reserved[4]; /*Reserved registers, padding structure */ }CFM; #define CFM_REG ((CFM *)CFM_REG_BASE) typedef struct _cfmChannelMode { uint8_t channel0; /* Channel x mode */ uint8_t channel1; /* Channel x mode */ uint8_t channel2; /* Channel x mode */ uint8_t channel3; /* Channel x mode */ uint8_t channel4; /* Channel x mode */ uint8_t channel5; /* Channel x mode */ uint8_t channel6; /* Channel x mode */ uint8_t channel7; /* Channel x mode */ }cfmChannelMode; #define CFM_CONTROL_REG_BUSY_MASK 0x01U #define CFM_CONTROL_REG_START_MASK 0x01U #define CFM_CONTROL_REG_STOP_BITS_SHIFT 0x01U #define CFM_CLK_SEL_MASK 0x07U #define CFM_CLK_REFSEL0_MASK 0x01U #define CFM_CLK_REFSEL0SHIFT 0x04U #define CFM_CLK_REFSEL1_MASK 0x01U #define CFM_CLK_REFSEL1SHIFT 0x05U #define CFM_CLK_MONSEL_MASK 0x07U #define CFM_CLK_MONSEL_SHIFT 0x08U #define CFM_CLK_MONEN_MASK 0x01 #define CFM_CLK_MONEN_SHIFT 11U #define CFM_RUNTIME_REG_MASK 0xFFFFFFU #define CFM_CHANNEL_MODE_MASK 0x3U #define CFM_CH0_SHIFT_MASK 0x00U #define CFM_CH1_SHIFT_MASK 0x02U #define CFM_CH2_SHIFT_MASK 0x04U #define CFM_CH3_SHIFT_MASK 0x06U #define CFM_CH4_SHIFT_MASK 0x08U #define CFM_CH5_SHIFT_MASK 0x0AU #define CFM_CH6_SHIFT_MASK 0x0CU #define CFM_CH7_SHIFT_MASK 0x0EU /***************************************************************************** * CFM Function Prototypes ******************************************************************************* */ /*-------------------------------------------------------------------------*//** The MSS_CFM_control_start() function causes the measurement circuitry to start. This state of 'busy' will clear which measurement is complete. @param None @return Busy state Example: The following call will start the CFM @code MSS_CFM_control_start( ); @endcode */ uint8_t MSS_CFM_control_start(void); /*-------------------------------------------------------------------------*//** The MSS_CFM_control_stop() function causes the measurement circuitry to stop. @param None @return uint8_t Returns the busy flag. Example: The following call will stop the CFM @code MSS_CFM_control_stop( ); @endcode */ uint8_t MSS_CFM_control_stop(void); /*-------------------------------------------------------------------------*//** The MSS_CLF_clk_configuration() function is used to configure the clock selection register. @param clkSel Selects which group of clock inputs are selected by the channels, control the input multiplexer. @param refsel0 Selects the reference input, 0=clkref1 / 1=clkref2 @param refsel1 When in timer mode allows ATPG (corners) / clkref3 clock input to clock the channel counters. This clock input is expected to be sourced from an on-chip PLL to support at-speed testing. This allows the timer to clocked off a much higher clock frequency that the reference counter that is limited to 100Mhz. @param monSEL Selects which channel drives the clock monitor output 0-7. @param monEN Enables the clock monitor output. @return cfm_error_id_t Example: The following call will configure clk 0, using clkref1, channel zero drives the clock monitor and enable the clock monitor output. @code MSS_GPIO_config( 0, 0, 0, 0, 1 ); @endcode */ cfm_error_id_t MSS_CLF_clk_configuration( uint8_t clkSel, uint8_t refsel0, uint8_t refsel1, uint8_t monSEL, uint8_t monEN ); /*-------------------------------------------------------------------------*//** The MSS_CFM_runtime_register() function is used to set how many reference clock cycles the frequency and time measurement should be made. The register does NOT change during oepration @param refcount The reference count value. */ void MSS_CFM_runtime_register( uint32_t referenceCount ); /*-------------------------------------------------------------------------*//** The MSS_CFM_channel_mode() function is used to set the measurement mode for the specified channel. 2'b00: Disabled 2'b01: Frequency Mode 2'b11: Timer Mode 2'b10: Reserved @param cfmChannelMode Configuration structure for each channel @return None */ void MSS_CFM_channel_mode(cfmChannelMode chMode); /*-------------------------------------------------------------------------*//** The MSS_CFM_get_count() function is used to get the count value. Block must not be busy. @param ch The channel ID to return the count for. @param count The count for the channel register. @return cfm_error_id_t Example: The following call will return the value in count register. channel 0 @code MSS_CFM_get_count(); @endcode */ cfm_error_id_t MSS_CFM_get_count(cfm_count_id_t ch, uint32_t *count); #ifdef __cplusplus } #endif #endif /* __COREPLEX_PLATFORM_CFM_H_ */ mss_ddr.c000066400000000000000000007667211432224323300364650ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_ddr.h * @author Microchip-FPGA Embedded Systems Solutions * @brief DDR related code * */ //#define PRINT_CA_VREF_WINDOW "1" #define MOVE_CK #define MANUAL_ADDCMD_TRAINIG //#define FABRIC_NOISE_TEST #include #include #include "mpfs_hal/mss_hal.h" #include "mss_nwc_init.h" #ifdef DDR_SUPPORT #include "mss_ddr_debug.h" #include "simulation.h" #ifdef FABRIC_NOISE_TEST #include "drivers/mss_gpio/mss_gpio.h" #endif /******************************************************************************* * Local Defines */ /* This string is updated if any change to ddr driver */ #define DDR_DRIVER_VERSION_STRING "0.4.018" const char DDR_DRIVER_VERSION[] = DDR_DRIVER_VERSION_STRING; /* Version | Comment */ /* 0.4.018 | Corrected error introduced for DDR3 in 0.4.14 */ /* 0.4.017 | made SW_TRAING_BCLK_SCLK_OFFSET seperate for each mem type */ /* 0.4.016 | DDR3-Added support for DDR3L removed in v0.3.027 */ /* | Corrected dpc value update during write leveling */ /* 0.4.015 | Added some debug feedback in verify state. */ /* 0.4.014 | Tidy-up, replace some majic numbers.No functional change. */ /* 0.4.013 | ddr3- Corrected dpc value update during write leveling */ /* 0.4.012 | ADD_CMD_CLK_MOVE_ORDER 0,1,2 for 1333Mhz, 1,2,0 for 1600MHz */ /* | LIBERO_SETTING_RPC_156_VALUE 1 for 1333Mhz, 6 for 1600MHz */ /* 0.4.011 | ADD_CMD_CLK_MOVE_ORDER changed from 0,1,2 to 1,2,0 */ /* 0.4.010 | LIBERO_SETTING_RPC_156_VALUE default changed from 1 to 6 */ /* 0.4.009 | vrgen, modify during write leveling for DDR3 corrected */ /* 0.4.008 | DQ/DQS push order has been parameterised */ /* 0.4.007 | Corrected write_latency print message */ /* 0.4.006 | Refactored delay() routine, skips extra checking in write */ /* | calibration once a failure has occured to shorten training */ /* | time. */ /* 0.4.005 | When LIBERO_FAST_START, now slects random as opposed to */ /* | counting pattern. */ /* 0.4.004 | Upadted tip_register_status() to show dual ranks */ /* 0.4.003 | Added FAST_START option - can reduce post training checks */ /* 0.4.002 | Added stat recording ddr training time */ /* 0.4.001 | Fixed DDR3 DDR_1333_MHZ define to match Libero gen version */ /* 0.4.000 | corrected incorrect offset introduced in last commit */ /* 0.3.030 | Added setting of rpc136, required for board tuning to pass */ /* | DQ/DQS Window when too small. Moves test start from the */ /* | starting edge. */ /* 0.3.029 | LIBERO_SETTING_REFCLK_DDR3_1067_NUM_OFFSETS changed 2 to 1 */ /* 0.3.028 | ddr3_address_cmd_training() routine added */ /* 0.3.027 | ddr3 mod- vrgen, modify during write leveling */ /* 0.3.026 | SW_TRAING_BCLK_SCLK_OFFSET changed from 0 to 5 */ /* 0.3.025 | LPDDR4@1600 ref clk offsets 4,3,2,4 changed to 3,4,2,5 */ /* 0.3.024 | lpddr4_manual_training() improved */ /* 0.3.023 | Changing the common mode of the Receiver to low common mode */ /* 0.3.022 | DDR_VERIFY_PATTERN_IN_CACHE added tests */ /* 0.3.021 | Turn off ODT during write leveling */ /* 0.3.020 | added for retrain reset */ /* 0.3.019 | SAR122487 training not converging at 125C Min condition on */ /* | rev-c devices. */ /* 0.3.018 | SAR121393 relates to DDR3 robustness when ECC not being used*/ /* | Note: DDR3 with no ECC only affected varient */ /* 0.3.017 | Removed some warnings, some tidy-up, removed sweep code */ /* | as not being used. */ /* | restriced INIT_AUTOINIT_DISABLE=0x1; in DDR_TRAINING_RESET */ /* | state to lpddr4 only, as only in lpddr4 DCT version */ /* | and causes issue for DDR3 */ /* 0.3.016 | Multiple LPDDR4 updates. */ /* 0.3.015 | REFCLK change for LPDDR3, rpc168 = 0x0U for LPDDR3 */ /* 0.3.014 | DDR3 WPU/WPD overridden, REFCLK (0,1) -> (7,0) */ /* 0.3.013 | DDR4 refclk offsets updated by dct */ /* 0.3.012 | DDR Controller reset toggled on start-up, DDR refclk */ /* | default offsets updated */ /* 0.3.011 | Update to DDR4 ADD CMD sweep @800 <0,7,1> to <7,0> */ /* 0.3.010 | Update to LPDDR4 ADD CMD sweep values <5,4,6,3> to <1,5,1,5>*/ /* 0.3.009 | Corrected refclk_offset used for lower frequecies */ /* | See function: ddr_manual_addcmd_refclk_offset() */ /* 0.3.008 | Removed weak rand() function, which continually returned 0 */ /* 0.3.007 | Updated DDR3 add cmd offsets */ /* | Updated DDR4 add cmd offsets */ /* 0.3.006 | modified debug printing after failure */ /* 0.3.005 | modified addcmd offsets DDR3/DDR3L @ 1333 = 0,1 */ /* | DDR3/DDR3L to 0,1 */ /* | Also some ADD CMD training improvments from Jaswanth */ /* 0.3.004 | Removed dq setting before claibration for DDR3/4 and lpddr3 */ /* | Some tidy up */ /* 0.3.003 | Modified latency sweep from 0-8 to 0-3. Speeded u[p MCC test*/ /* | when faulure */ /* 0.3.002 | Move refclk offset outside manual training loop */ /* 0.3.001 | wip - adding in manual add cmd training */ /* 0.3.000 | wip - adding in manual add cmd training */ /* 0.2.003 | Updated SEG setup to match Libero 12.7, Removed warnings, */ /* | shortened timeout in mtc_test */ /* 0.2.002 | MTC_test() update -added more tests */ /* 0.2.001 | Reverted ADDCMD training command */ /* 0.2.000 | RPC166 now does short retrain by default */ /* 0.1.009 | Removed AXI overrides. Agreed better placed in */ /* | mss_sw_config.h util until corrected in configurator v3.0 */ /* 0.1.008 | Added manual addcmd traing for all variants */ /* 0.1.007 | Added some updates from SVG and DCT. Also overrides AXI */ /* | ranges if incorrectly set (Liber0 v12.5 and Liber0 v12.6 */ /* 0.1.006 | Added tuning for rpc166, read lane FIFO alignement */ /* 0.1.005 | Added parameter to modify rpc166, lane out of sync on read */ /* 0.1.004 | Corrected default RPC220 setting so dq/dqs window centred */ /* 0.1.003 | refclk_phase correctly masked during bclk sclk sw training */ /* 0.1.002 | Reset modified- corrects softreset on retry issue (1.8.x) */ /* 0.1.001 | Reset modified- corrects softreset on retry issue (1.7.2) */ /* 0.0.016 | Added #define DDR_FULL_32BIT_NC_CHECK_EN to mss_ddr.h */ /* 0.0.016 | updated mss_ddr_debug.c with additio of 32-bit write test */ /* 0.0.015 | DDR3L - Use Software Bclk Sclk training */ /* 0.0.014 | DDR3 and DDR update to sync with SVG proven golden version */ /* 0.0.013 | Added code to turn off DM if DDR4 and using ECC */ /* 0.0.012 | Added support for turning off unused I/O from Libero */ /* * Calibration data records calculated write calibration values during training */ mss_ddr_calibration calib_data; mss_ddr_diag ddr_diag; /* rx lane FIFO used for tuning */ #if (TUNE_RPC_166_VALUE == 1) static uint32_t rpc_166_fifo_offset; #endif /* auto tunes rpc156 when enabled */ #ifdef TUNE_RPC_156_DQDQS_INIT_VALUE static uint32_t rpc_156_dqdqs_init_offset = LIBERO_SETTING_MIN_RPC_156_VALUE; #endif /* * This string is used as a quick sanity check of write/read to DDR. * The memory test core is used for more comprehensive testing during and * post calibration */ #ifdef DDR_SANITY_CHECKS_EN static const uint32_t test_string[] = { 0x12345678,23211234,0x35675678,0x4456789,0x56789123,0x65432198,\ 0x45673214,0xABCD1234,0x99999999,0xaaaaaaaa,0xbbbbbbbb,0xcccccccc,\ 0xdddddddd,0xeeeeeeee,0x12121212,0x12345678}; #endif /******************************************************************************* * external functions */ /* Use to record instance of errors during calibration */ static uint32_t ddr_error_count; /******************************************************************************* * Local function declarations */ #ifdef ZQ_CAL static uint32_t zq_cal(void); #endif static uint32_t mode_register_masked_write(uint32_t address); static uint32_t mode_register_masked_write_x5(uint32_t address); static uint32_t ddr_setup(void); static void init_ddrc(void); static uint8_t write_calibration_using_mtc(uint8_t num_of_lanes_to_calibrate); /*static uint8_t mode_register_write(uint32_t MR_ADDR, uint32_t MR_DATA);*/ static uint8_t MTC_test(uint8_t mask, uint64_t start_address, uint32_t size, MTC_PATTERN pattern, MTC_ADD_PATTERN add_pattern, uint32_t *error); #ifdef VREFDQ_CALIB static uint8_t FPGA_VREFDQ_calibration_using_mtc(void); static uint8_t VREFDQ_calibration_using_mtc(void); #endif #ifdef DDR_SANITY_CHECKS_EN static uint8_t rw_sanity_chk(uint64_t * address, uint32_t count); static uint8_t mtc_sanity_check(uint64_t start_address); #endif #ifdef SET_VREF_LPDDR4_MODE_REGS static uint8_t mode_register_write(uint32_t MR_ADDR, uint32_t MR_DATA); #endif #ifdef MODE_WRITE1_USED static uint32_t mode_register_write1(uint32_t address, uint32_t data); #endif #ifdef DDR_SANITY_CHECKS_EN static uint8_t memory_tests(void); #endif static void ddr_off_mode(void); static void set_ddr_mode_reg_and_vs_bits(uint32_t dpc_bits); static void set_ddr_rpc_regs(DDR_TYPE ddr_type); static uint8_t get_num_lanes(void); static void load_dq(uint8_t lane); static uint8_t use_software_bclk_sclk_training(DDR_TYPE ddr_type); static uint8_t bclk_sclk_offset(DDR_TYPE ddr_type); static void config_ddr_io_pull_up_downs_rpc_bits(DDR_TYPE ddr_type); #ifdef MANUAL_ADDCMD_TRAINIG static uint8_t ddr_manual_addcmd_refclk_offset(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index); #endif static void lpddr4_manual_training(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index, uint32_t retry_count, uint8_t *refclk_offset); static void non_lpddr4_address_cmd_training(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index, uint32_t *bclk_phase, uint32_t *bclk90_phase, uint32_t *refclk_phase ); static void ddr3_address_cmd_training(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index, uint32_t retry_count, uint32_t *bclk_phase, uint32_t *bclk90_phase, uint32_t *refclk_phase, uint8_t *refclk_offset); /******************************************************************************* * External function declarations */ #ifdef DEBUG_DDR_INIT extern mss_uart_instance_t *g_debug_uart; #ifdef DEBUG_DDR_DDRCFG void debug_read_ddrcfg(void); #endif #endif #ifdef FABRIC_NOISE_TEST uint32_t fabric_noise_en = 1; uint32_t fabric_noise_en_log = 1; uint32_t num_of_noise_blocks_en = 3; /* do not set less than 1 */ uint32_t noise_ena = 0x0; #endif /******************************************************************************* * Instance definitions */ /******************************************************************************* * Public Functions - API ******************************************************************************/ /***************************************************************************//** * ddr_state_machine(DDR_SS_COMMAND) * call this routine if you do not require the state machine * * @param ddr_type */ uint32_t ddr_state_machine(DDR_SS_COMMAND command) { static DDR_SM_STATES ddr_state; static uint32_t return_status; if (command == DDR_SS__INIT) { ddr_state = DDR_STATE_INIT; } SIM_FEEDBACK0(100U + ddr_state); SIM_FEEDBACK1(ddr_state); switch (ddr_state) { default: case DDR_STATE_INIT: ddr_state = DDR_STATE_TRAINING; return_status = 0U; break; case DDR_STATE_TRAINING: /* * We stay in this state until finished training/fail training */ return_status = ddr_setup(); break; case DDR_STATE_MONITOR: /* * 1. Periodically check DDR access * 2. Run any tests, as directed */ // return_status = ddr_monitor(); break; } SIM_FEEDBACK1(0xFF000000UL + return_status); return (return_status); } /***************************************************************************//** * ddr_setup(DDR_TYPE ddr_type) * call this routine if you do not require the state machine * * @param ddr_type */ static uint32_t ddr_setup(void) { static DDR_TRAINING_SM ddr_training_state = DDR_TRAINING_INIT; static uint32_t error; static uint32_t timeout; #ifdef DEBUG_DDR_INIT static uint32_t addr_cmd_value; static uint32_t bclk_sclk_offset_value; static uint32_t dpc_vrgen_v_value; static uint32_t dpc_vrgen_h_value; static uint32_t dpc_vrgen_vs_value; #endif static uint32_t retry_count; static uint32_t write_latency; static uint32_t tip_cfg_params; static uint32_t dpc_bits; static uint64_t training_start_cycle; #if (TUNE_RPC_166_VALUE == 1) static uint8_t num_rpc_166_retires = 0U; #endif #ifdef MANUAL_ADDCMD_TRAINIG static uint8_t refclk_offset; static uint8_t refclk_sweep_index =0xFU; #endif static uint32_t bclk_answer = 0U; DDR_TYPE ddr_type; uint32_t ret_status = 0U; uint8_t number_of_lanes_to_calibrate; ddr_type = LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_MASK; SIM_FEEDBACK0(200U + ddr_training_state); SIM_FEEDBACK1(0U); switch (ddr_training_state) { case DDR_TRAINING_INIT: training_start_cycle = rdcycle(); tip_cfg_params = LIBERO_SETTING_TIP_CFG_PARAMS; dpc_bits = LIBERO_SETTING_DPC_BITS ; write_latency = LIBERO_SETTING_CFG_WRITE_LATENCY_SET; #if (TUNE_RPC_166_VALUE == 1) rpc_166_fifo_offset = DEFAULT_RPC_166_VALUE; #endif #ifdef MANUAL_ADDCMD_TRAINIG refclk_offset = LIBERO_SETTING_MAX_MANUAL_REF_CLK_PHASE_OFFSET + 1U; #endif ddr_error_count = 0U; error = 0U; memfill((uint8_t *)&calib_data,0U,sizeof(calib_data)); memfill((uint8_t *)&ddr_diag,0U,sizeof(ddr_diag)); retry_count = 0U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r Start training. TIP_CFG_PARAMS:"\ , LIBERO_SETTING_TIP_CFG_PARAMS); #endif ddr_training_state = DDR_TRAINING_CHECK_FOR_OFFMODE; break; case DDR_TRAINING_FAIL_SM2_VERIFY: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r SM2_VERIFY: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_SM_VERIFY: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r SM_VERIFY: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_SM_DQ_DQS: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r SM_DQ_DQS: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_SM_RDGATE: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r SM_RDGATE: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_SM_WRLVL: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r SM_WRLVL: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_SM_ADDCMD: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r SM_ADDCMD: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_SM_BCLKSCLK: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r BCLKSCLK_SWY: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_BCLKSCLK_SW: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r BCLKSCLK_SW: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_FULL_32BIT_NC_CHECK: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r 32BIT_NC_CHECK: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_32BIT_CACHE_CHECK: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r 32BIT_CACHE_CHECK: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_MIN_LATENCY: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r MIN_LATENCY: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_START_CHECK: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r START_CHECK: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_PLL_LOCK: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r PLL LOCK FAIL: ",addr_cmd_value); #endif ddr_training_state = DDR_TRAINING_FAIL; break; case DDR_TRAINING_FAIL_DDR_SANITY_CHECKS: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r DDR_SANITY_CHECKS FAIL: ",\ addr_cmd_value); ddr_training_state = DDR_TRAINING_FAIL; #endif break; case DDR_TRAINING_FAIL: #ifdef DEBUG_DDR_INIT { tip_register_status (g_debug_uart); (void)uprint32(g_debug_uart, "\n\r ****************************************************", 0U); } #endif DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; delay(DELAY_CYCLES_5_MICRO); DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x1; delay(DELAY_CYCLES_2MS); retry_count++; ddr_diag.num_retrains = retry_count; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r DDR_TRAINING_FAIL: ",\ ddr_training_state); (void)uprint32(g_debug_uart, "\n\r Retry Count: ", retry_count); #endif /* Init */ ddr_error_count = 0U; error = 0U; memfill((uint8_t *)&calib_data,0U,sizeof(calib_data)); DDRCFG->DFI.PHY_DFI_INIT_START.PHY_DFI_INIT_START = 0x0U; /* reset controller */ DDRCFG->MC_BASE2.CTRLR_INIT.CTRLR_INIT = 0x0U; CFG_DDR_SGMII_PHY->training_start.training_start = 0x0U; ddr_training_state = DDR_TRAINING_CHECK_FOR_OFFMODE; break; case DDR_TRAINING_CHECK_FOR_OFFMODE: /* * check if we are in off mode */ if (ddr_type == DDR_OFF_MODE) { ddr_off_mode(); ret_status |= DDR_SETUP_DONE; return (ret_status); } else { /* * set initial conditions */ /* enable fabric noise */ #ifdef FABRIC_NOISE_TEST if(fabric_noise_en) { SYSREG->SOFT_RESET_CR &= 0x00U; SYSREG->SUBBLK_CLOCK_CR = 0xffffffffUL; SYSREG->GPIO_INTERRUPT_FAB_CR = 0x00000000UL; PLIC_init(); PLIC_SetPriority_Threshold(0); __enable_irq(); /* bit0-bit15 used to enable noise logic in steps of 5% bit 16 noise logic reset bit 17 clkmux sel bit 18 pll powerdown bit 19 external io enable for GCLKINT */ PLIC_SetPriority(GPIO0_BIT0_or_GPIO2_BIT0_PLIC_0, 4U); PLIC_SetPriority(GPIO0_BIT1_or_GPIO2_BIT1_PLIC_1, 4U); PLIC_SetPriority(GPIO0_BIT2_or_GPIO2_BIT2_PLIC_2, 4U); PLIC_SetPriority(GPIO0_BIT3_or_GPIO2_BIT3_PLIC_3, 4U); PLIC_SetPriority(GPIO0_BIT4_or_GPIO2_BIT4_PLIC_4, 4U); PLIC_SetPriority(GPIO0_BIT5_or_GPIO2_BIT5_PLIC_5, 4U); PLIC_SetPriority(GPIO0_BIT6_or_GPIO2_BIT6_PLIC_6, 4U); PLIC_SetPriority(GPIO0_BIT7_or_GPIO2_BIT7_PLIC_7, 4U); PLIC_SetPriority(GPIO0_BIT8_or_GPIO2_BIT8_PLIC_8, 4U); PLIC_SetPriority(GPIO0_BIT9_or_GPIO2_BIT9_PLIC_9, 4U); PLIC_SetPriority(GPIO0_BIT10_or_GPIO2_BIT10_PLIC_10, 4U); PLIC_SetPriority(GPIO0_BIT11_or_GPIO2_BIT11_PLIC_11, 4U); PLIC_SetPriority(GPIO0_BIT12_or_GPIO2_BIT12_PLIC_12, 4U); PLIC_SetPriority(GPIO0_BIT13_or_GPIO2_BIT13_PLIC_13, 4U); PLIC_SetPriority(GPIO1_BIT0_or_GPIO2_BIT14_PLIC_14, 4U); PLIC_SetPriority(GPIO1_BIT1_or_GPIO2_BIT15_PLIC_15, 4U); PLIC_SetPriority(GPIO1_BIT2_or_GPIO2_BIT16_PLIC_16, 4U); PLIC_SetPriority(GPIO1_BIT3_or_GPIO2_BIT17_PLIC_17, 4U); PLIC_SetPriority(GPIO1_BIT4_or_GPIO2_BIT18_PLIC_18, 4U); PLIC_SetPriority(GPIO1_BIT5_or_GPIO2_BIT19_PLIC_19, 4U); MSS_GPIO_init(GPIO2_LO); MSS_GPIO_config_all(GPIO2_LO, MSS_GPIO_OUTPUT_MODE); MSS_GPIO_set_outputs(GPIO2_LO, 0x00000UL); /* bits 15:0 - 0, noise logic disabled */ delay(DELAY_CYCLES_5_MICRO); /*MSS_GPIO_set_outputs(GPIO2_LO, 0x00FFFUL);*/ /* bits 12:0 - 1, 56% enabled */ noise_ena = (1 << num_of_noise_blocks_en) - 1; MSS_GPIO_set_outputs(GPIO2_LO, noise_ena); /* num_of_noise_blocks_en * 4.72% */ fabric_noise_en = 0; } #endif /* FABRIC_NOISE_TEST */ write_latency = DDR_CAL_MIN_LATENCY; ddr_training_state = DDR_TRAINING_SET_MODE_VS_BITS; } break; case DDR_TRAINING_SET_MODE_VS_BITS: #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r dpc_bits: ",\ dpc_bits); #endif /* * Set the training mode */ set_ddr_mode_reg_and_vs_bits(dpc_bits); if (ddr_type == LPDDR4) { /* vrgen, modify during write leveling, turns off ODT */ CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ (dpc_bits & ~DDR_DPC_VRGEN_H_MASK)| (DPC_VRGEN_H_LPDDR4_WR_LVL_VAL << DDR_DPC_VRGEN_H_SHIFT); CFG_DDR_SGMII_PHY->rpc3_ODT.rpc3_ODT = 0x0; } else if ((ddr_type == DDR3)||(ddr_type == DDR3L)) { /* vrgen, modify during write leveling */ CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS = dpc_bits | (DPC_VRGEN_H_DDR3_WR_LVL_VAL< mss_boot -> re-flash nv_map -> override * any changes (to fix issues) * * SOFT_RESET_ bit 0 == periph soft reset, auto cleared */ CFG_DDR_SGMII_PHY->SOFT_RESET_DECODER_DRIVER.SOFT_RESET_DECODER_DRIVER = 1U; CFG_DDR_SGMII_PHY->SOFT_RESET_DECODER_ODT.SOFT_RESET_DECODER_ODT=1U; CFG_DDR_SGMII_PHY->SOFT_RESET_DECODER_IO.SOFT_RESET_DECODER_IO = 1U; ddr_training_state = DDR_TRAINING_CORRECT_RPC; break; case DDR_TRAINING_CORRECT_RPC: /* * correct some rpc registers, which were incorrectly set in mode * setting */ set_ddr_rpc_regs(ddr_type); ddr_training_state = DDR_TRAINING_SOFT_RESET; break; case DDR_TRAINING_SOFT_RESET: /* * Set soft reset on IP to load RPC to SCB regs (dynamic mode) * Bring the DDR bank controller out of reset */ IOSCB_BANKCONT_DDR->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ ddr_training_state = DDR_TRAINING_CALIBRATE_IO; break; case DDR_TRAINING_CALIBRATE_IO: /* * Calibrate DDR I/O here, once all RPC settings correct */ ddr_pvt_calibration(); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r PCODE = ",\ (CFG_DDR_SGMII_PHY->IOC_REG2.IOC_REG2 & 0x7FU)); (void)uprint32(g_debug_uart, "\n\r NCODE = ", \ (((CFG_DDR_SGMII_PHY->IOC_REG2.IOC_REG2) >> 7U) & 0x7FU)); (void)uprint32(g_debug_uart, "\n\r addr_cmd_value: ",\ addr_cmd_value); (void)uprint32(g_debug_uart, "\n\r bclk_sclk_offset_value: ",\ bclk_sclk_offset_value); (void)uprint32(g_debug_uart, "\n\r dpc_vrgen_v_value: ",\ dpc_vrgen_v_value); (void)uprint32(g_debug_uart, "\n\r dpc_vrgen_h_value: ",\ dpc_vrgen_h_value); (void)uprint32(g_debug_uart, "\n\r dpc_vrgen_vs_value: ",\ dpc_vrgen_vs_value); #endif ddr_training_state = DDR_TRAINING_CONFIG_PLL; break; case DDR_TRAINING_CONFIG_PLL: /* * Configure the DDR PLL */ ddr_pll_config(SCB_UPDATE); timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_VERIFY_PLL_LOCK; break; case DDR_TRAINING_VERIFY_PLL_LOCK: /* * Verify DDR PLL lock */ if (ddr_pll_lock_scb() == 0U) { ddr_training_state = DDR_TRAINING_SETUP_SEGS; } else if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_PLL_LOCK; } break; case DDR_TRAINING_SETUP_SEGS: /* * Configure Segments- address mapping, CFG0/CFG1 */ setup_ddr_segments(DEFAULT_SEG_SETUP); /* * enable the DDRC */ /* Turn on DDRC clock */ SYSREG->SUBBLK_CLOCK_CR |= SUBBLK_CLOCK_CR_DDRC_MASK; /* Remove soft reset */ SYSREG->SOFT_RESET_CR |= (uint32_t)SOFT_RESET_CR_DDRC_MASK; SYSREG->SOFT_RESET_CR &= (uint32_t)~SOFT_RESET_CR_DDRC_MASK; ddr_training_state = DDR_TRAINING_SETUP_DDRC; break; case DDR_TRAINING_SETUP_DDRC: /* * set-up DDRC * Configuration taken from the user. */ { init_ddrc(); ddr_training_state = DDR_TRAINING_RESET; } break; case DDR_TRAINING_RESET: /* * Assert training reset * reset pin is bit [1] * and load skip setting */ /* leave in reset */ /* To verify if separate reset required for DDR4 - believe it is not */ #ifndef SPECIAL_TRAINIG_RESET CFG_DDR_SGMII_PHY->training_reset.training_reset = 0x00000002U; #ifndef SOFT_RESET_PRE_TAG_172 if (ddr_type == LPDDR4) { //ALISTER 7/16/21 DDRCFG->MC_BASE2.INIT_AUTOINIT_DISABLE.INIT_AUTOINIT_DISABLE=0x1; } DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N =\ 0x00000000U; DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N =\ 0x00000001U; #endif /* !SOFT_RESET_PRE_TAG_172 */ #else /* Disable CKE */ DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; /* Assert FORCE_RESET */ DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x1; delay(DELAY_CYCLES_5_MICRO); /* release reset to memory here, set INIT_FORCE_RESET to 0 */ DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x0; delay(DELAY_CYCLES_2MS); /* 2MS */ /* Enable CKE */ DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x0; delay(DELAY_CYCLES_50_MICRO); /* reset pin is bit [1] */ CFG_DDR_SGMII_PHY->training_reset.training_reset = 0x00000002U; #endif ddr_training_state = DDR_TRAINING_ROTATE_CLK; break; case DDR_TRAINING_ROTATE_CLK: /* * Rotate bclk90 by 90 deg */ CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt = 0x00000004U; /*expert mode enabling */ CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000002U; /* */ CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x7CU; /* loading */ CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x78U; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x78U; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x7CU; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x4U; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x64U; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x66U; /* increment */ for (uint32_t d=0;d< \ LIBERO_SETTING_TIP_CONFIG_PARAMS_BCLK_VCOPHS_OFFSET;d++) { CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x67U; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x66U; } CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x64U; CFG_DDR_SGMII_PHY->expert_pllcnt.expert_pllcnt= 0x4U; /* setting load delay lines */ CFG_DDR_SGMII_PHY->expert_dlycnt_mv_rd_dly_reg.expert_dlycnt_mv_rd_dly_reg\ = 0x1FU; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0xFFFFFFFFU; /* setting to 1 to load delaylines */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0x00000000U; /* write w DFICFG_REG mv_rd_dly 0x00000000 # tip_apb_write(12'h89C, 32'h0); mv_rd_dly */ CFG_DDR_SGMII_PHY->expert_dlycnt_mv_rd_dly_reg.expert_dlycnt_mv_rd_dly_reg \ = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0xFFFFFFFFU; /* setting to 1 to load delaylines */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0x00000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x0000003FU; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x00000000U; /* DQ */ /* dfi_training_complete_shim = 1'b1 dfi_wrlvl_en_shim = 1'b1 */ CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x6; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0=\ 0xFFFFFFFFU; /* load output delays */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0xF; /* (ECC) - load output delays */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0=\ 0x0; /* clear */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0x0; /* (ECC) clear */ /* DQS * dfi_wrlvl_en_shim = 1'b1 */ CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x4; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0=\ 0xFFFFFFFFU; /* load output delays */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0xF; /* (ECC) - load output delays */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0=\ 0x0; /* clear */ CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1=\ 0x0; /* (ECC) clear */ CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x0; /* clear */ CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x0000003FU; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x00000000U; /* expert mode disabling */ CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en =\ 0x00000000U; ddr_training_state = DDR_TRAINING_SET_TRAINING_PARAMETERS; break; case DDR_TRAINING_SET_TRAINING_PARAMETERS: /* * SET TRAINING PARAMETERS * * TIP STATIC PARAMETERS 0 * * 30:22 Number of VCO Phase offsets between BCLK and SCLK * 21:13 Number of VCO Phase offsets between BCLK and SCLK * 12:6 Number of VCO Phase offsets between BCLK and SCLK * 5:3 Number of VCO Phase offsets between BCLK and SCLK * 2:0 Number of VCO Phase offsets between REFCLK and ADDCMD bits */ { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r tip_cfg_params: ",\ tip_cfg_params); #endif CFG_DDR_SGMII_PHY->tip_cfg_params.tip_cfg_params =\ tip_cfg_params; timeout = 0xFFFF; if(use_software_bclk_sclk_training(ddr_type) == 1U) { /* * Initiate software training */ #ifdef SOFT_RESET_PRE_TAG_172 DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N =\ 0x00000001U; #endif ddr_training_state = DDR_TRAINING_IP_SM_BCLKSCLK_SW; } else { /* * Initiate IP training and wait for dfi_init_complete */ /*asserting training_reset */ if (!((ddr_type == DDR3)||(ddr_type == DDR3L))) { CFG_DDR_SGMII_PHY->training_reset.training_reset =\ 0x00000000U; } else { DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N =\ 0x00000001U; } ddr_training_state = DDR_TRAINING_IP_SM_START; } } break; case DDR_TRAINING_IP_SM_BCLKSCLK_SW: /* * We have chosen to use software bclk sclk sweep instead of IP */ { uint32_t bclk_phase, bclk90_phase,refclk_phase; bclk_answer = 0U; { /* * BEGIN MANUAL BCLKSCLK TRAINING */ uint32_t rx_previous=0x3U; uint32_t rx_current=0U; uint32_t answer_count[8U]={0U,0U,0U,0U,0U,0U,0U,0U}; uint32_t answer_index=0U; /*UPPER LIMIT MUST BE MULTIPLE OF 8 */ for (uint32_t i=0U; i<(8U * 100); i++) { bclk_phase = ( i & 0x07UL ) << 8U; bclk90_phase = ((i+2U) & 0x07UL ) << 11U; /* * LOAD BCLK90 PHASE */ MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | bclk_phase | bclk90_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase); /* * No pause required, causes an issue */ /* * SAMPLE RX_BCLK */ rx_current = ((CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback) >> 12)& 0x03; /* IF WE FOUND A TRANSITION, BREAK THE LOOP */ if ((rx_current & (~rx_previous)) != 0x00000000UL) { answer_index=i&0x07U; /* increment the answer count for this index */ answer_count[answer_index]++; } rx_previous = rx_current; uint32_t max=0U; for (uint32_t j=0U;j<8U;j++) { /* sweep through found answers and select the most common */ if (answer_count[j] > max) { bclk_answer = j; max=answer_count[j]; } } } } ddr_training_state = DDR_MANUAL_ADDCMD_TRAINING_SW; break; case DDR_MANUAL_ADDCMD_TRAINING_SW: { /* * APPLY OFFSET & LOAD THE PHASE * bclk_sclk_offset_value * BCLK_SCLK_OFFSET_BASE */ { bclk_phase = ((bclk_answer+bclk_sclk_offset(ddr_type)) & 0x07UL ) << 8U; bclk90_phase=((bclk_answer+bclk_sclk_offset(ddr_type)+2U) & 0x07UL ) << 11U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | bclk_phase | bclk90_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase); } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r bclk_phase ", bclk_phase); (void)uprint32(g_debug_uart, "\n\r bclk_sclk_offset value ", bclk_sclk_offset(ddr_type)); #endif /* SET Store DRV & VREF initial values (to be re-applied after CA training) */ uint32_t ca_drv=CFG_DDR_SGMII_PHY->rpc1_DRV.rpc1_DRV; uint32_t ca_vref=(CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS >>12)&0x3F; /* SET DRIVE TO MAX */ { /* vref training begins */ uint32_t dpc_bits_new; uint32_t vref_answer; uint32_t transition_a5_min_last = 129U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000001U; for (uint32_t ca_indly=0;ca_indly < 30; ca_indly=ca_indly+5) { CFG_DDR_SGMII_PHY->rpc145.rpc145 = ca_indly;//TEMPORARY CFG_DDR_SGMII_PHY->rpc147.rpc147 = ca_indly;//TEMPORARY uint32_t break_loop=1; uint32_t in_window=0; vref_answer=128; for (uint32_t vref=5;vref <30;vref++) //begin vref training { uint32_t transition_a5_max=0; uint32_t transition_a5_min=128; uint32_t rx_a5_last,rx_a5; uint32_t transition_a5; uint32_t range_a5=0; if(transition_a5_min_last > 128U) { transition_a5_min_last=128U; } IOSCB_BANKCONT_DDR->soft_reset = 0U; /* DPC_BITS NV_MAP reset */ //SET VREF HERE delay(DELAY_CYCLES_500_NS); dpc_bits_new=( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (vref <<12) | (0x1<<18); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS=dpc_bits_new; delay(DELAY_CYCLES_500_NS); IOSCB_BANKCONT_DDR->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ delay(DELAY_CYCLES_500_NS); //ADDCMD Training improvement , adds delay on A9 loopback path - Suggested by Alister //CFG_DDR_SGMII_PHY->rpc145.rpc145 = 0x8U; uint32_t deltat = 128UL; for (uint32_t j = 0; j<20 ; j++) { //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; // rx_a5_last=0x0; rx_a5_last=0xF; transition_a5=0; deltat=128; delay(DELAY_CYCLES_500_NS); for (uint32_t i=0; i < (128-ca_indly);i++) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; delay(DELAY_CYCLES_500_NS); rx_a5 = (CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x0300) >> 8; if (transition_a5 != 0){ if (((i - transition_a5) > 8) ){ //was 8 //////////// break; } } if (transition_a5 ==0) { // if ( ((rx_a5 ^ rx_a5_last) & (~rx_a5) ) ){ if ( ((rx_a5 ^ rx_a5_last) & rx_a5 ) ){ transition_a5 = i; } else{ rx_a5_last=rx_a5; } } else { if ((i - transition_a5) == 4) //was 4 //////////// //if (rx_a5!=rx_a5_last) //IF rx_ca not stable after 4 increments, set transition detected to 0 (false transition) // if(!((rx_a5 ^ rx_a5_last) & (~rx_a5) )) if(!((rx_a5 ^ rx_a5_last) & rx_a5 )) { transition_a5=0; //Continue looking for transition rx_a5_last=rx_a5; } } }//delay loop ends here if (transition_a5 !=0) { if (transition_a5 > transition_a5_max) { transition_a5_max = transition_a5; } if (transition_a5 < transition_a5_min) { transition_a5_min = transition_a5; } } }//Sample loop ends here range_a5=transition_a5_max-transition_a5_min; if (transition_a5_min < 10){ break_loop=0; } if (range_a5 <=5) { //(min(transition_a5_min - transition_a5_min_last,transition_a5_min_last-transition_a5_min) <=4)) if (transition_a5_min > transition_a5_min_last) { deltat=transition_a5_min-transition_a5_min_last; } else { deltat=transition_a5_min_last-transition_a5_min; } if (deltat <=5) { in_window=(in_window<<1)|1; } } else { in_window=(in_window<<1)|0; } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r ca_indly ", ca_indly); (void)uprint32(g_debug_uart, " vref ", vref); (void)uprint32(g_debug_uart, " a5_dly_max:", transition_a5_max); (void)uprint32(g_debug_uart, " a5_dly_min:", transition_a5_min); (void)uprint32(g_debug_uart, " a5_dly_min_last:", transition_a5_min_last); (void)uprint32(g_debug_uart, " range_a5:", range_a5); (void)uprint32(g_debug_uart, " deltat:", deltat); (void)uprint32(g_debug_uart, " in_window:", in_window); (void)uprint32(g_debug_uart, " vref_answer:", vref_answer); #endif if(vref_answer==128) { if ((in_window &0x3)==0x3) //ALISTER CHANGE 2/17/2021 { vref_answer=vref; //ALISTER CHANGE #ifndef PRINT_CA_VREF_WINDOW break; #endif } } transition_a5_min_last=transition_a5_min; } if (break_loop) { break; } } #ifdef DEBUG_DDR_INIT if (vref_answer!=128U) { (void)uprint32(g_debug_uart, "\n\r vref_answer found", vref_answer); } else { (void)uprint32(g_debug_uart, "\n\r CA_VREF training failed! ", vref_answer); } #endif IOSCB_BANKCONT_DDR->soft_reset = 0U; /* DPC_BITS NV_MAP reset */ /* SET VREF HERE */ delay(DELAY_CYCLES_500_NS); if(vref_answer == 128U) { vref_answer = 0x10U; dpc_bits_new=( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (vref_answer <<12U) | (0x1<<18U); } else { //vref_answer = vref_answer; dpc_bits_new=( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (vref_answer <<12) | (0x1<<18U); } CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS=dpc_bits_new; delay(DELAY_CYCLES_500_NS); IOSCB_BANKCONT_DDR->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ delay(DELAY_CYCLES_500_MICRO); }/* end vref_training; */ if ((ddr_type == DDR3)||(ddr_type == DDR3L)) { ddr3_address_cmd_training(ddr_type, &refclk_sweep_index, retry_count, &bclk_phase, &bclk90_phase, &refclk_phase, &refclk_offset ); } else if (ddr_type != LPDDR4) { non_lpddr4_address_cmd_training(ddr_type, &refclk_sweep_index, &bclk_phase, &bclk90_phase, &refclk_phase); } /* END MANUAL BCLKSCLK TRAINING */ else /* LPDDR4 */ { /* PRE_INITIALIZATION when using LPDDR4 */ refclk_phase =(0x7U)<<2U; bclk_phase=MSS_SCB_DDR_PLL->PLL_PHADJ & 0x700; bclk90_phase=MSS_SCB_DDR_PLL->PLL_PHADJ & 0x3800; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase | refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | bclk_phase | bclk90_phase | refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase | refclk_phase); delay(DELAY_CYCLES_500_NS); } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r Returning FPGA CA VREF & CA drive to user setting.\n\r ", 0x0); #endif /* SET VREF BACK TO CONFIGURED VALUE */ IOSCB_BANKCONT_DDR->soft_reset = 0U; /* DPC_BITS NV_MAP reset */ delay(DELAY_CYCLES_500_NS); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS=\ ( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (ca_vref <<12U) | (0x1<<18U); delay(DELAY_CYCLES_500_NS); IOSCB_BANKCONT_DDR->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ delay(DELAY_CYCLES_500_NS); /* SET CA DRV BACK TO CONFIGURED VALUE */ CFG_DDR_SGMII_PHY->rpc1_DRV.rpc1_DRV=ca_drv; //return ca_drv to original value ddr_training_state = DDR_TRAINING_IP_SM_START; } } if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_BCLKSCLK_SW; } break; case DDR_TRAINING_IP_SM_START: { CFG_DDR_SGMII_PHY->training_skip.training_skip =\ LIBERO_SETTING_TRAINING_SKIP_SETTING; if ((ddr_type == DDR3)||(ddr_type == DDR3L)||(ddr_type == LPDDR3)||(ddr_type == LPDDR4)||(ddr_type == DDR4)) { /* RX_MD_CLKN */ CFG_DDR_SGMII_PHY->rpc168.rpc168 = 0x0U; } #ifdef DDR_TRAINING_IP_SM_START_DELAY delay(DELAY_CYCLES_5_MICRO); #endif /* release reset to training */ CFG_DDR_SGMII_PHY->training_reset.training_reset = 0x00000000U; #ifdef IP_SM_START_TRAINING_PAUSE CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0xffU; delay(DELAY_CYCLES_5_MICRO); CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause = 0x00000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause = 0x0000003FU; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause = 0x00000000U; delay(DELAY_CYCLES_5_MICRO); CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00U; delay(DELAY_CYCLES_5_MICRO); #endif } { DDRCFG->DFI.PHY_DFI_INIT_START.PHY_DFI_INIT_START =\ 0x00000000U; /* kick off training- DDRC, set dfi_init_start */ DDRCFG->DFI.PHY_DFI_INIT_START.PHY_DFI_INIT_START =\ 0x00000001U; DDRCFG->MC_BASE2.CTRLR_INIT.CTRLR_INIT = 0x00000000U; DDRCFG->MC_BASE2.CTRLR_INIT.CTRLR_INIT = 0x00000001U; timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_START_CHECK; } #ifdef DEBUG_DDR_INIT #ifdef MANUAL_ADDCMD_TRAINIG (void)uprint32(g_debug_uart, "\n\r\n\r ADDCMD_OFFSET ", refclk_offset); #endif #endif break; case DDR_TRAINING_IP_SM_START_CHECK: #ifndef RENODE_DEBUG if((DDRCFG->DFI.STAT_DFI_INIT_COMPLETE.STAT_DFI_INIT_COMPLETE\ & 0x01U) == 0x01U) #endif { #ifdef LANE_ALIGNMENT_RESET_REQUIRED CFG_DDR_SGMII_PHY->lane_alignment_fifo_control.lane_alignment_fifo_control = 0x00U; CFG_DDR_SGMII_PHY->lane_alignment_fifo_control.lane_alignment_fifo_control = 0x02U; #endif if(ddr_type == LPDDR4) { lpddr4_manual_training(ddr_type, &refclk_sweep_index, retry_count, &refclk_offset); } /* end of LPDDR4 exclusive */ #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r\n\r pll_phadj_after_hw_training ",\ MSS_SCB_DDR_PLL->PLL_DIV_2_3); (void)uprint32(g_debug_uart, \ "\n\r\n\r pll_phadj_after_hw_training ",\ MSS_SCB_DDR_PLL->PLL_DIV_0_1); #endif if(LIBERO_SETTING_TRAINING_SKIP_SETTING & BCLK_SCLK_BIT) { ddr_training_state = DDR_TRAINING_IP_SM_ADDCMD; } else { ddr_training_state = DDR_TRAINING_IP_SM_BCLKSCLK; } timeout = 0xFFFF; } if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_START_CHECK; } break; case DDR_TRAINING_IP_SM_BCLKSCLK: if(CFG_DDR_SGMII_PHY->training_status.training_status & BCLK_SCLK_BIT) { timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_ADDCMD; } if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_SM_BCLKSCLK; } break; case DDR_TRAINING_IP_SM_ADDCMD: if(LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) { timeout = 0xFFFFF; ddr_training_state = DDR_TRAINING_IP_SM_WRLVL; } else if(CFG_DDR_SGMII_PHY->training_status.training_status & ADDCMD_BIT) { timeout = 0xFFFFF; ddr_training_state = DDR_TRAINING_IP_SM_WRLVL; } if(--timeout == 0U) { /* * Typically this can fail for two * reasons: * 1. ADD/CMD not being received * We need to sweep: * ADDCMD_OFFSET [0:3] RW value * sweep-> 0x2 -> 4 -> C -> 0 * 2. DQ not received * We need to sweep: * LIBERO_SETTING_DPC_BITS * DPC_VRGEN_H [4:6] value= 0x8->0xC * * */ ddr_training_state = DDR_TRAINING_FAIL_SM_ADDCMD; } break; case DDR_TRAINING_IP_SM_WRLVL: //END VREFTRN if(LIBERO_SETTING_TRAINING_SKIP_SETTING & WRLVL_BIT) { timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_RDGATE; } else if(CFG_DDR_SGMII_PHY->training_status.training_status & WRLVL_BIT) { timeout = 0xFFFFF; ddr_training_state = DDR_TRAINING_IP_SM_RDGATE; } if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_SM_WRLVL; } break; case DDR_TRAINING_IP_SM_RDGATE: /* vrgen, revert temp change during write leveling for lpddr4, turn back on ODT */ CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS = dpc_bits ; CFG_DDR_SGMII_PHY->rpc3_ODT.rpc3_ODT = LIBERO_SETTING_RPC_ODT_DQ; /* end addition 11th Feb 22 */ if(LIBERO_SETTING_TRAINING_SKIP_SETTING & RDGATE_BIT) { timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_DQ_DQS; } else if(CFG_DDR_SGMII_PHY->training_status.training_status & RDGATE_BIT) { timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_DQ_DQS; } if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_SM_RDGATE; } break; case DDR_TRAINING_IP_SM_DQ_DQS: if(LIBERO_SETTING_TRAINING_SKIP_SETTING & DQ_DQS_BIT) { timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_VERIFY; } else if(CFG_DDR_SGMII_PHY->training_status.training_status & DQ_DQS_BIT) { timeout = 0xFFFF; ddr_training_state = DDR_TRAINING_IP_SM_VERIFY; } if(--timeout == 0U) { ddr_training_state = DDR_TRAINING_FAIL_SM_DQ_DQS; } break; case DDR_TRAINING_IP_SM_VERIFY: if ((DDRCFG->DFI.STAT_DFI_TRAINING_COMPLETE.STAT_DFI_TRAINING_COMPLETE & 0x01U) == 0x01U) { /* * Step 15: * check worked for each lane */ uint32_t lane_sel, t_status = 0U; for (lane_sel=0U; lane_sel< \ LIBERO_SETTING_DATA_LANES_USED; lane_sel++) { SIM_FEEDBACK1(1000U); delay(10U); SIM_FEEDBACK1(1001U); CFG_DDR_SGMII_PHY->lane_select.lane_select =\ lane_sel; delay(10U); /* * verify cmd address results * rejects if not acceptable * */ { uint32_t ca_status[8]= {\ ((CFG_DDR_SGMII_PHY->addcmd_status0.addcmd_status0)&0xFFU),\ ((CFG_DDR_SGMII_PHY->addcmd_status0.addcmd_status0>>8U)&0xFFU), \ ((CFG_DDR_SGMII_PHY->addcmd_status0.addcmd_status0>>16U)&0xFFU),\ ((CFG_DDR_SGMII_PHY->addcmd_status0.addcmd_status0>>24U)&0xFFU),\ ((CFG_DDR_SGMII_PHY->addcmd_status1.addcmd_status1)&0xFFU),\ ((CFG_DDR_SGMII_PHY->addcmd_status1.addcmd_status1>>8U)&0xFFU),\ ((CFG_DDR_SGMII_PHY->addcmd_status1.addcmd_status1>>16U)&0xFFU),\ ((CFG_DDR_SGMII_PHY->addcmd_status1.addcmd_status1>>24U)&0xFFU)}; uint32_t low_ca_dly_count = 0U; uint32_t last = 0U; uint32_t decrease_count = 0U; for(uint32_t i =0U; i<8U;i++) { if(ca_status[i] < 5U) { low_ca_dly_count++; } if(ca_status[i]<=last) { decrease_count++; } last = ca_status[i]; } if(ca_status[0]<= ca_status[7U]) { decrease_count++; } if((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) != ADDCMD_BIT) { /* Retrain if abnormal CA training result detected */ if(low_ca_dly_count > ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT) { t_status = t_status | 0x01U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT : ",\ low_ca_dly_count); #endif } /* Retrain if abnormal CA training result detected */ if(decrease_count > ABNORMAL_RETRAIN_CA_DECREASE_COUNT) { t_status = t_status | 0x02U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL ABNORMAL_RETRAIN_CA_DECREASE_COUNT : ",\ decrease_count); #endif } } } /* Check that gate training passed without error */ t_status = t_status |\ CFG_DDR_SGMII_PHY->gt_err_comb.gt_err_comb; delay(10U); /* Check that DQ/DQS training passed without error */ if(CFG_DDR_SGMII_PHY->dq_dqs_err_done.dq_dqs_err_done != 8U) { t_status = t_status | 0x01U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL dq_dqs_err_done : ",\ CFG_DDR_SGMII_PHY->dq_dqs_err_done.dq_dqs_err_done); #endif } /* Check that DQ/DQS calculated window is above 5 taps. */ if(CFG_DDR_SGMII_PHY->dqdqs_status2.dqdqs_status2 < \ DQ_DQS_NUM_TAPS) { t_status = t_status | 0x01U; /* * Increment startin value to push past starting edge */ #ifdef TUNE_RPC_156_DQDQS_INIT_VALUE if (rpc_156_dqdqs_init_offset <= LIBERO_SETTING_MAX_RPC_156_VALUE) { rpc_156_dqdqs_init_offset++; } #endif #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r\n\r Filtering failures DQDQS Windows is too small ",CFG_DDR_SGMII_PHY->dqdqs_status2.dqdqs_status2); #ifdef TUNE_RPC_156_DQDQS_INIT_VALUE (void)uprint32(g_debug_uart, \ "\n\r\n\r rpc_156_dqdqs_init_offset = ",rpc_156_dqdqs_init_offset); #endif #endif } #define DCT_EXTRA_CHECKS #ifdef DCT_EXTRA_CHECKS uint32_t temp = 0U, gt_clk_sel = (CFG_DDR_SGMII_PHY->gt_clk_sel.gt_clk_sel & 3U); if(((CFG_DDR_SGMII_PHY->gt_txdly.gt_txdly)&0xFFU) == 0U) // Gate training tx_dly check: AL { temp++; if(gt_clk_sel == 0) { t_status = t_status | 0x01U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL gt_clk_sel : ",\ gt_clk_sel); #endif } } if(((CFG_DDR_SGMII_PHY->gt_txdly.gt_txdly>>8U)&0xFFU) == 0U) { temp++; if(gt_clk_sel == 1) { t_status = t_status | 0x01U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL gt_clk_sel : ",\ gt_clk_sel); #endif } } if(((CFG_DDR_SGMII_PHY->gt_txdly.gt_txdly>>16U)&0xFFU) == 0U) { temp++; if(gt_clk_sel == 2) { t_status = t_status | 0x01U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL gt_clk_sel : ",\ gt_clk_sel); #endif } } if(((CFG_DDR_SGMII_PHY->gt_txdly.gt_txdly>>24U)&0xFFU) == 0U) { temp++; if(gt_clk_sel == 3) { t_status = t_status | 0x01U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r SM_VERIFY FAIL gt_clk_sel : ",\ gt_clk_sel); #endif } } if(temp > 1) { t_status = t_status | 0x01U; } #endif } #ifdef RENODE_DEBUG t_status = 0U; /* Dummy success -move on to next stage */ #endif if(t_status == 0U) { SIM_FEEDBACK1(21U); /* * We can now set vref on the memory * mode register for lpddr4 * May include other modes, and include a sweep * Alister looking into this and will revert. */ if (ddr_type == LPDDR4) { #ifdef SET_VREF_LPDDR4_MODE_REGS mode_register_write(DDR_MODE_REG_VREF,\ DDR_MODE_REG_VREF_VALUE); #endif } ddr_training_state = DDR_TRAINING_SET_FINAL_MODE; } else /* fail, try again */ { SIM_FEEDBACK1(20U); ddr_training_state = DDR_TRAINING_FAIL_SM_VERIFY; } } else { ddr_training_state = DDR_TRAINING_FAIL_SM2_VERIFY; } break; case DDR_TRAINING_SET_FINAL_MODE: /* * Set final mode register value. */ CFG_DDR_SGMII_PHY->DDRPHY_MODE.DDRPHY_MODE =\ LIBERO_SETTING_DDRPHY_MODE; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r DDR FINAL_MODE: ",\ LIBERO_SETTING_DDRPHY_MODE); #ifdef DEBUG_DDR_CFG_DDR_SGMII_PHY (void)print_reg_array(g_debug_uart , (uint32_t *)CFG_DDR_SGMII_PHY,\ (sizeof(CFG_DDR_SGMII_PHY_TypeDef)/4U)); #endif #ifdef DEBUG_DDR_DDRCFG debug_read_ddrcfg(); #endif #endif #ifdef DEBUG_DDR_INIT { tip_register_status (g_debug_uart); (void)uprint32(g_debug_uart, "\n\r ****************************************************", 0U); } #endif ddr_training_state = DDR_TRAINING_WRITE_CALIBRATION; break; case DDR_TRAINING_WRITE_CALIBRATION: /* * Does the following in the DDRC need to be checked?? * DDRCFG->DFI.STAT_DFI_TRAINING_COMPLETE.STAT_DFI_TRAINING_COMPLETE; * */ number_of_lanes_to_calibrate = get_num_lanes(); /* * Now start the write calibration as training has been successful */ /* Setting expert mode */ CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x0000008U; if(error == 0U) { if((ddr_type == DDR3)||(ddr_type == DDR3L)) /* Changing WPU and WPD */ { /* only run when ECC is on - sar121393 */ if (LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_ECC_MASK) { CFG_DDR_SGMII_PHY->ovrt16.ovrt16 = 0x00000F80UL; CFG_DDR_SGMII_PHY->ovrt15.ovrt15 = 0x00000000UL; CFG_DDR_SGMII_PHY->ovrt14.ovrt14 = 0x00000000UL; CFG_DDR_SGMII_PHY->ovrt13.ovrt13 = 0x00000000UL; CFG_DDR_SGMII_PHY->ovrt12.ovrt12 = 0x00000000UL; } } if (ddr_type == LPDDR4) { #ifdef SWEEP_DQ_DELAY uint8_t lane; uint32_t dly_firstpass=0xFF; uint32_t dly_right_edge=20U; uint32_t pass=0U; for(lane = 0U; lane < number_of_lanes_to_calibrate; lane++) //load DQ { load_dq(lane); } delay(DELAY_CYCLES_50_MICRO); for (uint32_t dq_dly=0U;dq_dly < 20U ; dq_dly=dq_dly+1U){ CFG_DDR_SGMII_PHY->rpc220.rpc220 = dq_dly; //set DQ load value for(lane = 0U; lane < number_of_lanes_to_calibrate; lane++) //load DQ { load_dq(lane); } SIM_FEEDBACK1(1U); delay(DELAY_CYCLES_50_MICRO); pass =\ write_calibration_using_mtc(\ number_of_lanes_to_calibrate); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r dq_dly ",\ dq_dly); (void)uprint32(g_debug_uart, " pass ",\ pass); (void)uprint32(g_debug_uart, " wr calib result ",\ calib_data.write_cal.lane_calib_result); #endif if (dly_firstpass != 0xFFU) { if (pass !=0U) { dly_right_edge=dq_dly; break; } } if (dly_firstpass ==0xFFU) { if (pass==0U) { dly_firstpass=dq_dly; } } } if(dly_firstpass == 0xFFU) { error = 1U; } else { CFG_DDR_SGMII_PHY->rpc220.rpc220 = (dly_firstpass + dly_right_edge)/2U; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r dq_dly_answer ",\ CFG_DDR_SGMII_PHY->rpc220.rpc220); //(void)uprint32(g_debug_uart, " vrefdq_answer ", (vref_firstpass + vref_right_edge)/2); (void)uprint32(g_debug_uart, " wr calib result ",\ calib_data.write_cal.lane_calib_result); #endif for(lane = 0U; lane < number_of_lanes_to_calibrate; lane++) //load DQ { load_dq(lane); } delay(DELAY_CYCLES_50_MICRO); error =\ write_calibration_using_mtc(\ number_of_lanes_to_calibrate); } #else /* alternate calibration */ if(ddr_type == LPDDR4) { uint8_t lane; /* Changed default value to centre dq/dqs on window */ CFG_DDR_SGMII_PHY->rpc220.rpc220 = 0xCUL; for(lane = 0U; lane < number_of_lanes_to_calibrate; lane++) { load_dq(lane); } } error = write_calibration_using_mtc(number_of_lanes_to_calibrate); #endif /* end of alternate calibration */ } else { SIM_FEEDBACK1(2U); error =\ write_calibration_using_mtc(number_of_lanes_to_calibrate); } if(error) { ddr_error_count++; SIM_FEEDBACK1(106U); } } if(error == 0U) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r wr calib result ",\ calib_data.write_cal.lane_calib_result); #endif ddr_training_state = DDR_SWEEP_CHECK; } else if(error == MTC_TIMEOUT_ERROR) { error = 0U; ddr_training_state = DDR_TRAINING_FAIL_DDR_SANITY_CHECKS; } else { error = 0U; ddr_training_state = DDR_TRAINING_WRITE_CALIBRATION_RETRY; } break; case DDR_TRAINING_WRITE_CALIBRATION_RETRY: /* * Clear write calibration data */ memfill((uint8_t *)&calib_data,0U,sizeof(calib_data)); /* * Try the next offset */ write_latency = DDRCFG->DFI.CFG_DFI_T_PHY_WRLAT.CFG_DFI_T_PHY_WRLAT; write_latency++; if (write_latency > DDR_CAL_MAX_LATENCY) { write_latency = DDR_CAL_MIN_LATENCY; ddr_training_state = DDR_TRAINING_FAIL_MIN_LATENCY; } else { DDRCFG->DFI.CFG_DFI_T_PHY_WRLAT.CFG_DFI_T_PHY_WRLAT =\ write_latency; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r wr write latency ",\ write_latency); #endif ddr_training_state = DDR_TRAINING_WRITE_CALIBRATION; } break; case DDR_SWEEP_CHECK: ddr_training_state = DDR_SANITY_CHECKS; break; case DDR_SANITY_CHECKS: /* * Now start the write calibration if training successful */ #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r DDR SANITY_CHECKS: ",\ error); #endif if(error == 0U) { #ifdef DDR_SANITY_CHECKS_EN error = memory_tests(); #endif } if(error == 0U) { ddr_training_state = DDR_FULL_MTC_CHECK; } else { ddr_training_state = DDR_TRAINING_FAIL_DDR_SANITY_CHECKS; } break; case DDR_FULL_MTC_CHECK: { uint64_t start_address = 0x0000000000000000ULL; uint32_t size = ONE_MB_MTC; /* Number of reads for each iteration 2**size*/ uint8_t mask; if (get_num_lanes() <= 3U) { mask = 0x3U; } else { mask = 0xFU; } error = MTC_test(mask, start_address, size, MTC_COUNTING_PATTERN, MTC_ADD_SEQUENTIAL, &error); /* Read using different patterns */ error = 0U; error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM, MTC_ADD_SEQUENTIAL, &error); #if ((LIBERO_FAST_START & 0x02) == 0U) error |= MTC_test(mask, start_address, size, MTC_COUNTING_PATTERN, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_WALKING_ONE, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_NO_REPEATING_PSEUDO_RANDOM, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_ALT_ONES_ZEROS, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_ALT_5_A, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM_16BIT, MTC_ADD_SEQUENTIAL, &error); error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM_8BIT, MTC_ADD_SEQUENTIAL, &error); #endif #if ((LIBERO_FAST_START & 0x01) == 0U) error |= MTC_test(mask, start_address, size, MTC_COUNTING_PATTERN, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_WALKING_ONE, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_NO_REPEATING_PSEUDO_RANDOM, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_ALT_ONES_ZEROS, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_ALT_5_A, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM_16BIT, MTC_ADD_RANDOM, &error); error |= MTC_test(mask, start_address, size, MTC_PSEUDO_RANDOM_8BIT, MTC_ADD_RANDOM, &error); #endif } if(error == 0U) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r Passed MTC full check ", error); #endif ddr_training_state = DDR_FULL_32BIT_NC_CHECK; } else { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r Failed MTC full check ", error); #endif ddr_training_state = DDR_TRAINING_FAIL; } break; case DDR_FULL_32BIT_NC_CHECK: /* * write and read back test from drr, non cached access */ { #if (DDR_FULL_32BIT_NC_CHECK_EN == 1) #if ((LIBERO_FAST_START & 0x08) == 0U) error = ddr_read_write_fn((uint64_t*)LIBERO_SETTING_DDR_32_NON_CACHE,\ SW_CFG_NUM_READS_WRITES,\ SW_CONFIG_PATTERN); #else error = ddr_read_write_fn((uint64_t*)LIBERO_SETTING_DDR_32_NON_CACHE,\ SW_CFG_NUM_READS_WRITES_FAST_START,\ SW_CONFIG_PATTERN_FAST_START); #endif #endif } if(error == 0U) { ddr_training_state = DDR_FULL_32BIT_CACHE_CHECK; } else { ddr_training_state = DDR_TRAINING_FAIL_FULL_32BIT_NC_CHECK; } break; case DDR_FULL_32BIT_CACHE_CHECK: #if (DDR_FULL_32BIT_CACHED_CHECK_EN == 1) error = ddr_read_write_fn((uint64_t*)LIBERO_SETTING_DDR_32_CACHE,\ SW_CFG_NUM_READS_WRITES,\ SW_CONFIG_PATTERN); #endif if(error == 0U) { #ifdef SKIP_VERIFY_PATTERN_IN_CACHE ddr_training_state = DDR_FULL_32BIT_WRC_CHECK; #else ddr_training_state = DDR_LOAD_PATTERN_TO_CACHE; #endif } else { ddr_training_state = DDR_TRAINING_FAIL_32BIT_CACHE_CHECK; } break; case DDR_LOAD_PATTERN_TO_CACHE: load_ddr_pattern(LIBERO_SETTING_DDR_32_CACHE, SIZE_OF_PATTERN_TEST*2, SIZE_OF_PATTERN_OFFSET); if(error == 0U) { ddr_training_state = DDR_VERIFY_PATTERN_IN_CACHE; } else { ddr_training_state = DDR_TRAINING_FAIL; } break; case DDR_VERIFY_PATTERN_IN_CACHE: error = test_ddr(NO_PATTERN_IN_CACHE_READS, SIZE_OF_PATTERN_TEST); #if ((LIBERO_FAST_START & 0x04) == 0U) error = error | test_ddr(NO_PATTERN_IN_CACHE_READS, SIZE_OF_PATTERN_TEST); error = error | test_ddr(NO_PATTERN_IN_CACHE_READS, SIZE_OF_PATTERN_TEST); #endif if(error == 0U) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r wr write latency ",\ DDRCFG->DFI.CFG_DFI_T_PHY_WRLAT.CFG_DFI_T_PHY_WRLAT); #if (TUNE_RPC_166_VALUE == 1) (void)uprint32(g_debug_uart, "\n\r rpc_166_fifo_offset: ",\ rpc_166_fifo_offset); #endif #endif ddr_training_state = DDR_FULL_32BIT_WRC_CHECK; } else { #if (TUNE_RPC_166_VALUE == 1) #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r rpc_166_fifo_offset: ",\ rpc_166_fifo_offset); #endif #ifdef NOT_A_FULL_RETRAIN /* this fails post tests */ if(num_rpc_166_retires < NUM_RPC_166_VALUES) { num_rpc_166_retires++; rpc_166_fifo_offset++; if(rpc_166_fifo_offset > MAX_RPC_166_VALUE) { rpc_166_fifo_offset = MIN_RPC_166_VALUE; } /* try again here DDR_LOAD_PATTERN_TO_CACHE */ } else { num_rpc_166_retires = 0U; rpc_166_fifo_offset = DEFAULT_RPC_166_VALUE; ddr_training_state = DDR_TRAINING_FAIL; } CFG_DDR_SGMII_PHY->rpc166.rpc166 = rpc_166_fifo_offset; /* PAUSE to reset fifo (loads new RXPTR value).*/ //CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x07U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x1U; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x0000003EU ; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x00000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x8U; delay(DELAY_CYCLES_50_MICRO); //END PAUSE #else if(num_rpc_166_retires < NUM_RPC_166_VALUES) { num_rpc_166_retires++; rpc_166_fifo_offset++; if(rpc_166_fifo_offset > MAX_RPC_166_VALUE) { rpc_166_fifo_offset = MIN_RPC_166_VALUE; } /* try again here DDR_LOAD_PATTERN_TO_CACHE */ } else { num_rpc_166_retires = 0U; rpc_166_fifo_offset = DEFAULT_RPC_166_VALUE; ddr_training_state = DDR_TRAINING_FAIL; } ddr_training_state = DDR_TRAINING_FAIL; #endif #else /* (TUNE_RPC_166_VALUE == 0) */ ddr_training_state = DDR_TRAINING_FAIL; #endif } break; case DDR_FULL_32BIT_WRC_CHECK: if(error == 0U) { ddr_training_state = DDR_FULL_64BIT_NC_CHECK; } else { ddr_training_state = DDR_TRAINING_FAIL; } break; case DDR_FULL_64BIT_NC_CHECK: if(error == 0U) { ddr_training_state = DDR_FULL_64BIT_CACHE_CHECK; } else { ddr_training_state = DDR_TRAINING_FAIL; } break; case DDR_FULL_64BIT_CACHE_CHECK: if(error == 0U) { ddr_training_state = DDR_FULL_64BIT_WRC_CHECK; } else { ddr_training_state = DDR_TRAINING_FAIL; } break; case DDR_FULL_64BIT_WRC_CHECK: if(error == 0U) { ddr_training_state = DDR_TRAINING_VREFDQ_CALIB; } else { ddr_training_state = DDR_TRAINING_FAIL; } break; case DDR_TRAINING_VREFDQ_CALIB: #ifdef VREFDQ_CALIB /* * This step is optional */ error = VREFDQ_calibration_using_mtc(); if(error != 0U) { ddr_error_count++; } #endif ddr_training_state = DDR_TRAINING_FPGA_VREFDQ_CALIB; break; case DDR_TRAINING_FPGA_VREFDQ_CALIB: #ifdef FPGA_VREFDQ_CALIB /* * This step is optional */ error = FPGA_VREFDQ_calibration_using_mtc(); if(error != 0U) { ddr_error_count++; } #endif ddr_training_state = DDR_TRAINING_FINISH_CHECK; break; case DDR_TRAINING_FINISH_CHECK: /* * return status */ ddr_diag.train_time = (uint64_t)(rdcycle() - training_start_cycle) / (LIBERO_SETTING_MSS_COREPLEX_CPU_CLK/1000); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r ddr train time (ms): ", (uint32_t)ddr_diag.train_time); (void)uprint32(g_debug_uart, "\n\r Number of retrains: ", ddr_diag.num_retrains); { tip_register_status (g_debug_uart); uprint(g_debug_uart, "\n\r\n\r DDR_TRAINING_PASS: "); #ifdef DEBUG_DDR_DDRCFG debug_read_ddrcfg(); #endif } #endif if(ddr_error_count > 0) { ret_status |= DDR_SETUP_FAIL; } else { /* * Configure Segments- address mapping, CFG0/CFG1 */ setup_ddr_segments(LIBERO_SEG_SETUP); } ret_status |= DDR_SETUP_DONE; ddr_training_state = DDR_TRAINING_FINISHED; break; default: case DDR_TRAINING_FINISHED: break; } /* end of case statement */ return (ret_status); } /** * get_num_lanes(void) * @return number of lanes used, 2(16 bit), 3(16 bit + ecc), 4(32 bit) or 5 * Note: Lane 4 always used when ECC enabled, even for x16 */ static uint8_t get_num_lanes(void) { uint8_t lanes; /* Check width, 16bit or 32bit bit supported, 1 => 32 bit */ if ((LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_BUS_WIDTH_MASK) ==\ DDRPHY_MODE_BUS_WIDTH_4_LANE) { lanes = 4U; } else { lanes = 2U; } /* Check if using ECC, add a lane */ if ((LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_ECC_MASK) ==\ DDRPHY_MODE_ECC_ON) { lanes++; } return lanes; } /***************************************************************************//** * set_ddr_mode_reg_and_vs_bits() * */ static void set_ddr_mode_reg_and_vs_bits(uint32_t dpc_bits) { DDR_TYPE ddr_type = LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_MASK; /* * R1.6 * Write DDR phy mode reg (eg DDR3) * When we write to the mode register, an ip state machine copies default * values for the particular mode chosen to RPC registers associated with * DDR in the MSS custom block. * ( Note: VS bits are not include in the copy so we set below ) * The RPC register values are transferred to the SCB registers in a * subsequent step. */ /* * Set VS bits * Select VS bits for DDR mode selected --- set dynamic pc bit settings to * allow editing of RPC registers * pvt calibration etc * * [19] dpc_move_en_v enable dynamic control of vrgen circuit for * ADDCMD pins * [18] dpc_vrgen_en_v enable vref generator for ADDCMD pins * [17:12] dpc_vrgen_v reference voltage ratio setting for ADDCMD * pins * [11:11] dpc_move_en_h enable dynamic control of vrgen circuit for * DQ/DQS pins * [10:10] dpc_vrgen_en_h enable vref generator for DQ/DQS pins * [9:4] dpc_vrgen_h reference voltage ratio setting for DQ/DQS * pins * [3:0] dpc_vs bank voltage select for pvt calibration */ /* DDRPHY_MODE setting from MSS configurator DDRMODE :3; ECC :1; CRC :1; Bus_width :3; DMI_DBI :1; DQ_drive :2; DQS_drive :2; ADD_CMD_drive :2; Clock_out_drive :2; DQ_termination :2; DQS_termination :2; ADD_CMD_input_pin_termination :2; preset_odt_clk :2; Power_down :1; rank :1; Command_Address_Pipe :2; */ { if ((ddr_type == DDR4) &&\ (LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_ECC_MASK) ==\ DDRPHY_MODE_ECC_ON) { /* * For ECC on when DDR4, and data mask on during training, training * will not pass * This will eventually be handled by the configurator * DM will not be allowed for DDR4 with ECC */ CFG_DDR_SGMII_PHY->DDRPHY_MODE.DDRPHY_MODE =\ (LIBERO_SETTING_DDRPHY_MODE & DMI_DBI_MASK ); } else { CFG_DDR_SGMII_PHY->DDRPHY_MODE.DDRPHY_MODE =\ LIBERO_SETTING_DDRPHY_MODE; } delay((uint32_t) 100U); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS = dpc_bits; } } /***************************************************************************//** * set_ddr_rpc_regs() * @param ddr_type */ static void set_ddr_rpc_regs(DDR_TYPE ddr_type) { /* * Write DDR phy mode reg (eg DDR3) * When we write to the mode register, an ip state machine copies default * values for the particular mode chossen * to RPC registers associated with DDR in the MSS custom block. * The RPC register values are transferred to the SCB registers in a * subsequent step. * * Question: * Select VS bits (eg DDR3 ) (vs bits not included in mode setup - should * be??) * Small wait while state machine transfer takes place required here. * (status bit required?) * */ /* DDRPHY_MODE setting from MSS configurator DDRMODE :3; ECC :1; CRC :1; Bus_width :3; DMI_DBI :1; DQ_drive :2; DQS_drive :2; ADD_CMD_drive :2; Clock_out_drive :2; DQ_termination :2; DQS_termination :2; ADD_CMD_input_pin_termination :2; preset_odt_clk :2; Power_down :1; rank :1; Command_Address_Pipe :2; */ { switch (ddr_type) { default: case DDR_OFF_MODE: /* Below have already been set */ /* CFG_DDR_SGMII_PHY->rpc95.rpc95 = 0x07; */ /* addcmd I/O*/ /* CFG_DDR_SGMII_PHY->rpc96.rpc96 = 0x07; */ /* clk */ /* CFG_DDR_SGMII_PHY->rpc97.rpc97 = 0x07; */ /* dq */ /* CFG_DDR_SGMII_PHY->rpc98.rpc98 = 0x07; */ /* dqs */ /* * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK */ CFG_DDR_SGMII_PHY->UNUSED_SPACE0[0] = 0x0U; break; case DDR3L: case DDR3: /* Required when rank x 2 */ if ((LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_RANK_MASK) ==\ DDRPHY_MODE_TWO_RANKS) { CFG_DDR_SGMII_PHY->spio253.spio253 = 1U; } { /* * firmware set this to 3'b100 for all cases except when we * are in OFF mode (DDR3,DDR4,LPDDR3,LPDDR4). */ CFG_DDR_SGMII_PHY->rpc98.rpc98 = 0x04U; } /* * SAR xxxx * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK */ CFG_DDR_SGMII_PHY->UNUSED_SPACE0[0] = 0x0U; break; case DDR4: { /* * Sar 108017 * ODT_STATIC setting is wrong for DDR4/LPDDR3, needs to * be overwritten in embedded SW for E51 * * ODT_STATIC is set to 001 for DQ/DQS/DBI bits in * DDR3/LPDDR4, this enables termination to VSS. * * This needs to be switched to VDDI termination. * * To do this, we do APB register writes to override * the following PC bits: * odt_static_dq=010 * odt_static_dqs=010 */ CFG_DDR_SGMII_PHY->rpc10_ODT.rpc10_ODT = 2U; CFG_DDR_SGMII_PHY->rpc11_ODT.rpc11_ODT = 2U; /* * SAR 108218 * The firmware should set this to 3'b100 for * all cases except when we are in OFF mode (DDR3,DDR4, * LPDDR3,LPDDR4). */ CFG_DDR_SGMII_PHY->rpc98.rpc98 = 0x04U; /* * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK */ CFG_DDR_SGMII_PHY->UNUSED_SPACE0[0] = 0x0U; } break; case LPDDR3: { /* * Sar 108017 * ODT_STATIC setting is wrong for DDR4/LPDDR3, needs to be * overwritten in embedded SW for E51 * * ODT_STATIC is set to 001 for DQ/DQS/DBI bits in * DDR3/LPDDR4, this enables termination to VSS. * * This needs to be switched to VDDI termination. * * To do this, we should do APB register writes to override * the following PC bits: * odt_static_dq=010 * odt_static_dqs=010 */ CFG_DDR_SGMII_PHY->rpc10_ODT.rpc10_ODT = 2U; CFG_DDR_SGMII_PHY->rpc11_ODT.rpc11_ODT = 2U; /* * SAR 108218 * I've reviewed the results, and the ibufmd bit should be * fixed in firmware for ibufmd_dqs. Malachy please have * the firmware set this to 3'b100 for all cases except * when we are in OFF mode (DDR3,DDR4,LPDDR3,LPDDR4). */ CFG_DDR_SGMII_PHY->rpc98.rpc98 = 0x04U; /* * SAR xxxx * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK */ CFG_DDR_SGMII_PHY->UNUSED_SPACE0[0] = 0x0U; } break; case LPDDR4: { /* * We need to be able to implement different physical * configurations of LPDDR4, given the twindie architecture. * These are not fully decoded by the APB decoder (we dont * have all the options). * Basically we want to support: * Hook the CA buses from the 2 die up in parallel on the * same FPGA pins * Hook the CA buses from the 2 die up in parallel using * the mirrored FPGA pins (IE CA_A/CA_B) * Some combination of the 2, ie duplicate the clocks but * not the CA, duplicate the clocks and command, but not * address, etc. */ /* OVRT_EN_ADDCMD1 (default 0xF00), register named ovrt11 */ #ifndef LIBERO_SETTING_RPC_EN_ADDCMD0_OVRT9 /* * If this define is not present, indicates older * Libero core (pre 2.0.109) * So we run this code */ CFG_DDR_SGMII_PHY->ovrt10.ovrt10 =\ LIBERO_SETTING_RPC_EN_ADDCMD1_OVRT10; { /* Use pull-ups to set the CMD/ADD ODT */ CFG_DDR_SGMII_PHY->rpc245.rpc245 =\ 0x00000000U; CFG_DDR_SGMII_PHY->rpc237.rpc237 =\ 0xffffffff; } /* OVRT_EN_ADDCMD2 (default 0xE06U), register named ovrt12 */ CFG_DDR_SGMII_PHY->ovrt11.ovrt11 =\ LIBERO_SETTING_RPC_EN_ADDCMD2_OVRT11; #endif /* Required when rank x 2 */ if ((LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_RANK_MASK) ==\ DDRPHY_MODE_TWO_RANKS) { CFG_DDR_SGMII_PHY->spio253.spio253 = 1; } { /* * SAR 108218 * I've reviewed the results, and the ibufmd bit should be * fixed in firmware for ibufmd_dqs. Malachy please have the * firmware set this to 3'b100 for all cases except when we * are in OFF mode (DDR3,DDR4,LPDDR3,LPDDR4). */ CFG_DDR_SGMII_PHY->rpc98.rpc98 = 0x04U; } /* * SAR xxxx * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK */ CFG_DDR_SGMII_PHY->rpc226.rpc226 = 0x14U; CFG_DDR_SGMII_PHY->UNUSED_SPACE0[0] = 0xA000U; /* for Skew debug at 125C MIN TTHH18->Changing the common mode of the Receiver to low common mode to improve IO Performance of LPDDR4 */ CFG_DDR_SGMII_PHY->SPARE0.SPARE0 = 0xA000U; } break; } } #ifdef TUNE_RPC_156_DQDQS_INIT_VALUE CFG_DDR_SGMII_PHY->rpc156.rpc156 = rpc_156_dqdqs_init_offset; #else CFG_DDR_SGMII_PHY->rpc156.rpc156 = LIBERO_SETTING_RPC_156_VALUE; #endif #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r\n\r CFG_DDR_SGMII_PHY->rpc156.rpc156 = ",CFG_DDR_SGMII_PHY->rpc156.rpc156); #endif #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r\n\r Spare bit value: ",CFG_DDR_SGMII_PHY->SPARE0.SPARE0); #endif { /* * sar107009 found by Paul in Crevin, * This has been fixed in tag g5_mss_ddrphy_apb tag 2.9.130 * todo: remove this software workaround as no longer required * * Default of rpc27 should be 2, currently is 0 * We will set to 2 for the moment with software. */ CFG_DDR_SGMII_PHY->rpc27.rpc27 = 0x2U; /* * Default of rpc27 Issue see by Paul/Alister 10th June * tb_top.duv_wrapper.u_design.mss_custom.gbank6.tip.gapb.\ * MAIN.u_apb_mss_decoder_io.rpc203_spare_iog_dqsn */ CFG_DDR_SGMII_PHY->rpc203.rpc203 = 0U; } { /* * * We'll have to pass that one in via E51, meaning APB writes to * addresses: * 0x2000 7384 rpc1_ODT ODT_CA * 0x2000 7388 rpc2_ODT RPC_ODT_CLK * 0x2000 738C rpc3_ODT ODT_DQ * 0x2000 7390 rpc4_ODT ODT_DQS * * todo: replace with Libero settings below, once values verified */ CFG_DDR_SGMII_PHY->rpc1_ODT.rpc1_ODT = LIBERO_SETTING_RPC_ODT_ADDCMD; CFG_DDR_SGMII_PHY->rpc2_ODT.rpc2_ODT = LIBERO_SETTING_RPC_ODT_CLK; CFG_DDR_SGMII_PHY->rpc3_ODT.rpc3_ODT = LIBERO_SETTING_RPC_ODT_DQ; CFG_DDR_SGMII_PHY->rpc4_ODT.rpc4_ODT = LIBERO_SETTING_RPC_ODT_DQS; } { /* * bclk_sel_clkn - selects bclk sclk training clock */ CFG_DDR_SGMII_PHY->rpc19.rpc19 = 0x01U; /* bclk_sel_clkn */ /* * add cmd - selects bclk sclk training clock */ CFG_DDR_SGMII_PHY->rpc20.rpc20 = 0x00U; /* bclk_sel_clkp */ } { /* * Each lane has its own FIFO. This paramater adjusts offset for all lanes. */ #if (TUNE_RPC_166_VALUE == 1) CFG_DDR_SGMII_PHY->rpc166.rpc166 = rpc_166_fifo_offset; #endif } /* * Override RPC bits for weak PU and PD's * Set over-ride bit for unused I/O */ config_ddr_io_pull_up_downs_rpc_bits(ddr_type); } /** Info on OFF modes: OFF MODE from reset- I/O not being used MSSIO from reset- non default values Needs non default values to completely go completely OFF Drive bits and ibuff mode Ciaran to define what need to be done SAR107676 DDR - by default put to DDR4 mode so needs active intervention Bills sac spec (DDR PHY SAC spec section 6.1) Mode register set to 7 Ibuff mode set to 7 (rx turned off) P-Code/ N-code of no relevance as not used Disable DDR PLL Will be off from reset- no need Need to reflash DDR APB ( three resets - soft reset bit 0 to 1) Drive odt etc SGMII - from reset nothing to be done See Jeff's spread sheet- default values listed Extn clock off also defined in spread sheet */ /** * ddr_off_mode(void) * Assumed in Dynamic mode. * i.e. * SCB dynamic enable bit is high * MSS core_up = 1 * dce[0,1,2] 0,0,0 * flash valid = 1 * IP: * DECODER_DRIVER, ODT, IO all out of reset * * DDR PHY off mode that I took from version 1.58 of the DDR SAC spec. * 1. DDR PHY OFF mode (not used at all). * 1. Set the DDR_MODE register to 7 * This will disable all the drive and ODT to 0, as well as set all WPU bits. * 2. Set the RPC_IBUF_MD_* registers to 7 * This will disable all receivers. * 3. Set the REG_POWERDOWN_B register to 0 * This will disable the DDR PLL * */ static void ddr_off_mode(void) { /* * DDR PLL is not turn on on reset- so no need to do anything */ /* * set the mode register to 7 => off mode * From the DDRPHY training firmware spec.: * If the DDR interface is unused, the firmware will have to write 3'b111 * into the APB_DDR_MODE register. This will disable all the DRIVERs, ODT * and INPUT receivers. * By default, WPD will be applied to all pads. * * If a user wants to apply WPU, this will have to be applied through * firmware, by changing all RPC_WPU_*=0, and RPC_WPD_*=1, via APB register * writes. * * Unused IO within an interface will automatically be shut off, as unused * DQ/DM/DQS/and CA buffers and odt are automatically disabled by the * decode, and put into WPD mode. * Again, if the user wants to change this to WPU, the will have to write * RPC_WPU_*=0 and RPC_WPD_*=1 to override the default. * */ /* Note: DMI_DBI [8:1] needs to be 0 (off) during training */ CFG_DDR_SGMII_PHY->DDRPHY_MODE.DDRPHY_MODE =\ (LIBERO_SETTING_DDRPHY_MODE_OFF /* & DMI_DBI_MASK */); /* * VS for off mode */ CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ LIBERO_SETTING_DPC_BITS_OFF_MODE; /* * Toggle decoder here * bit 0 == PERIPH soft reset, auto cleared */ CFG_DDR_SGMII_PHY->SOFT_RESET_DECODER_DRIVER.SOFT_RESET_DECODER_DRIVER= 1U; CFG_DDR_SGMII_PHY->SOFT_RESET_DECODER_ODT.SOFT_RESET_DECODER_ODT = 1U; CFG_DDR_SGMII_PHY->SOFT_RESET_DECODER_IO.SOFT_RESET_DECODER_IO = 1U; /* * set ibuff mode to 7 in off mode * */ CFG_DDR_SGMII_PHY->rpc95.rpc95 = 0x07; /* addcmd I/O*/ CFG_DDR_SGMII_PHY->rpc96.rpc96 = 0x07; /* clk */ CFG_DDR_SGMII_PHY->rpc97.rpc97 = 0x07; /* dq */ CFG_DDR_SGMII_PHY->rpc98.rpc98 = 0x07; /* dqs */ /* * Default WPU, modify If user wants Weak Pull Up */ /* * UNUSED_SPACE0 * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK * todo: Do we need to add Pu/PD option for off mode to Libero setting? */ CFG_DDR_SGMII_PHY->UNUSED_SPACE0[0] = 0x0000U; /* * REG_POWERDOWN_B on PLL turn-off, in case was turned on. */ ddr_pll_config_scb_turn_off(); return; } /***************************************************************************//** * Number of tests which write and read from DDR * Tests data path through the cache and through AXI4 switch. */ #ifdef DDR_SANITY_CHECKS_EN static uint8_t memory_tests(void) { uint64_t shift_walking_one = 4U; uint64_t start_address = 0x0000000000000000U; uint8_t error = 0U; SIM_FEEDBACK1(199U); /* * Verify seg1 reg 2, datapath through AXI4 switch */ while(shift_walking_one <= 28U) /* 28 => 1G, as 2**28 == 256K and this is mult by (4 lanes) */ { SIM_FEEDBACK1(shift_walking_one); start_address = (uint64_t)(0xC0000000U + (0x1U< 1G { SIM_FEEDBACK1(shift_walking_one); start_address = (uint64_t)(0x1400000000U + (0x1U<= 4U) { start_address = (uint64_t)(0x1400000000U + \ (((0x1U<<(shift_walking_one +1)) - 1U) -0x0F) ); error = rw_sanity_chk((uint64_t *)start_address , (uint32_t)0x5U); if(error) { ddr_error_count++; SIM_FEEDBACK1(201U); } } shift_walking_one++; } /* * Verify mtc */ SIM_FEEDBACK1(600U); shift_walking_one = 4U; while(shift_walking_one <= 28U) //28 => 1G { SIM_FEEDBACK1(shift_walking_one); start_address = (uint64_t)(0x1U<= 4U) { start_address = (uint64_t)((((0x1U<<(shift_walking_one +1)) - 1U)\ -0x0F) ); error = mtc_sanity_check(start_address); if(error) { ddr_error_count++; SIM_FEEDBACK1(204U); } } shift_walking_one++; } /* * Verify seg0 reg 0, datapath through cache */ SIM_FEEDBACK1(700U); shift_walking_one = 4U; while(shift_walking_one <= 27U) //28 => 1G { SIM_FEEDBACK1(shift_walking_one); start_address = (uint64_t)(0x80000000U + (0x1U< 1G (0x10000000(address) * 4 (32bits wide)) { SIM_FEEDBACK1(shift_walking_one); start_address = (uint64_t)(0x1000000000U + (0x1U<expert_dlycnt_move_reg0.expert_dlycnt_move_reg0 = 0U; } else { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = \ (CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1\ & (uint32_t)~0x0FU); } //set expert_dfi_status_override_to_shim = 0x7 CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x07U; //set expert_mode_en = 0x21 CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x21U; //set dyn_ovr_dlycnt_dq_load* = 1 if(lane < 4U) { CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0 =\ (0xFFU << (lane * 8U)); } else { CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 |=\ 0x0FU; } //set dyn_ovr_dlycnt_dq_load* = 0 CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0 = 0U; if(lane < 4U) { CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg0.expert_dlycnt_load_reg0 = 0U; } else { CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = \ (CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1\ & (uint32_t)~0x0FU); } //set expert_mode_en = 0x8 CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x8U; } /***************************************************************************//** * increment_dq() * set dyn_ovr_dlycnt_dq_move* = 0 * set dyn_ovr_dlycnt_dq_direction* = 1 * set expert_dfi_status_override_to_shim = 0x7 * set expert_mode_en = 0x21 * * #to increment multiple times loop the move=0/1 multiple times * set dyn_ovr_dlycnt_dq_move* = 1 * set dyn_ovr_dlycnt_dq_move* = 0 * # * set expert_mode_en = 0x8 * @param lane * @param move_count */ #ifdef SW_CONFIG_LPDDR_WR_CALIB_FN static void increment_dq(uint8_t lane, uint32_t move_count) { //set dyn_ovr_dlycnt_dq_move* = 0 if(lane < 4U) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg0.expert_dlycnt_move_reg0 = 0U; } else { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = \ (CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1\ & ~0x0FU); } //set dyn_ovr_dlycnt_dq_direction* = 1 if(lane < 4U) { CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg0.expert_dlycnt_direction_reg0\ = (0xFFU << (lane * 8U)); } else { /* only four lines, use 0xFU */ CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 |= 0xFU; } /* set expert_dfi_status_override_to_shim = 0x7 */ CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x07U; /* set expert_mode_en = 0x21 */ CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x21U; /* #to increment multiple times loop the move=0/1 multiple times */ move_count = move_count + move_count + move_count; while(move_count) { // set dyn_ovr_dlycnt_dq_move* = 1 if(lane < 4U) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg0.expert_dlycnt_move_reg0\ = (0xFFU << (lane * 8U)); } else { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1\ |= 0x0FU; } // set dyn_ovr_dlycnt_dq_move* = 0 CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg0.expert_dlycnt_move_reg0 = 0U; if(lane < 4U) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg0.expert_dlycnt_move_reg0\ = 0U; } else { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = \ (CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 & ~0x0FU); } move_count--; } /* set expert_mode_en = 0x8 */ CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x8U; } #endif /***************************************************************************//** * */ static void set_write_calib(uint8_t user_lanes) { uint32_t temp = 0U; uint8_t lane_to_set; uint8_t shift = 0U; /* * Calculate the calibrated value and write back */ calib_data.write_cal.lane_calib_result = 0U; for (lane_to_set = 0x00U;\ lane_to_setexpert_mode_en.expert_mode_en = 0x00000008U; SIM_FEEDBACK1(0xFF000000); SIM_FEEDBACK1(calib_data.write_cal.lane_calib_result); SIM_FEEDBACK1(0xFF000000); /* set the calibrated value */ CFG_DDR_SGMII_PHY->expert_wrcalib.expert_wrcalib =\ calib_data.write_cal.lane_calib_result; } /***************************************************************************//** * * @param lane_to_set */ #ifdef SW_CONFIG_LPDDR_WR_CALIB_FN static void set_calc_dq_delay_offset(uint8_t lane_to_set) { uint32_t move_count; load_dq(lane_to_set); /* set to start */ /* shift by 1 to divide by two */ move_count = ((calib_data.dq_cal.upper[lane_to_set] -\ calib_data.dq_cal.lower[lane_to_set] ) >> 1U) +\ calib_data.dq_cal.lower[lane_to_set]; increment_dq(lane_to_set, move_count); } #endif /***************************************************************************//** * * @param user_lanes */ #ifdef SW_CONFIG_LPDDR_WR_CALIB_FN static void set_calib_values(uint8_t user_lanes) { uint8_t lane_to_set; uint32_t move_count; for (lane_to_set = 0x00U;\ lane_to_set< user_lanes ; lane_to_set++) { set_calc_dq_delay_offset(lane_to_set); } /* and set the write calibration calculated */ set_write_calib(user_lanes); } #endif /***************************************************************************//** * write_calibration_using_mtc * Use Memory Test Core plugged in to the front end of the DDR controller to * perform lane-based writes and read backs and increment write calibration * offset for each lane until data match occurs. The Memory Test Core is the * basis for all training. * * @param number_of_lanes_to_calibrate * @return */ static uint8_t \ write_calibration_using_mtc(uint8_t number_of_lanes_to_calibrate) { uint8_t laneToTest; uint32_t result = 0U; uint32_t cal_data; uint64_t start_address = 0x0000000000000000ULL; uint32_t size = ONE_MB_MTC; /* Number of reads for each iteration 2**size*/ calib_data.write_cal.status_lower = 0U; /* * bit 3 must be set if we want to use the * expert_wrcalib * register */ CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000008U; /* * training carried out here- sweeping write calibration offset from 0 to F * Explanation: A register, expert_wrcalib, is described in MSS DDR TIP * Register Map [1], and its purpose is to delay--by X number of memory clock * cycles--the write data, write data mask, and write output enable with the * respect to the address and command for each lane. */ for (cal_data=0x00000U;cal_data<0xfffffU;cal_data=cal_data+0x11111U) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\rCalibration offset used:",cal_data &0xFUL); #endif CFG_DDR_SGMII_PHY->expert_wrcalib.expert_wrcalib = cal_data; for (laneToTest = 0x00U; laneToTestMC_BASE2.INIT_MRR_MODE.INIT_MRR_MODE = 0x01; DDRCFG->MC_BASE2.INIT_MR_ADDR.INIT_MR_ADDR = MR_ADDR ; /* * next: * write desired VREF calibration range (0=Range 1, 1=Range 2) to bit 6 * of MR6 * write 0x00 to bits 5:0 of MR6 (base calibration value) */ DDRCFG->MC_BASE2.INIT_MR_WR_DATA.INIT_MR_WR_DATA = MR_DATA; DDRCFG->MC_BASE2.INIT_MR_WR_MASK.INIT_MR_WR_MASK = 0U; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ = 0x01U; while((DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK & 0x01U) == 0U) /* wait for ack- to confirm register is written */ { test--; if(test-- == 0U) { result = 1U; break; } } return result; } #endif #define VREF_INVALID 0x01U /***************************************************************************//** * FPGA_VREFDQ_calibration_using_mtc(void) * vary DQ voltage and set optimum DQ voltage * @return */ #ifdef VREFDQ_CALIB /* * This step is optional * todo: Test once initial board verification complete */ static uint8_t FPGA_VREFDQ_calibration_using_mtc(void) { uint8_t laneToTest, result = 0U; uint64_t mask; uint32_t vRef; uint64_t start_address = 0x0000000000000000ULL; uint64_t size = 4U; /* * Step 2a. FPGA VREF (Local VREF training) * Train FPGA VREF using the vrgen_h and vrgen_v registers */ { /* * To manipulate the FPGA VREF value, firmware must write to the * DPC_BITS register, located at physical address 0x2000 7184. * Full documentation for this register can be found in * DFICFG Register Map [4]. */ /* * See DPC_BITS definition in .h file */ /* CFG_DDR_SGMII_PHY->DPC_BITS.bitfield.dpc_vrgen_h; */ /* CFG_DDR_SGMII_PHY->DPC_BITS.bitfield.dpc_vrgen_v; */ } /* * training carried out here- sweeping write calibration offset from 0 to F * Explanation: A register, expert_wrcalib, is described in MSS DDR TIP * Register Map [1], and its purpose is to delay--by X number of memory * clock cycles--the write data, write data mask, and write output enable * with the respect to the address and command for each lane. */ calib_data.fpga_vref.vref_result = 0U; calib_data.fpga_vref.lower = VREF_INVALID; calib_data.fpga_vref.upper = VREF_INVALID; calib_data.fpga_vref.status_lower = 0x00U; calib_data.fpga_vref.status_upper = 0x00U; mask = 0xFU; /* todo: obtain data width from user parameters */ uint32_t count = 0U; /* each bit .25% of VDD ?? */ for (vRef=(0x1U<<4U);vRef<(0x1fU<<4U);vRef=vRef+(0x1U<<4U)) { /* CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ (CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & (~(0x1U<<10U))); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ (CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & (~(0x1fU<<4U))) | vRef; */ /* need to set via the SCB, otherwise reset required. So lines below * rather than above used */ IOSCB_BANKCONT_DDR->dpc_bits = (IOSCB_BANKCONT_DDR->dpc_bits &\ (~(0x1U<<10U))); IOSCB_BANKCONT_DDR->dpc_bits = (IOSCB_BANKCONT_DDR->dpc_bits &\ (~(0x1fU<<4U))) | vRef; /* read one to flush MTC - this is required */ result = MTC_test(1U<>1U); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ (CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & (0x1fU<<4U)) | vRef; /* need to set via the SCB, otherwise reset required. */ IOSCB_BANKCONT_DDR->dpc_bits = (IOSCB_BANKCONT_DDR->dpc_bits &\ (0x1fU<<4U)) | vRef; } else { result = 1U; /* failed to get good data at any voltage level */ } return result; } #endif #ifdef VREFDQ_CALIB /* * This step is optional * todo: Test once initial board verification complete */ #define MEM_VREF_INVALID 0xFFFFFFFFU /***************************************************************************//** * * VREFDQ_calibration_using_mtc * In order to write to mode registers, the E51 must use the INIT_* interface * at the front end of the DDR controller, * which is available via a series of control registers described in the DDR * CSR APB Register Map. * * @return */ static uint8_t VREFDQ_calibration_using_mtc(void) { uint8_t laneToTest, result = 0U; uint64_t mask; uint32_t vRef; uint64_t start_address = 0x00000000C0000000ULL; uint64_t size = 4U; /* * Step 2a. FPGA VREF (Local VREF training) * Train FPGA VREF using the vrgen_h and vrgen_v registers */ { /* * */ DDRCFG->MC_BASE2.INIT_MRR_MODE.INIT_MRR_MODE = 0x01U; DDRCFG->MC_BASE2.INIT_MR_ADDR.INIT_MR_ADDR = 6U ; /* * next: * write desired VREF calibration range (0=Range 1, 1=Range 2) to bit 6 * of MR6 * write 0x00 to bits 5:0 of MR6 (base calibration value) */ DDRCFG->MC_BASE2.INIT_MR_WR_DATA.INIT_MR_WR_DATA = 0U; DDRCFG->MC_BASE2.INIT_MR_WR_MASK.INIT_MR_WR_MASK = (0x01U <<6U) |\ (0x3FU) ; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ = 0x01U; if((DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK & 0x01U) == 0U) /* wait for ack- to confirm register is written */ { } } /* * training carried out here- sweeping write calibration offset from 0 to F * Explanation: A register, expert_wrcalib, is described in MSS DDR TIP * Register Map [1], and its purpose is to delay--by X number of memory clock * cycles--the write data, write data mask, and write output enable with the * respect to the address and command for each lane. */ calib_data.mem_vref.vref_result = 0U; calib_data.mem_vref.lower = MEM_VREF_INVALID; calib_data.mem_vref.upper = MEM_VREF_INVALID; calib_data.mem_vref.status_lower = 0x00U; calib_data.mem_vref.status_upper = 0x00U; mask = 0xFU; /* todo: obtain data width from user paramaters */ for (vRef=(0x1U<<4U);vRef<0x3fU;vRef=(vRef+0x1U)) { /* * We change the value in the RPC register, but we will lso need to * change SCB as will not be reflected without a soft reset */ CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ (CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & (0x1fU<<4U)) | vRef; /* need to set via the SCB, otherwise reset required. */ IOSCB_BANKCONT_DDR->dpc_bits = (IOSCB_BANKCONT_DDR->dpc_bits\ & (0x1fU<<4U)) | vRef; /* read one to flush MTC - this is required */ result = MTC_test(1U<1U); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS =\ (CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & (0x1fU<<4U)) | vRef; /* need to set via the SCB, otherwise reset required. */ IOSCB_BANKCONT_DDR->dpc_bits = (IOSCB_BANKCONT_DDR->dpc_bits & (0x1fU<<4U)) | vRef; } else { result = 1U; /* failed to get good data at any voltage level */ } return result; } #endif /***************************************************************************//** * MTC_test * test memory using the NWL memory test core * There are numerous options * todo: Add user input as to option to use? * @param laneToTest * @param mask0 * @param mask1 some lane less DQ as only used for parity * @param start_address * @param size = x, where x is used as power of two 2**x e.g. 256K => x == 18 * @return pass/fail */ static uint8_t MTC_test(uint8_t mask, uint64_t start_address, uint32_t size, MTC_PATTERN data_pattern, MTC_ADD_PATTERN add_pattern, uint32_t *error) { if((*error & MTC_TIMEOUT_ERROR) == MTC_TIMEOUT_ERROR) { return (uint8_t)*error; } /* Write Calibration - first configure memory test */ { /* * write calibration * configure common memory test interface by writing registers: * MT_STOP_ON_ERROR, MT_DATA_PATTERN, MT_ADDR_PATTERN, MT_ADDR_BITS */ /* see MTC user guide */ DDRCFG->MEM_TEST.MT_STOP_ON_ERROR.MT_STOP_ON_ERROR = 0U; /* make sure off, will turn on later. */ DDRCFG->MEM_TEST.MT_EN_SINGLE.MT_EN_SINGLE = 0x00U; /* * MT_DATA_PATTERN * * 0x00 => Counting pattern * 0x01 => walking 1's * 0x02 => pseudo random * 0x03 => no repeating pseudo random * 0x04 => alt 1's and 0's * 0x05 => alt 5's and A's * 0x06 => User specified * 0x07 => pseudo random 16-bit * 0x08 => pseudo random 8-bit * 0x09- 0x0f reserved * */ { /* * Added changing pattern so write pattern is different, read back * can not pass on previously written data */ DDRCFG->MEM_TEST.MT_DATA_PATTERN.MT_DATA_PATTERN = data_pattern; } if(add_pattern == MTC_ADD_RANDOM) { /* * MT_ADDR_PATTERN * 0x00 => Count in pattern * 0x01 => Pseudo Random Pattern * 0x02 => Arbiatry Pattern Gen (user defined ) - Using RAMS */ DDRCFG->MEM_TEST.MT_ADDR_PATTERN.MT_ADDR_PATTERN = 1U; } else { DDRCFG->MEM_TEST.MT_ADDR_PATTERN.MT_ADDR_PATTERN = 0U; } } if(add_pattern != MTC_ADD_RANDOM) { /* * Set the starting address and number to test * * MT_START_ADDR * Starting address * MT_ADRESS_BITS * Length to test = 2 ** MT_ADRESS_BITS */ DDRCFG->MEM_TEST.MT_START_ADDR_0.MT_START_ADDR_0 =\ (uint32_t)(start_address & 0xFFFFFFFFUL); /* The address here is as see from DDR controller => start at 0x0*/ DDRCFG->MEM_TEST.MT_START_ADDR_1.MT_START_ADDR_1 =\ (uint32_t)((start_address >> 32U)); } else { DDRCFG->MEM_TEST.MT_START_ADDR_0.MT_START_ADDR_0 = 0U; DDRCFG->MEM_TEST.MT_START_ADDR_1.MT_START_ADDR_1 = 0U; } DDRCFG->MEM_TEST.MT_ADDR_BITS.MT_ADDR_BITS =\ size; /* 2 power 24 => 256k to do- make user programmable */ { /* * FOR each DQ lane * set error mask registers MT_ERROR_MASK_* to mask out * all error bits but the ones for the current DQ lane * WHILE timeout counter is less than a threshold * perform memory test by writing MT_EN or MT_EN_SINGLE * wait for memory test completion by polling MT_DONE_ACK * read back memory test error status from MT_ERROR_STS * IF no error detected * exit loop * ELSE * increment write calibration offset for current DQ lane * by writing EXPERT_WRCALIB * ENDWHILE * ENDFOR */ { /* * MT_ERROR_MASK * All bits set in this field mask corresponding bits in data fields * i.e. mt_error and mt_error_hold will not be set for errors in * those fields * * Structure of 144 bits same as DFI bus * 36 bits per lane ( 8 physical * 4) + (1ECC * 4) = 36 * * If we wrote out the following pattern from software: * 0x12345678 * 0x87654321 * 0x56789876 * 0x43211234 * We should see: * NNNN_YXXX_XXX3_4YXX_XXXX_76YX_XXXX_X21Y_XXXX_XX78 * N: not used * Y: */ DDRCFG->MEM_TEST.MT_ERROR_MASK_0.MT_ERROR_MASK_0 = 0xFFFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_1.MT_ERROR_MASK_1 = 0xFFFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_2.MT_ERROR_MASK_2 = 0xFFFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_3.MT_ERROR_MASK_3 = 0xFFFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_4.MT_ERROR_MASK_4 = 0xFFFFFFFFU; if (mask & 0x1U) { DDRCFG->MEM_TEST.MT_ERROR_MASK_0.MT_ERROR_MASK_0 &= 0xFFFFFF00U; DDRCFG->MEM_TEST.MT_ERROR_MASK_1.MT_ERROR_MASK_1 &= 0xFFFFF00FU; DDRCFG->MEM_TEST.MT_ERROR_MASK_2.MT_ERROR_MASK_2 &= 0xFFFF00FFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_3.MT_ERROR_MASK_3 &= 0xFFF00FFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_4.MT_ERROR_MASK_4 &= 0xFFFFFFFFU; } if (mask & 0x2U) { DDRCFG->MEM_TEST.MT_ERROR_MASK_0.MT_ERROR_MASK_0 &= 0xFFFF00FFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_1.MT_ERROR_MASK_1 &= 0xFFF00FFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_2.MT_ERROR_MASK_2 &= 0xFF00FFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_3.MT_ERROR_MASK_3 &= 0xF00FFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_4.MT_ERROR_MASK_4 &= 0xFFFFFFFFU; } if (mask & 0x4U) { DDRCFG->MEM_TEST.MT_ERROR_MASK_0.MT_ERROR_MASK_0 &= 0xFF00FFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_1.MT_ERROR_MASK_1 &= 0xF00FFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_2.MT_ERROR_MASK_2 &= 0x00FFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_3.MT_ERROR_MASK_3 &= 0x0FFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_4.MT_ERROR_MASK_4 &= 0xFFFFFFF0U; } if (mask & 0x8U) { DDRCFG->MEM_TEST.MT_ERROR_MASK_0.MT_ERROR_MASK_0 &= 0x00FFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_1.MT_ERROR_MASK_1 &= 0x0FFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_2.MT_ERROR_MASK_2 &= 0xFFFFFFF0U; DDRCFG->MEM_TEST.MT_ERROR_MASK_3.MT_ERROR_MASK_3 &= 0xFFFFFF00U; DDRCFG->MEM_TEST.MT_ERROR_MASK_4.MT_ERROR_MASK_4 &= 0xFFFFF00FU; } if (mask & 0x10U) { DDRCFG->MEM_TEST.MT_ERROR_MASK_0.MT_ERROR_MASK_0 &= 0xFFFFFFFFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_1.MT_ERROR_MASK_1 &= 0xFFFFFFF0U; DDRCFG->MEM_TEST.MT_ERROR_MASK_2.MT_ERROR_MASK_2 &= 0xFFFFFF0FU; DDRCFG->MEM_TEST.MT_ERROR_MASK_3.MT_ERROR_MASK_3 &= 0xFFFFF0FFU; DDRCFG->MEM_TEST.MT_ERROR_MASK_4.MT_ERROR_MASK_4 &= 0xFFFF0FFFU; } /* * MT_EN * Enables memory test * If asserted at end of memory test, will keep going */ DDRCFG->MEM_TEST.MT_EN.MT_EN = 0U; /* * MT_EN_SINGLE * Will not repeat if this is set */ DDRCFG->MEM_TEST.MT_EN_SINGLE.MT_EN_SINGLE = 0x00U; DDRCFG->MEM_TEST.MT_EN_SINGLE.MT_EN_SINGLE = 0x01U; /* * MT_DONE_ACK * Set when test completes */ volatile uint64_t something_to_do = 0U; #ifndef UNITTEST while (( DDRCFG->MEM_TEST.MT_DONE_ACK.MT_DONE_ACK & 0x01U) == 0U) { something_to_do++; if(something_to_do > 0xFFFFFFUL) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\rmtc test error:",MTC_TIMEOUT_ERROR); #endif return (MTC_TIMEOUT_ERROR); } #ifdef RENODE_DEBUG break; #endif } #endif } } /* * MT_ERROR_STS * Return the error status * todo:Check NWL data and detail error states here */ return (DDRCFG->MEM_TEST.MT_ERROR_STS.MT_ERROR_STS & 0x01U); } /***************************************************************************//** * Setup DDRC * These settings come from config tool * */ #define _USE_SETTINGS_USED_IN_DDR3_FULL_CHIP_TEST static void init_ddrc(void) { DDRCFG->ADDR_MAP.CFG_MANUAL_ADDRESS_MAP.CFG_MANUAL_ADDRESS_MAP =\ LIBERO_SETTING_CFG_MANUAL_ADDRESS_MAP; DDRCFG->ADDR_MAP.CFG_CHIPADDR_MAP.CFG_CHIPADDR_MAP =\ LIBERO_SETTING_CFG_CHIPADDR_MAP; DDRCFG->ADDR_MAP.CFG_CIDADDR_MAP.CFG_CIDADDR_MAP =\ LIBERO_SETTING_CFG_CIDADDR_MAP; DDRCFG->ADDR_MAP.CFG_MB_AUTOPCH_COL_BIT_POS_LOW.CFG_MB_AUTOPCH_COL_BIT_POS_LOW =\ LIBERO_SETTING_CFG_MB_AUTOPCH_COL_BIT_POS_LOW; DDRCFG->ADDR_MAP.CFG_MB_AUTOPCH_COL_BIT_POS_HIGH.CFG_MB_AUTOPCH_COL_BIT_POS_HIGH =\ LIBERO_SETTING_CFG_MB_AUTOPCH_COL_BIT_POS_HIGH; DDRCFG->ADDR_MAP.CFG_BANKADDR_MAP_0.CFG_BANKADDR_MAP_0 =\ LIBERO_SETTING_CFG_BANKADDR_MAP_0; DDRCFG->ADDR_MAP.CFG_BANKADDR_MAP_1.CFG_BANKADDR_MAP_1 =\ LIBERO_SETTING_CFG_BANKADDR_MAP_1; DDRCFG->ADDR_MAP.CFG_ROWADDR_MAP_0.CFG_ROWADDR_MAP_0 =\ LIBERO_SETTING_CFG_ROWADDR_MAP_0; DDRCFG->ADDR_MAP.CFG_ROWADDR_MAP_1.CFG_ROWADDR_MAP_1 =\ LIBERO_SETTING_CFG_ROWADDR_MAP_1; DDRCFG->ADDR_MAP.CFG_ROWADDR_MAP_2.CFG_ROWADDR_MAP_2 =\ LIBERO_SETTING_CFG_ROWADDR_MAP_2; DDRCFG->ADDR_MAP.CFG_ROWADDR_MAP_3.CFG_ROWADDR_MAP_3 =\ LIBERO_SETTING_CFG_ROWADDR_MAP_3; DDRCFG->ADDR_MAP.CFG_COLADDR_MAP_0.CFG_COLADDR_MAP_0 =\ LIBERO_SETTING_CFG_COLADDR_MAP_0; DDRCFG->ADDR_MAP.CFG_COLADDR_MAP_1.CFG_COLADDR_MAP_1 =\ LIBERO_SETTING_CFG_COLADDR_MAP_1; DDRCFG->ADDR_MAP.CFG_COLADDR_MAP_2.CFG_COLADDR_MAP_2 =\ LIBERO_SETTING_CFG_COLADDR_MAP_2; DDRCFG->MC_BASE3.CFG_VRCG_ENABLE.CFG_VRCG_ENABLE =\ LIBERO_SETTING_CFG_VRCG_ENABLE; DDRCFG->MC_BASE3.CFG_VRCG_DISABLE.CFG_VRCG_DISABLE =\ LIBERO_SETTING_CFG_VRCG_DISABLE; DDRCFG->MC_BASE3.CFG_WRITE_LATENCY_SET.CFG_WRITE_LATENCY_SET =\ LIBERO_SETTING_CFG_WRITE_LATENCY_SET; DDRCFG->MC_BASE3.CFG_THERMAL_OFFSET.CFG_THERMAL_OFFSET =\ LIBERO_SETTING_CFG_THERMAL_OFFSET; DDRCFG->MC_BASE3.CFG_SOC_ODT.CFG_SOC_ODT = LIBERO_SETTING_CFG_SOC_ODT; DDRCFG->MC_BASE3.CFG_ODTE_CK.CFG_ODTE_CK = LIBERO_SETTING_CFG_ODTE_CK; DDRCFG->MC_BASE3.CFG_ODTE_CS.CFG_ODTE_CS = LIBERO_SETTING_CFG_ODTE_CS; DDRCFG->MC_BASE3.CFG_ODTD_CA.CFG_ODTD_CA = LIBERO_SETTING_CFG_ODTD_CA; DDRCFG->MC_BASE3.CFG_LPDDR4_FSP_OP.CFG_LPDDR4_FSP_OP =\ LIBERO_SETTING_CFG_LPDDR4_FSP_OP; DDRCFG->MC_BASE3.CFG_GENERATE_REFRESH_ON_SRX.CFG_GENERATE_REFRESH_ON_SRX =\ LIBERO_SETTING_CFG_GENERATE_REFRESH_ON_SRX; DDRCFG->MC_BASE3.CFG_DBI_CL.CFG_DBI_CL = LIBERO_SETTING_CFG_DBI_CL; DDRCFG->MC_BASE3.CFG_NON_DBI_CL.CFG_NON_DBI_CL =\ LIBERO_SETTING_CFG_NON_DBI_CL; DDRCFG->MC_BASE3.INIT_FORCE_WRITE_DATA_0.INIT_FORCE_WRITE_DATA_0 =\ LIBERO_SETTING_INIT_FORCE_WRITE_DATA_0; DDRCFG->MC_BASE1.CFG_WRITE_CRC.CFG_WRITE_CRC =\ LIBERO_SETTING_CFG_WRITE_CRC; DDRCFG->MC_BASE1.CFG_MPR_READ_FORMAT.CFG_MPR_READ_FORMAT =\ LIBERO_SETTING_CFG_MPR_READ_FORMAT; DDRCFG->MC_BASE1.CFG_WR_CMD_LAT_CRC_DM.CFG_WR_CMD_LAT_CRC_DM =\ LIBERO_SETTING_CFG_WR_CMD_LAT_CRC_DM; DDRCFG->MC_BASE1.CFG_FINE_GRAN_REF_MODE.CFG_FINE_GRAN_REF_MODE =\ LIBERO_SETTING_CFG_FINE_GRAN_REF_MODE; DDRCFG->MC_BASE1.CFG_TEMP_SENSOR_READOUT.CFG_TEMP_SENSOR_READOUT =\ LIBERO_SETTING_CFG_TEMP_SENSOR_READOUT; DDRCFG->MC_BASE1.CFG_PER_DRAM_ADDR_EN.CFG_PER_DRAM_ADDR_EN =\ LIBERO_SETTING_CFG_PER_DRAM_ADDR_EN; DDRCFG->MC_BASE1.CFG_GEARDOWN_MODE.CFG_GEARDOWN_MODE =\ LIBERO_SETTING_CFG_GEARDOWN_MODE; DDRCFG->MC_BASE1.CFG_WR_PREAMBLE.CFG_WR_PREAMBLE =\ LIBERO_SETTING_CFG_WR_PREAMBLE; DDRCFG->MC_BASE1.CFG_RD_PREAMBLE.CFG_RD_PREAMBLE =\ LIBERO_SETTING_CFG_RD_PREAMBLE; DDRCFG->MC_BASE1.CFG_RD_PREAMB_TRN_MODE.CFG_RD_PREAMB_TRN_MODE =\ LIBERO_SETTING_CFG_RD_PREAMB_TRN_MODE; DDRCFG->MC_BASE1.CFG_SR_ABORT.CFG_SR_ABORT = LIBERO_SETTING_CFG_SR_ABORT; DDRCFG->MC_BASE1.CFG_CS_TO_CMDADDR_LATENCY.CFG_CS_TO_CMDADDR_LATENCY =\ LIBERO_SETTING_CFG_CS_TO_CMDADDR_LATENCY; DDRCFG->MC_BASE1.CFG_INT_VREF_MON.CFG_INT_VREF_MON =\ LIBERO_SETTING_CFG_INT_VREF_MON; DDRCFG->MC_BASE1.CFG_TEMP_CTRL_REF_MODE.CFG_TEMP_CTRL_REF_MODE =\ LIBERO_SETTING_CFG_TEMP_CTRL_REF_MODE; DDRCFG->MC_BASE1.CFG_TEMP_CTRL_REF_RANGE.CFG_TEMP_CTRL_REF_RANGE =\ LIBERO_SETTING_CFG_TEMP_CTRL_REF_RANGE; DDRCFG->MC_BASE1.CFG_MAX_PWR_DOWN_MODE.CFG_MAX_PWR_DOWN_MODE =\ LIBERO_SETTING_CFG_MAX_PWR_DOWN_MODE; DDRCFG->MC_BASE1.CFG_READ_DBI.CFG_READ_DBI = LIBERO_SETTING_CFG_READ_DBI; DDRCFG->MC_BASE1.CFG_WRITE_DBI.CFG_WRITE_DBI =\ LIBERO_SETTING_CFG_WRITE_DBI; DDRCFG->MC_BASE1.CFG_DATA_MASK.CFG_DATA_MASK =\ LIBERO_SETTING_CFG_DATA_MASK; DDRCFG->MC_BASE1.CFG_CA_PARITY_PERSIST_ERR.CFG_CA_PARITY_PERSIST_ERR =\ LIBERO_SETTING_CFG_CA_PARITY_PERSIST_ERR; DDRCFG->MC_BASE1.CFG_RTT_PARK.CFG_RTT_PARK = LIBERO_SETTING_CFG_RTT_PARK; DDRCFG->MC_BASE1.CFG_ODT_INBUF_4_PD.CFG_ODT_INBUF_4_PD =\ LIBERO_SETTING_CFG_ODT_INBUF_4_PD; DDRCFG->MC_BASE1.CFG_CA_PARITY_ERR_STATUS.CFG_CA_PARITY_ERR_STATUS =\ LIBERO_SETTING_CFG_CA_PARITY_ERR_STATUS; DDRCFG->MC_BASE1.CFG_CRC_ERROR_CLEAR.CFG_CRC_ERROR_CLEAR =\ LIBERO_SETTING_CFG_CRC_ERROR_CLEAR; DDRCFG->MC_BASE1.CFG_CA_PARITY_LATENCY.CFG_CA_PARITY_LATENCY =\ LIBERO_SETTING_CFG_CA_PARITY_LATENCY; DDRCFG->MC_BASE1.CFG_CCD_S.CFG_CCD_S = LIBERO_SETTING_CFG_CCD_S; DDRCFG->MC_BASE1.CFG_CCD_L.CFG_CCD_L = LIBERO_SETTING_CFG_CCD_L; DDRCFG->MC_BASE1.CFG_VREFDQ_TRN_ENABLE.CFG_VREFDQ_TRN_ENABLE =\ LIBERO_SETTING_CFG_VREFDQ_TRN_ENABLE; DDRCFG->MC_BASE1.CFG_VREFDQ_TRN_RANGE.CFG_VREFDQ_TRN_RANGE =\ LIBERO_SETTING_CFG_VREFDQ_TRN_RANGE; DDRCFG->MC_BASE1.CFG_VREFDQ_TRN_VALUE.CFG_VREFDQ_TRN_VALUE =\ LIBERO_SETTING_CFG_VREFDQ_TRN_VALUE; DDRCFG->MC_BASE1.CFG_RRD_S.CFG_RRD_S = LIBERO_SETTING_CFG_RRD_S; DDRCFG->MC_BASE1.CFG_RRD_L.CFG_RRD_L = LIBERO_SETTING_CFG_RRD_L; DDRCFG->MC_BASE1.CFG_WTR_S.CFG_WTR_S = LIBERO_SETTING_CFG_WTR_S; DDRCFG->MC_BASE1.CFG_WTR_L.CFG_WTR_L = LIBERO_SETTING_CFG_WTR_L; DDRCFG->MC_BASE1.CFG_WTR_S_CRC_DM.CFG_WTR_S_CRC_DM =\ LIBERO_SETTING_CFG_WTR_S_CRC_DM; DDRCFG->MC_BASE1.CFG_WTR_L_CRC_DM.CFG_WTR_L_CRC_DM =\ LIBERO_SETTING_CFG_WTR_L_CRC_DM; DDRCFG->MC_BASE1.CFG_WR_CRC_DM.CFG_WR_CRC_DM =\ LIBERO_SETTING_CFG_WR_CRC_DM; DDRCFG->MC_BASE1.CFG_RFC1.CFG_RFC1 = LIBERO_SETTING_CFG_RFC1; DDRCFG->MC_BASE1.CFG_RFC2.CFG_RFC2 = LIBERO_SETTING_CFG_RFC2; DDRCFG->MC_BASE1.CFG_RFC4.CFG_RFC4 = LIBERO_SETTING_CFG_RFC4; DDRCFG->MC_BASE1.CFG_NIBBLE_DEVICES.CFG_NIBBLE_DEVICES =\ LIBERO_SETTING_CFG_NIBBLE_DEVICES; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS0_0.CFG_BIT_MAP_INDEX_CS0_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS0_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS0_1.CFG_BIT_MAP_INDEX_CS0_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS0_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS1_0.CFG_BIT_MAP_INDEX_CS1_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS1_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS1_1.CFG_BIT_MAP_INDEX_CS1_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS1_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS2_0.CFG_BIT_MAP_INDEX_CS2_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS2_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS2_1.CFG_BIT_MAP_INDEX_CS2_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS2_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS3_0.CFG_BIT_MAP_INDEX_CS3_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS3_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS3_1.CFG_BIT_MAP_INDEX_CS3_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS3_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS4_0.CFG_BIT_MAP_INDEX_CS4_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS4_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS4_1.CFG_BIT_MAP_INDEX_CS4_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS4_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS5_0.CFG_BIT_MAP_INDEX_CS5_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS5_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS5_1.CFG_BIT_MAP_INDEX_CS5_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS5_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS6_0.CFG_BIT_MAP_INDEX_CS6_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS6_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS6_1.CFG_BIT_MAP_INDEX_CS6_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS6_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS7_0.CFG_BIT_MAP_INDEX_CS7_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS7_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS7_1.CFG_BIT_MAP_INDEX_CS7_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS7_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS8_0.CFG_BIT_MAP_INDEX_CS8_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS8_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS8_1.CFG_BIT_MAP_INDEX_CS8_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS8_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS9_0.CFG_BIT_MAP_INDEX_CS9_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS9_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS9_1.CFG_BIT_MAP_INDEX_CS9_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS9_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS10_0.CFG_BIT_MAP_INDEX_CS10_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS10_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS10_1.CFG_BIT_MAP_INDEX_CS10_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS10_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS11_0.CFG_BIT_MAP_INDEX_CS11_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS11_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS11_1.CFG_BIT_MAP_INDEX_CS11_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS11_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS12_0.CFG_BIT_MAP_INDEX_CS12_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS12_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS12_1.CFG_BIT_MAP_INDEX_CS12_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS12_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS13_0.CFG_BIT_MAP_INDEX_CS13_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS13_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS13_1.CFG_BIT_MAP_INDEX_CS13_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS13_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS14_0.CFG_BIT_MAP_INDEX_CS14_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS14_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS14_1.CFG_BIT_MAP_INDEX_CS14_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS14_1; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS15_0.CFG_BIT_MAP_INDEX_CS15_0 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS15_0; DDRCFG->MC_BASE1.CFG_BIT_MAP_INDEX_CS15_1.CFG_BIT_MAP_INDEX_CS15_1 =\ LIBERO_SETTING_CFG_BIT_MAP_INDEX_CS15_1; DDRCFG->MC_BASE1.CFG_NUM_LOGICAL_RANKS_PER_3DS.CFG_NUM_LOGICAL_RANKS_PER_3DS =\ LIBERO_SETTING_CFG_NUM_LOGICAL_RANKS_PER_3DS; DDRCFG->MC_BASE1.CFG_RFC_DLR1.CFG_RFC_DLR1 = LIBERO_SETTING_CFG_RFC_DLR1; DDRCFG->MC_BASE1.CFG_RFC_DLR2.CFG_RFC_DLR2 = LIBERO_SETTING_CFG_RFC_DLR2; DDRCFG->MC_BASE1.CFG_RFC_DLR4.CFG_RFC_DLR4 = LIBERO_SETTING_CFG_RFC_DLR4; DDRCFG->MC_BASE1.CFG_RRD_DLR.CFG_RRD_DLR = LIBERO_SETTING_CFG_RRD_DLR; DDRCFG->MC_BASE1.CFG_FAW_DLR.CFG_FAW_DLR = LIBERO_SETTING_CFG_FAW_DLR; DDRCFG->MC_BASE1.CFG_ADVANCE_ACTIVATE_READY.CFG_ADVANCE_ACTIVATE_READY =\ LIBERO_SETTING_CFG_ADVANCE_ACTIVATE_READY; DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N =\ LIBERO_SETTING_CTRLR_SOFT_RESET_N; DDRCFG->MC_BASE2.CFG_LOOKAHEAD_PCH.CFG_LOOKAHEAD_PCH =\ LIBERO_SETTING_CFG_LOOKAHEAD_PCH; DDRCFG->MC_BASE2.CFG_LOOKAHEAD_ACT.CFG_LOOKAHEAD_ACT =\ LIBERO_SETTING_CFG_LOOKAHEAD_ACT; DDRCFG->MC_BASE2.INIT_AUTOINIT_DISABLE.INIT_AUTOINIT_DISABLE =\ LIBERO_SETTING_INIT_AUTOINIT_DISABLE; DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET =\ LIBERO_SETTING_INIT_FORCE_RESET; DDRCFG->MC_BASE2.INIT_GEARDOWN_EN.INIT_GEARDOWN_EN =\ LIBERO_SETTING_INIT_GEARDOWN_EN; DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE =\ LIBERO_SETTING_INIT_DISABLE_CKE; DDRCFG->MC_BASE2.INIT_CS.INIT_CS = LIBERO_SETTING_INIT_CS; DDRCFG->MC_BASE2.INIT_PRECHARGE_ALL.INIT_PRECHARGE_ALL =\ LIBERO_SETTING_INIT_PRECHARGE_ALL; DDRCFG->MC_BASE2.INIT_REFRESH.INIT_REFRESH = LIBERO_SETTING_INIT_REFRESH; DDRCFG->MC_BASE2.INIT_ZQ_CAL_REQ.INIT_ZQ_CAL_REQ =\ LIBERO_SETTING_INIT_ZQ_CAL_REQ; DDRCFG->MC_BASE2.CFG_BL.CFG_BL = LIBERO_SETTING_CFG_BL; DDRCFG->MC_BASE2.CTRLR_INIT.CTRLR_INIT = LIBERO_SETTING_CTRLR_INIT; DDRCFG->MC_BASE2.CFG_AUTO_REF_EN.CFG_AUTO_REF_EN =\ LIBERO_SETTING_CFG_AUTO_REF_EN; DDRCFG->MC_BASE2.CFG_RAS.CFG_RAS = LIBERO_SETTING_CFG_RAS; DDRCFG->MC_BASE2.CFG_RCD.CFG_RCD = LIBERO_SETTING_CFG_RCD; DDRCFG->MC_BASE2.CFG_RRD.CFG_RRD = LIBERO_SETTING_CFG_RRD; DDRCFG->MC_BASE2.CFG_RP.CFG_RP = LIBERO_SETTING_CFG_RP; DDRCFG->MC_BASE2.CFG_RC.CFG_RC = LIBERO_SETTING_CFG_RC; DDRCFG->MC_BASE2.CFG_FAW.CFG_FAW = LIBERO_SETTING_CFG_FAW; DDRCFG->MC_BASE2.CFG_RFC.CFG_RFC = LIBERO_SETTING_CFG_RFC; DDRCFG->MC_BASE2.CFG_RTP.CFG_RTP = LIBERO_SETTING_CFG_RTP; DDRCFG->MC_BASE2.CFG_WR.CFG_WR = LIBERO_SETTING_CFG_WR; DDRCFG->MC_BASE2.CFG_WTR.CFG_WTR = LIBERO_SETTING_CFG_WTR; DDRCFG->MC_BASE2.CFG_PASR.CFG_PASR = LIBERO_SETTING_CFG_PASR; DDRCFG->MC_BASE2.CFG_XP.CFG_XP = LIBERO_SETTING_CFG_XP; DDRCFG->MC_BASE2.CFG_XSR.CFG_XSR = LIBERO_SETTING_CFG_XSR; DDRCFG->MC_BASE2.CFG_CL.CFG_CL = LIBERO_SETTING_CFG_CL; DDRCFG->MC_BASE2.CFG_READ_TO_WRITE.CFG_READ_TO_WRITE =\ LIBERO_SETTING_CFG_READ_TO_WRITE; DDRCFG->MC_BASE2.CFG_WRITE_TO_WRITE.CFG_WRITE_TO_WRITE =\ LIBERO_SETTING_CFG_WRITE_TO_WRITE; DDRCFG->MC_BASE2.CFG_READ_TO_READ.CFG_READ_TO_READ =\ LIBERO_SETTING_CFG_READ_TO_READ; DDRCFG->MC_BASE2.CFG_WRITE_TO_READ.CFG_WRITE_TO_READ =\ LIBERO_SETTING_CFG_WRITE_TO_READ; DDRCFG->MC_BASE2.CFG_READ_TO_WRITE_ODT.CFG_READ_TO_WRITE_ODT =\ LIBERO_SETTING_CFG_READ_TO_WRITE_ODT; DDRCFG->MC_BASE2.CFG_WRITE_TO_WRITE_ODT.CFG_WRITE_TO_WRITE_ODT =\ LIBERO_SETTING_CFG_WRITE_TO_WRITE_ODT; DDRCFG->MC_BASE2.CFG_READ_TO_READ_ODT.CFG_READ_TO_READ_ODT =\ LIBERO_SETTING_CFG_READ_TO_READ_ODT; DDRCFG->MC_BASE2.CFG_WRITE_TO_READ_ODT.CFG_WRITE_TO_READ_ODT =\ LIBERO_SETTING_CFG_WRITE_TO_READ_ODT; DDRCFG->MC_BASE2.CFG_MIN_READ_IDLE.CFG_MIN_READ_IDLE =\ LIBERO_SETTING_CFG_MIN_READ_IDLE; DDRCFG->MC_BASE2.CFG_MRD.CFG_MRD = LIBERO_SETTING_CFG_MRD; DDRCFG->MC_BASE2.CFG_BT.CFG_BT = LIBERO_SETTING_CFG_BT; DDRCFG->MC_BASE2.CFG_DS.CFG_DS = LIBERO_SETTING_CFG_DS; DDRCFG->MC_BASE2.CFG_QOFF.CFG_QOFF = LIBERO_SETTING_CFG_QOFF; DDRCFG->MC_BASE2.CFG_RTT.CFG_RTT = LIBERO_SETTING_CFG_RTT; DDRCFG->MC_BASE2.CFG_DLL_DISABLE.CFG_DLL_DISABLE =\ LIBERO_SETTING_CFG_DLL_DISABLE; DDRCFG->MC_BASE2.CFG_REF_PER.CFG_REF_PER = LIBERO_SETTING_CFG_REF_PER; DDRCFG->MC_BASE2.CFG_STARTUP_DELAY.CFG_STARTUP_DELAY =\ LIBERO_SETTING_CFG_STARTUP_DELAY; DDRCFG->MC_BASE2.CFG_MEM_COLBITS.CFG_MEM_COLBITS =\ LIBERO_SETTING_CFG_MEM_COLBITS; DDRCFG->MC_BASE2.CFG_MEM_ROWBITS.CFG_MEM_ROWBITS =\ LIBERO_SETTING_CFG_MEM_ROWBITS; DDRCFG->MC_BASE2.CFG_MEM_BANKBITS.CFG_MEM_BANKBITS =\ LIBERO_SETTING_CFG_MEM_BANKBITS; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS0.CFG_ODT_RD_MAP_CS0 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS0; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS1.CFG_ODT_RD_MAP_CS1 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS1; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS2.CFG_ODT_RD_MAP_CS2 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS2; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS3.CFG_ODT_RD_MAP_CS3 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS3; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS4.CFG_ODT_RD_MAP_CS4 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS4; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS5.CFG_ODT_RD_MAP_CS5 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS5; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS6.CFG_ODT_RD_MAP_CS6 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS6; DDRCFG->MC_BASE2.CFG_ODT_RD_MAP_CS7.CFG_ODT_RD_MAP_CS7 =\ LIBERO_SETTING_CFG_ODT_RD_MAP_CS7; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS0.CFG_ODT_WR_MAP_CS0 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS0; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS1.CFG_ODT_WR_MAP_CS1 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS1; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS2.CFG_ODT_WR_MAP_CS2 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS2; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS3.CFG_ODT_WR_MAP_CS3 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS3; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS4.CFG_ODT_WR_MAP_CS4 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS4; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS5.CFG_ODT_WR_MAP_CS5 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS5; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS6.CFG_ODT_WR_MAP_CS6 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS6; DDRCFG->MC_BASE2.CFG_ODT_WR_MAP_CS7.CFG_ODT_WR_MAP_CS7 =\ LIBERO_SETTING_CFG_ODT_WR_MAP_CS7; DDRCFG->MC_BASE2.CFG_ODT_RD_TURN_ON.CFG_ODT_RD_TURN_ON =\ LIBERO_SETTING_CFG_ODT_RD_TURN_ON; DDRCFG->MC_BASE2.CFG_ODT_WR_TURN_ON.CFG_ODT_WR_TURN_ON =\ LIBERO_SETTING_CFG_ODT_WR_TURN_ON; DDRCFG->MC_BASE2.CFG_ODT_RD_TURN_OFF.CFG_ODT_RD_TURN_OFF =\ LIBERO_SETTING_CFG_ODT_RD_TURN_OFF; DDRCFG->MC_BASE2.CFG_ODT_WR_TURN_OFF.CFG_ODT_WR_TURN_OFF =\ LIBERO_SETTING_CFG_ODT_WR_TURN_OFF; DDRCFG->MC_BASE2.CFG_EMR3.CFG_EMR3 = LIBERO_SETTING_CFG_EMR3; DDRCFG->MC_BASE2.CFG_TWO_T.CFG_TWO_T = LIBERO_SETTING_CFG_TWO_T; DDRCFG->MC_BASE2.CFG_TWO_T_SEL_CYCLE.CFG_TWO_T_SEL_CYCLE =\ LIBERO_SETTING_CFG_TWO_T_SEL_CYCLE; DDRCFG->MC_BASE2.CFG_REGDIMM.CFG_REGDIMM = LIBERO_SETTING_CFG_REGDIMM; DDRCFG->MC_BASE2.CFG_MOD.CFG_MOD = LIBERO_SETTING_CFG_MOD; DDRCFG->MC_BASE2.CFG_XS.CFG_XS = LIBERO_SETTING_CFG_XS; DDRCFG->MC_BASE2.CFG_XSDLL.CFG_XSDLL = LIBERO_SETTING_CFG_XSDLL; DDRCFG->MC_BASE2.CFG_XPR.CFG_XPR = LIBERO_SETTING_CFG_XPR; DDRCFG->MC_BASE2.CFG_AL_MODE.CFG_AL_MODE = LIBERO_SETTING_CFG_AL_MODE; DDRCFG->MC_BASE2.CFG_CWL.CFG_CWL = LIBERO_SETTING_CFG_CWL; DDRCFG->MC_BASE2.CFG_BL_MODE.CFG_BL_MODE = LIBERO_SETTING_CFG_BL_MODE; DDRCFG->MC_BASE2.CFG_TDQS.CFG_TDQS = LIBERO_SETTING_CFG_TDQS; DDRCFG->MC_BASE2.CFG_RTT_WR.CFG_RTT_WR = LIBERO_SETTING_CFG_RTT_WR; DDRCFG->MC_BASE2.CFG_LP_ASR.CFG_LP_ASR = LIBERO_SETTING_CFG_LP_ASR; DDRCFG->MC_BASE2.CFG_AUTO_SR.CFG_AUTO_SR = LIBERO_SETTING_CFG_AUTO_SR; DDRCFG->MC_BASE2.CFG_SRT.CFG_SRT = LIBERO_SETTING_CFG_SRT; DDRCFG->MC_BASE2.CFG_ADDR_MIRROR.CFG_ADDR_MIRROR =\ LIBERO_SETTING_CFG_ADDR_MIRROR; DDRCFG->MC_BASE2.CFG_ZQ_CAL_TYPE.CFG_ZQ_CAL_TYPE =\ LIBERO_SETTING_CFG_ZQ_CAL_TYPE; DDRCFG->MC_BASE2.CFG_ZQ_CAL_PER.CFG_ZQ_CAL_PER =\ LIBERO_SETTING_CFG_ZQ_CAL_PER; DDRCFG->MC_BASE2.CFG_AUTO_ZQ_CAL_EN.CFG_AUTO_ZQ_CAL_EN =\ LIBERO_SETTING_CFG_AUTO_ZQ_CAL_EN; DDRCFG->MC_BASE2.CFG_MEMORY_TYPE.CFG_MEMORY_TYPE =\ LIBERO_SETTING_CFG_MEMORY_TYPE; DDRCFG->MC_BASE2.CFG_ONLY_SRANK_CMDS.CFG_ONLY_SRANK_CMDS =\ LIBERO_SETTING_CFG_ONLY_SRANK_CMDS; DDRCFG->MC_BASE2.CFG_NUM_RANKS.CFG_NUM_RANKS =\ LIBERO_SETTING_CFG_NUM_RANKS; DDRCFG->MC_BASE2.CFG_QUAD_RANK.CFG_QUAD_RANK =\ LIBERO_SETTING_CFG_QUAD_RANK; DDRCFG->MC_BASE2.CFG_EARLY_RANK_TO_WR_START.CFG_EARLY_RANK_TO_WR_START =\ LIBERO_SETTING_CFG_EARLY_RANK_TO_WR_START; DDRCFG->MC_BASE2.CFG_EARLY_RANK_TO_RD_START.CFG_EARLY_RANK_TO_RD_START =\ LIBERO_SETTING_CFG_EARLY_RANK_TO_RD_START; DDRCFG->MC_BASE2.CFG_PASR_BANK.CFG_PASR_BANK =\ LIBERO_SETTING_CFG_PASR_BANK; DDRCFG->MC_BASE2.CFG_PASR_SEG.CFG_PASR_SEG = LIBERO_SETTING_CFG_PASR_SEG; DDRCFG->MC_BASE2.INIT_MRR_MODE.INIT_MRR_MODE =\ LIBERO_SETTING_INIT_MRR_MODE; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ =\ LIBERO_SETTING_INIT_MR_W_REQ; DDRCFG->MC_BASE2.INIT_MR_ADDR.INIT_MR_ADDR = LIBERO_SETTING_INIT_MR_ADDR; DDRCFG->MC_BASE2.INIT_MR_WR_DATA.INIT_MR_WR_DATA =\ LIBERO_SETTING_INIT_MR_WR_DATA; DDRCFG->MC_BASE2.INIT_MR_WR_MASK.INIT_MR_WR_MASK =\ LIBERO_SETTING_INIT_MR_WR_MASK; DDRCFG->MC_BASE2.INIT_NOP.INIT_NOP = LIBERO_SETTING_INIT_NOP; DDRCFG->MC_BASE2.CFG_INIT_DURATION.CFG_INIT_DURATION =\ LIBERO_SETTING_CFG_INIT_DURATION; DDRCFG->MC_BASE2.CFG_ZQINIT_CAL_DURATION.CFG_ZQINIT_CAL_DURATION =\ LIBERO_SETTING_CFG_ZQINIT_CAL_DURATION; DDRCFG->MC_BASE2.CFG_ZQ_CAL_L_DURATION.CFG_ZQ_CAL_L_DURATION =\ LIBERO_SETTING_CFG_ZQ_CAL_L_DURATION; DDRCFG->MC_BASE2.CFG_ZQ_CAL_S_DURATION.CFG_ZQ_CAL_S_DURATION =\ LIBERO_SETTING_CFG_ZQ_CAL_S_DURATION; DDRCFG->MC_BASE2.CFG_ZQ_CAL_R_DURATION.CFG_ZQ_CAL_R_DURATION =\ LIBERO_SETTING_CFG_ZQ_CAL_R_DURATION; DDRCFG->MC_BASE2.CFG_MRR.CFG_MRR = LIBERO_SETTING_CFG_MRR; DDRCFG->MC_BASE2.CFG_MRW.CFG_MRW = LIBERO_SETTING_CFG_MRW; DDRCFG->MC_BASE2.CFG_ODT_POWERDOWN.CFG_ODT_POWERDOWN =\ LIBERO_SETTING_CFG_ODT_POWERDOWN; DDRCFG->MC_BASE2.CFG_WL.CFG_WL = LIBERO_SETTING_CFG_WL; DDRCFG->MC_BASE2.CFG_RL.CFG_RL = LIBERO_SETTING_CFG_RL; DDRCFG->MC_BASE2.CFG_CAL_READ_PERIOD.CFG_CAL_READ_PERIOD =\ LIBERO_SETTING_CFG_CAL_READ_PERIOD; DDRCFG->MC_BASE2.CFG_NUM_CAL_READS.CFG_NUM_CAL_READS =\ LIBERO_SETTING_CFG_NUM_CAL_READS; DDRCFG->MC_BASE2.INIT_SELF_REFRESH.INIT_SELF_REFRESH =\ LIBERO_SETTING_INIT_SELF_REFRESH; DDRCFG->MC_BASE2.INIT_POWER_DOWN.INIT_POWER_DOWN =\ LIBERO_SETTING_INIT_POWER_DOWN; DDRCFG->MC_BASE2.INIT_FORCE_WRITE.INIT_FORCE_WRITE =\ LIBERO_SETTING_INIT_FORCE_WRITE; DDRCFG->MC_BASE2.INIT_FORCE_WRITE_CS.INIT_FORCE_WRITE_CS =\ LIBERO_SETTING_INIT_FORCE_WRITE_CS; DDRCFG->MC_BASE2.CFG_CTRLR_INIT_DISABLE.CFG_CTRLR_INIT_DISABLE =\ LIBERO_SETTING_CFG_CTRLR_INIT_DISABLE; DDRCFG->MC_BASE2.INIT_RDIMM_COMPLETE.INIT_RDIMM_COMPLETE =\ LIBERO_SETTING_INIT_RDIMM_COMPLETE; DDRCFG->MC_BASE2.CFG_RDIMM_LAT.CFG_RDIMM_LAT =\ LIBERO_SETTING_CFG_RDIMM_LAT; DDRCFG->MC_BASE2.CFG_RDIMM_BSIDE_INVERT.CFG_RDIMM_BSIDE_INVERT =\ LIBERO_SETTING_CFG_RDIMM_BSIDE_INVERT; DDRCFG->MC_BASE2.CFG_LRDIMM.CFG_LRDIMM = LIBERO_SETTING_CFG_LRDIMM; DDRCFG->MC_BASE2.INIT_MEMORY_RESET_MASK.INIT_MEMORY_RESET_MASK =\ LIBERO_SETTING_INIT_MEMORY_RESET_MASK; DDRCFG->MC_BASE2.CFG_RD_PREAMB_TOGGLE.CFG_RD_PREAMB_TOGGLE =\ LIBERO_SETTING_CFG_RD_PREAMB_TOGGLE; DDRCFG->MC_BASE2.CFG_RD_POSTAMBLE.CFG_RD_POSTAMBLE =\ LIBERO_SETTING_CFG_RD_POSTAMBLE; DDRCFG->MC_BASE2.CFG_PU_CAL.CFG_PU_CAL = LIBERO_SETTING_CFG_PU_CAL; DDRCFG->MC_BASE2.CFG_DQ_ODT.CFG_DQ_ODT = LIBERO_SETTING_CFG_DQ_ODT; DDRCFG->MC_BASE2.CFG_CA_ODT.CFG_CA_ODT = LIBERO_SETTING_CFG_CA_ODT; DDRCFG->MC_BASE2.CFG_ZQLATCH_DURATION.CFG_ZQLATCH_DURATION =\ LIBERO_SETTING_CFG_ZQLATCH_DURATION; DDRCFG->MC_BASE2.INIT_CAL_SELECT.INIT_CAL_SELECT =\ LIBERO_SETTING_INIT_CAL_SELECT; DDRCFG->MC_BASE2.INIT_CAL_L_R_REQ.INIT_CAL_L_R_REQ =\ LIBERO_SETTING_INIT_CAL_L_R_REQ; DDRCFG->MC_BASE2.INIT_CAL_L_B_SIZE.INIT_CAL_L_B_SIZE =\ LIBERO_SETTING_INIT_CAL_L_B_SIZE; DDRCFG->MC_BASE2.INIT_RWFIFO.INIT_RWFIFO = LIBERO_SETTING_INIT_RWFIFO; DDRCFG->MC_BASE2.INIT_RD_DQCAL.INIT_RD_DQCAL =\ LIBERO_SETTING_INIT_RD_DQCAL; DDRCFG->MC_BASE2.INIT_START_DQSOSC.INIT_START_DQSOSC =\ LIBERO_SETTING_INIT_START_DQSOSC; DDRCFG->MC_BASE2.INIT_STOP_DQSOSC.INIT_STOP_DQSOSC =\ LIBERO_SETTING_INIT_STOP_DQSOSC; DDRCFG->MC_BASE2.INIT_ZQ_CAL_START.INIT_ZQ_CAL_START =\ LIBERO_SETTING_INIT_ZQ_CAL_START; DDRCFG->MC_BASE2.CFG_WR_POSTAMBLE.CFG_WR_POSTAMBLE =\ LIBERO_SETTING_CFG_WR_POSTAMBLE; DDRCFG->MC_BASE2.INIT_CAL_L_ADDR_0.INIT_CAL_L_ADDR_0 =\ LIBERO_SETTING_INIT_CAL_L_ADDR_0; DDRCFG->MC_BASE2.INIT_CAL_L_ADDR_1.INIT_CAL_L_ADDR_1 =\ LIBERO_SETTING_INIT_CAL_L_ADDR_1; DDRCFG->MC_BASE2.CFG_CTRLUPD_TRIG.CFG_CTRLUPD_TRIG =\ LIBERO_SETTING_CFG_CTRLUPD_TRIG; DDRCFG->MC_BASE2.CFG_CTRLUPD_START_DELAY.CFG_CTRLUPD_START_DELAY =\ LIBERO_SETTING_CFG_CTRLUPD_START_DELAY; DDRCFG->MC_BASE2.CFG_DFI_T_CTRLUPD_MAX.CFG_DFI_T_CTRLUPD_MAX =\ LIBERO_SETTING_CFG_DFI_T_CTRLUPD_MAX; DDRCFG->MC_BASE2.CFG_CTRLR_BUSY_SEL.CFG_CTRLR_BUSY_SEL =\ LIBERO_SETTING_CFG_CTRLR_BUSY_SEL; DDRCFG->MC_BASE2.CFG_CTRLR_BUSY_VALUE.CFG_CTRLR_BUSY_VALUE =\ LIBERO_SETTING_CFG_CTRLR_BUSY_VALUE; DDRCFG->MC_BASE2.CFG_CTRLR_BUSY_TURN_OFF_DELAY.CFG_CTRLR_BUSY_TURN_OFF_DELAY =\ LIBERO_SETTING_CFG_CTRLR_BUSY_TURN_OFF_DELAY; DDRCFG->MC_BASE2.CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW.CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW =\ LIBERO_SETTING_CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW; DDRCFG->MC_BASE2.CFG_CTRLR_BUSY_RESTART_HOLDOFF.CFG_CTRLR_BUSY_RESTART_HOLDOFF =\ LIBERO_SETTING_CFG_CTRLR_BUSY_RESTART_HOLDOFF; DDRCFG->MC_BASE2.CFG_PARITY_RDIMM_DELAY.CFG_PARITY_RDIMM_DELAY =\ LIBERO_SETTING_CFG_PARITY_RDIMM_DELAY; DDRCFG->MC_BASE2.CFG_CTRLR_BUSY_ENABLE.CFG_CTRLR_BUSY_ENABLE =\ LIBERO_SETTING_CFG_CTRLR_BUSY_ENABLE; DDRCFG->MC_BASE2.CFG_ASYNC_ODT.CFG_ASYNC_ODT =\ LIBERO_SETTING_CFG_ASYNC_ODT; DDRCFG->MC_BASE2.CFG_ZQ_CAL_DURATION.CFG_ZQ_CAL_DURATION =\ LIBERO_SETTING_CFG_ZQ_CAL_DURATION; DDRCFG->MC_BASE2.CFG_MRRI.CFG_MRRI = LIBERO_SETTING_CFG_MRRI; DDRCFG->MC_BASE2.INIT_ODT_FORCE_EN.INIT_ODT_FORCE_EN =\ LIBERO_SETTING_INIT_ODT_FORCE_EN; DDRCFG->MC_BASE2.INIT_ODT_FORCE_RANK.INIT_ODT_FORCE_RANK =\ LIBERO_SETTING_INIT_ODT_FORCE_RANK; DDRCFG->MC_BASE2.CFG_PHYUPD_ACK_DELAY.CFG_PHYUPD_ACK_DELAY =\ LIBERO_SETTING_CFG_PHYUPD_ACK_DELAY; DDRCFG->MC_BASE2.CFG_MIRROR_X16_BG0_BG1.CFG_MIRROR_X16_BG0_BG1 =\ LIBERO_SETTING_CFG_MIRROR_X16_BG0_BG1; DDRCFG->MC_BASE2.INIT_PDA_MR_W_REQ.INIT_PDA_MR_W_REQ =\ LIBERO_SETTING_INIT_PDA_MR_W_REQ; DDRCFG->MC_BASE2.INIT_PDA_NIBBLE_SELECT.INIT_PDA_NIBBLE_SELECT =\ LIBERO_SETTING_INIT_PDA_NIBBLE_SELECT; DDRCFG->MC_BASE2.CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH.CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH =\ LIBERO_SETTING_CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH; DDRCFG->MC_BASE2.CFG_CKSRE.CFG_CKSRE = LIBERO_SETTING_CFG_CKSRE; DDRCFG->MC_BASE2.CFG_CKSRX.CFG_CKSRX = LIBERO_SETTING_CFG_CKSRX; DDRCFG->MC_BASE2.CFG_RCD_STAB.CFG_RCD_STAB = LIBERO_SETTING_CFG_RCD_STAB; DDRCFG->MC_BASE2.CFG_DFI_T_CTRL_DELAY.CFG_DFI_T_CTRL_DELAY =\ LIBERO_SETTING_CFG_DFI_T_CTRL_DELAY; DDRCFG->MC_BASE2.CFG_DFI_T_DRAM_CLK_ENABLE.CFG_DFI_T_DRAM_CLK_ENABLE =\ LIBERO_SETTING_CFG_DFI_T_DRAM_CLK_ENABLE; DDRCFG->MC_BASE2.CFG_IDLE_TIME_TO_SELF_REFRESH.CFG_IDLE_TIME_TO_SELF_REFRESH =\ LIBERO_SETTING_CFG_IDLE_TIME_TO_SELF_REFRESH; DDRCFG->MC_BASE2.CFG_IDLE_TIME_TO_POWER_DOWN.CFG_IDLE_TIME_TO_POWER_DOWN =\ LIBERO_SETTING_CFG_IDLE_TIME_TO_POWER_DOWN; DDRCFG->MC_BASE2.CFG_BURST_RW_REFRESH_HOLDOFF.CFG_BURST_RW_REFRESH_HOLDOFF =\ LIBERO_SETTING_CFG_BURST_RW_REFRESH_HOLDOFF; DDRCFG->MC_BASE2.CFG_BG_INTERLEAVE.CFG_BG_INTERLEAVE =\ LIBERO_SETTING_CFG_BG_INTERLEAVE; DDRCFG->MC_BASE2.CFG_REFRESH_DURING_PHY_TRAINING.CFG_REFRESH_DURING_PHY_TRAINING =\ LIBERO_SETTING_CFG_REFRESH_DURING_PHY_TRAINING; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P0.CFG_STARVE_TIMEOUT_P0 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P0; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P1.CFG_STARVE_TIMEOUT_P1 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P1; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P2.CFG_STARVE_TIMEOUT_P2 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P2; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P3.CFG_STARVE_TIMEOUT_P3 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P3; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P4.CFG_STARVE_TIMEOUT_P4 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P4; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P5.CFG_STARVE_TIMEOUT_P5 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P5; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P6.CFG_STARVE_TIMEOUT_P6 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P6; DDRCFG->MPFE.CFG_STARVE_TIMEOUT_P7.CFG_STARVE_TIMEOUT_P7 =\ LIBERO_SETTING_CFG_STARVE_TIMEOUT_P7; DDRCFG->REORDER.CFG_REORDER_EN.CFG_REORDER_EN =\ LIBERO_SETTING_CFG_REORDER_EN; DDRCFG->REORDER.CFG_REORDER_QUEUE_EN.CFG_REORDER_QUEUE_EN =\ LIBERO_SETTING_CFG_REORDER_QUEUE_EN; DDRCFG->REORDER.CFG_INTRAPORT_REORDER_EN.CFG_INTRAPORT_REORDER_EN =\ LIBERO_SETTING_CFG_INTRAPORT_REORDER_EN; DDRCFG->REORDER.CFG_MAINTAIN_COHERENCY.CFG_MAINTAIN_COHERENCY =\ LIBERO_SETTING_CFG_MAINTAIN_COHERENCY; DDRCFG->REORDER.CFG_Q_AGE_LIMIT.CFG_Q_AGE_LIMIT =\ LIBERO_SETTING_CFG_Q_AGE_LIMIT; DDRCFG->REORDER.CFG_RO_CLOSED_PAGE_POLICY.CFG_RO_CLOSED_PAGE_POLICY =\ LIBERO_SETTING_CFG_RO_CLOSED_PAGE_POLICY; DDRCFG->REORDER.CFG_REORDER_RW_ONLY.CFG_REORDER_RW_ONLY =\ LIBERO_SETTING_CFG_REORDER_RW_ONLY; DDRCFG->REORDER.CFG_RO_PRIORITY_EN.CFG_RO_PRIORITY_EN =\ LIBERO_SETTING_CFG_RO_PRIORITY_EN; DDRCFG->RMW.CFG_DM_EN.CFG_DM_EN = LIBERO_SETTING_CFG_DM_EN; DDRCFG->RMW.CFG_RMW_EN.CFG_RMW_EN = LIBERO_SETTING_CFG_RMW_EN; DDRCFG->ECC.CFG_ECC_CORRECTION_EN.CFG_ECC_CORRECTION_EN =\ LIBERO_SETTING_CFG_ECC_CORRECTION_EN; DDRCFG->ECC.CFG_ECC_BYPASS.CFG_ECC_BYPASS = LIBERO_SETTING_CFG_ECC_BYPASS; DDRCFG->ECC.INIT_WRITE_DATA_1B_ECC_ERROR_GEN.INIT_WRITE_DATA_1B_ECC_ERROR_GEN =\ LIBERO_SETTING_INIT_WRITE_DATA_1B_ECC_ERROR_GEN; DDRCFG->ECC.INIT_WRITE_DATA_2B_ECC_ERROR_GEN.INIT_WRITE_DATA_2B_ECC_ERROR_GEN =\ LIBERO_SETTING_INIT_WRITE_DATA_2B_ECC_ERROR_GEN; DDRCFG->ECC.CFG_ECC_1BIT_INT_THRESH.CFG_ECC_1BIT_INT_THRESH =\ LIBERO_SETTING_CFG_ECC_1BIT_INT_THRESH; DDRCFG->READ_CAPT.INIT_READ_CAPTURE_ADDR.INIT_READ_CAPTURE_ADDR =\ LIBERO_SETTING_INIT_READ_CAPTURE_ADDR; DDRCFG->MTA.CFG_ERROR_GROUP_SEL.CFG_ERROR_GROUP_SEL =\ LIBERO_SETTING_CFG_ERROR_GROUP_SEL; DDRCFG->MTA.CFG_DATA_SEL.CFG_DATA_SEL = LIBERO_SETTING_CFG_DATA_SEL; DDRCFG->MTA.CFG_TRIG_MODE.CFG_TRIG_MODE = LIBERO_SETTING_CFG_TRIG_MODE; DDRCFG->MTA.CFG_POST_TRIG_CYCS.CFG_POST_TRIG_CYCS =\ LIBERO_SETTING_CFG_POST_TRIG_CYCS; DDRCFG->MTA.CFG_TRIG_MASK.CFG_TRIG_MASK = LIBERO_SETTING_CFG_TRIG_MASK; DDRCFG->MTA.CFG_EN_MASK.CFG_EN_MASK = LIBERO_SETTING_CFG_EN_MASK; DDRCFG->MTA.MTC_ACQ_ADDR.MTC_ACQ_ADDR = LIBERO_SETTING_MTC_ACQ_ADDR; DDRCFG->MTA.CFG_TRIG_MT_ADDR_0.CFG_TRIG_MT_ADDR_0 =\ LIBERO_SETTING_CFG_TRIG_MT_ADDR_0; DDRCFG->MTA.CFG_TRIG_MT_ADDR_1.CFG_TRIG_MT_ADDR_1 =\ LIBERO_SETTING_CFG_TRIG_MT_ADDR_1; DDRCFG->MTA.CFG_TRIG_ERR_MASK_0.CFG_TRIG_ERR_MASK_0 =\ LIBERO_SETTING_CFG_TRIG_ERR_MASK_0; DDRCFG->MTA.CFG_TRIG_ERR_MASK_1.CFG_TRIG_ERR_MASK_1 =\ LIBERO_SETTING_CFG_TRIG_ERR_MASK_1; DDRCFG->MTA.CFG_TRIG_ERR_MASK_2.CFG_TRIG_ERR_MASK_2 =\ LIBERO_SETTING_CFG_TRIG_ERR_MASK_2; DDRCFG->MTA.CFG_TRIG_ERR_MASK_3.CFG_TRIG_ERR_MASK_3 =\ LIBERO_SETTING_CFG_TRIG_ERR_MASK_3; DDRCFG->MTA.CFG_TRIG_ERR_MASK_4.CFG_TRIG_ERR_MASK_4 =\ LIBERO_SETTING_CFG_TRIG_ERR_MASK_4; DDRCFG->MTA.MTC_ACQ_WR_DATA_0.MTC_ACQ_WR_DATA_0 =\ LIBERO_SETTING_MTC_ACQ_WR_DATA_0; DDRCFG->MTA.MTC_ACQ_WR_DATA_1.MTC_ACQ_WR_DATA_1 =\ LIBERO_SETTING_MTC_ACQ_WR_DATA_1; DDRCFG->MTA.MTC_ACQ_WR_DATA_2.MTC_ACQ_WR_DATA_2 =\ LIBERO_SETTING_MTC_ACQ_WR_DATA_2; DDRCFG->MTA.CFG_PRE_TRIG_CYCS.CFG_PRE_TRIG_CYCS =\ LIBERO_SETTING_CFG_PRE_TRIG_CYCS; DDRCFG->MTA.CFG_DATA_SEL_FIRST_ERROR.CFG_DATA_SEL_FIRST_ERROR =\ LIBERO_SETTING_CFG_DATA_SEL_FIRST_ERROR; DDRCFG->DYN_WIDTH_ADJ.CFG_DQ_WIDTH.CFG_DQ_WIDTH =\ LIBERO_SETTING_CFG_DQ_WIDTH; DDRCFG->DYN_WIDTH_ADJ.CFG_ACTIVE_DQ_SEL.CFG_ACTIVE_DQ_SEL =\ LIBERO_SETTING_CFG_ACTIVE_DQ_SEL; DDRCFG->CA_PAR_ERR.INIT_CA_PARITY_ERROR_GEN_REQ.INIT_CA_PARITY_ERROR_GEN_REQ =\ LIBERO_SETTING_INIT_CA_PARITY_ERROR_GEN_REQ; DDRCFG->CA_PAR_ERR.INIT_CA_PARITY_ERROR_GEN_CMD.INIT_CA_PARITY_ERROR_GEN_CMD =\ LIBERO_SETTING_INIT_CA_PARITY_ERROR_GEN_CMD; DDRCFG->DFI.CFG_DFI_T_RDDATA_EN.CFG_DFI_T_RDDATA_EN =\ LIBERO_SETTING_CFG_DFI_T_RDDATA_EN; DDRCFG->DFI.CFG_DFI_T_PHY_RDLAT.CFG_DFI_T_PHY_RDLAT =\ LIBERO_SETTING_CFG_DFI_T_PHY_RDLAT; DDRCFG->DFI.CFG_DFI_T_PHY_WRLAT.CFG_DFI_T_PHY_WRLAT =\ LIBERO_SETTING_CFG_DFI_T_PHY_WRLAT; DDRCFG->DFI.CFG_DFI_PHYUPD_EN.CFG_DFI_PHYUPD_EN =\ LIBERO_SETTING_CFG_DFI_PHYUPD_EN; DDRCFG->DFI.INIT_DFI_LP_DATA_REQ.INIT_DFI_LP_DATA_REQ =\ LIBERO_SETTING_INIT_DFI_LP_DATA_REQ; DDRCFG->DFI.INIT_DFI_LP_CTRL_REQ.INIT_DFI_LP_CTRL_REQ =\ LIBERO_SETTING_INIT_DFI_LP_CTRL_REQ; DDRCFG->DFI.INIT_DFI_LP_WAKEUP.INIT_DFI_LP_WAKEUP =\ LIBERO_SETTING_INIT_DFI_LP_WAKEUP; DDRCFG->DFI.INIT_DFI_DRAM_CLK_DISABLE.INIT_DFI_DRAM_CLK_DISABLE =\ LIBERO_SETTING_INIT_DFI_DRAM_CLK_DISABLE; DDRCFG->DFI.CFG_DFI_DATA_BYTE_DISABLE.CFG_DFI_DATA_BYTE_DISABLE =\ LIBERO_SETTING_CFG_DFI_DATA_BYTE_DISABLE; DDRCFG->DFI.CFG_DFI_LVL_SEL.CFG_DFI_LVL_SEL =\ LIBERO_SETTING_CFG_DFI_LVL_SEL; DDRCFG->DFI.CFG_DFI_LVL_PERIODIC.CFG_DFI_LVL_PERIODIC =\ LIBERO_SETTING_CFG_DFI_LVL_PERIODIC; DDRCFG->DFI.CFG_DFI_LVL_PATTERN.CFG_DFI_LVL_PATTERN =\ LIBERO_SETTING_CFG_DFI_LVL_PATTERN; DDRCFG->DFI.PHY_DFI_INIT_START.PHY_DFI_INIT_START =\ LIBERO_SETTING_PHY_DFI_INIT_START; DDRCFG->AXI_IF.CFG_AXI_START_ADDRESS_AXI1_0.CFG_AXI_START_ADDRESS_AXI1_0 =\ LIBERO_SETTING_CFG_AXI_START_ADDRESS_AXI1_0; DDRCFG->AXI_IF.CFG_AXI_START_ADDRESS_AXI1_1.CFG_AXI_START_ADDRESS_AXI1_1 =\ LIBERO_SETTING_CFG_AXI_START_ADDRESS_AXI1_1; DDRCFG->AXI_IF.CFG_AXI_START_ADDRESS_AXI2_0.CFG_AXI_START_ADDRESS_AXI2_0 =\ LIBERO_SETTING_CFG_AXI_START_ADDRESS_AXI2_0; DDRCFG->AXI_IF.CFG_AXI_START_ADDRESS_AXI2_1.CFG_AXI_START_ADDRESS_AXI2_1 =\ LIBERO_SETTING_CFG_AXI_START_ADDRESS_AXI2_1; DDRCFG->AXI_IF.CFG_AXI_END_ADDRESS_AXI1_0.CFG_AXI_END_ADDRESS_AXI1_0 =\ LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI1_0; DDRCFG->AXI_IF.CFG_AXI_END_ADDRESS_AXI1_1.CFG_AXI_END_ADDRESS_AXI1_1 =\ LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI1_1; DDRCFG->AXI_IF.CFG_AXI_END_ADDRESS_AXI2_0.CFG_AXI_END_ADDRESS_AXI2_0 =\ LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI2_0; DDRCFG->AXI_IF.CFG_AXI_END_ADDRESS_AXI2_1.CFG_AXI_END_ADDRESS_AXI2_1 =\ LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI2_1; DDRCFG->AXI_IF.CFG_MEM_START_ADDRESS_AXI1_0.CFG_MEM_START_ADDRESS_AXI1_0 =\ LIBERO_SETTING_CFG_MEM_START_ADDRESS_AXI1_0; DDRCFG->AXI_IF.CFG_MEM_START_ADDRESS_AXI1_1.CFG_MEM_START_ADDRESS_AXI1_1 =\ LIBERO_SETTING_CFG_MEM_START_ADDRESS_AXI1_1; DDRCFG->AXI_IF.CFG_MEM_START_ADDRESS_AXI2_0.CFG_MEM_START_ADDRESS_AXI2_0 =\ LIBERO_SETTING_CFG_MEM_START_ADDRESS_AXI2_0; DDRCFG->AXI_IF.CFG_MEM_START_ADDRESS_AXI2_1.CFG_MEM_START_ADDRESS_AXI2_1 =\ LIBERO_SETTING_CFG_MEM_START_ADDRESS_AXI2_1; DDRCFG->AXI_IF.CFG_ENABLE_BUS_HOLD_AXI1.CFG_ENABLE_BUS_HOLD_AXI1 =\ LIBERO_SETTING_CFG_ENABLE_BUS_HOLD_AXI1; DDRCFG->AXI_IF.CFG_ENABLE_BUS_HOLD_AXI2.CFG_ENABLE_BUS_HOLD_AXI2 =\ LIBERO_SETTING_CFG_ENABLE_BUS_HOLD_AXI2; DDRCFG->AXI_IF.CFG_AXI_AUTO_PCH.CFG_AXI_AUTO_PCH =\ LIBERO_SETTING_CFG_AXI_AUTO_PCH; DDRCFG->csr_custom.PHY_RESET_CONTROL.PHY_RESET_CONTROL =\ LIBERO_SETTING_PHY_RESET_CONTROL; DDRCFG->csr_custom.PHY_RESET_CONTROL.PHY_RESET_CONTROL =\ (LIBERO_SETTING_PHY_RESET_CONTROL & ~0x8000UL); DDRCFG->csr_custom.PHY_PC_RANK.PHY_PC_RANK = LIBERO_SETTING_PHY_PC_RANK; DDRCFG->csr_custom.PHY_RANKS_TO_TRAIN.PHY_RANKS_TO_TRAIN =\ LIBERO_SETTING_PHY_RANKS_TO_TRAIN; DDRCFG->csr_custom.PHY_WRITE_REQUEST.PHY_WRITE_REQUEST =\ LIBERO_SETTING_PHY_WRITE_REQUEST; DDRCFG->csr_custom.PHY_READ_REQUEST.PHY_READ_REQUEST =\ LIBERO_SETTING_PHY_READ_REQUEST; DDRCFG->csr_custom.PHY_WRITE_LEVEL_DELAY.PHY_WRITE_LEVEL_DELAY =\ LIBERO_SETTING_PHY_WRITE_LEVEL_DELAY; DDRCFG->csr_custom.PHY_GATE_TRAIN_DELAY.PHY_GATE_TRAIN_DELAY =\ LIBERO_SETTING_PHY_GATE_TRAIN_DELAY; DDRCFG->csr_custom.PHY_EYE_TRAIN_DELAY.PHY_EYE_TRAIN_DELAY =\ LIBERO_SETTING_PHY_EYE_TRAIN_DELAY; DDRCFG->csr_custom.PHY_EYE_PAT.PHY_EYE_PAT = LIBERO_SETTING_PHY_EYE_PAT; DDRCFG->csr_custom.PHY_START_RECAL.PHY_START_RECAL =\ LIBERO_SETTING_PHY_START_RECAL; DDRCFG->csr_custom.PHY_CLR_DFI_LVL_PERIODIC.PHY_CLR_DFI_LVL_PERIODIC =\ LIBERO_SETTING_PHY_CLR_DFI_LVL_PERIODIC; DDRCFG->csr_custom.PHY_TRAIN_STEP_ENABLE.PHY_TRAIN_STEP_ENABLE =\ LIBERO_SETTING_PHY_TRAIN_STEP_ENABLE; DDRCFG->csr_custom.PHY_LPDDR_DQ_CAL_PAT.PHY_LPDDR_DQ_CAL_PAT =\ LIBERO_SETTING_PHY_LPDDR_DQ_CAL_PAT; DDRCFG->csr_custom.PHY_INDPNDT_TRAINING.PHY_INDPNDT_TRAINING =\ LIBERO_SETTING_PHY_INDPNDT_TRAINING; DDRCFG->csr_custom.PHY_ENCODED_QUAD_CS.PHY_ENCODED_QUAD_CS =\ LIBERO_SETTING_PHY_ENCODED_QUAD_CS; DDRCFG->csr_custom.PHY_HALF_CLK_DLY_ENABLE.PHY_HALF_CLK_DLY_ENABLE =\ LIBERO_SETTING_PHY_HALF_CLK_DLY_ENABLE; } /** * setup_ddr_segments(void) * setup segment registers- translated DDR address as user requires */ void setup_ddr_segments(SEG_SETUP option) { if(option == DEFAULT_SEG_SETUP) { SEG[0].u[0].raw = (INIT_SETTING_SEG0_0 & 0x7FFFUL); SEG[0].u[1].raw = (INIT_SETTING_SEG0_1 & 0x7FFFUL); SEG[1].u[2].raw = (INIT_SETTING_SEG1_2 & 0x7FFFUL); SEG[1].u[3].raw = (INIT_SETTING_SEG1_3 & 0x7FFFUL); SEG[1].u[4].raw = (INIT_SETTING_SEG1_4 & 0x7FFFUL); SEG[1].u[5].raw = (INIT_SETTING_SEG1_5 & 0x7FFFUL); } else { SEG[0].u[0].raw = (LIBERO_SETTING_SEG0_0 & 0x7FFFUL); SEG[0].u[1].raw = (LIBERO_SETTING_SEG0_1 & 0x7FFFUL); SEG[1].u[2].raw = (LIBERO_SETTING_SEG1_2 & 0x7FFFUL); SEG[1].u[3].raw = (LIBERO_SETTING_SEG1_3 & 0x7FFFUL); SEG[1].u[4].raw = (LIBERO_SETTING_SEG1_4 & 0x7FFFUL); SEG[1].u[5].raw = (LIBERO_SETTING_SEG1_5 & 0x7FFFUL); } /* * disable ddr blocker * Is cleared at reset. When written to '1' disables the blocker function * allowing the L2 cache controller to access the DDRC. Once written to '1' * the register cannot be written to 0, only an MSS reset will clear the * register */ SEG[0].u[7].raw = 0x01U; } /** * use_software_bclk_sclk_training() * @param ddr_type * @return returns 1U if required, otherwise 0U */ static uint8_t use_software_bclk_sclk_training(DDR_TYPE ddr_type) { uint8_t result = 0U; switch (ddr_type) { default: case DDR_OFF_MODE: break; case DDR3L: result = 1U; break; case DDR3: result = 1U; break; case DDR4: result = 1U; break; case LPDDR3: result = 1U; break; case LPDDR4: result = 1U; break; } return(result); } /** * bclk_sclk_offset() * @param ddr_type * @return */ static uint8_t bclk_sclk_offset(DDR_TYPE ddr_type) { uint8_t result = 0U; switch (ddr_type) { default: case DDR_OFF_MODE: result = LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR4; break; case DDR3L: result = LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR3L; break; case DDR3: result = LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR3; break; case DDR4: result = LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR4; break; case LPDDR3: result = LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR3; break; case LPDDR4: result = LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR4; break; } return(result); } /** * config_ddr_io_pull_up_downs_rpc_bits() * * This function overrides the RPC bits related to weak pull up and * weak pull downs. It also sets the override bit if the I/O is disabled. * The settings come fro m Libero * * Note: If LIBERO_SETTING_RPC_EN_ADDCMD0_OVRT9 is not present, indicates older * Libero core (pre 2.0.109) * Post 2.0.109 version of Libero MSS core, weak pull up and pull down * settings come from Libero, along with setting unused MSS DDR I/O to * override. * */ static void config_ddr_io_pull_up_downs_rpc_bits(DDR_TYPE ddr_type) { if(ddr_type == LPDDR4) /* we will add other variants here once verified */ { #ifdef LIBERO_SETTING_RPC_EN_ADDCMD0_OVRT9 /* set over-rides (associated bit set to 1 if I/O not being used */ CFG_DDR_SGMII_PHY->ovrt9.ovrt9 = LIBERO_SETTING_RPC_EN_ADDCMD0_OVRT9; CFG_DDR_SGMII_PHY->ovrt10.ovrt10 = LIBERO_SETTING_RPC_EN_ADDCMD1_OVRT10; CFG_DDR_SGMII_PHY->ovrt11.ovrt11 = LIBERO_SETTING_RPC_EN_ADDCMD2_OVRT11; CFG_DDR_SGMII_PHY->ovrt12.ovrt12 = LIBERO_SETTING_RPC_EN_DATA0_OVRT12; CFG_DDR_SGMII_PHY->ovrt13.ovrt13 = LIBERO_SETTING_RPC_EN_DATA1_OVRT13; CFG_DDR_SGMII_PHY->ovrt14.ovrt14 = LIBERO_SETTING_RPC_EN_DATA2_OVRT14; CFG_DDR_SGMII_PHY->ovrt15.ovrt15 = LIBERO_SETTING_RPC_EN_DATA3_OVRT15; CFG_DDR_SGMII_PHY->ovrt16.ovrt16 = LIBERO_SETTING_RPC_EN_ECC_OVRT16; /* set the required wpu state- note: associated I/O bit 1=> off, 0=> on */ CFG_DDR_SGMII_PHY->rpc235.rpc235 = LIBERO_SETTING_RPC235_WPD_ADD_CMD0; CFG_DDR_SGMII_PHY->rpc236.rpc236 = LIBERO_SETTING_RPC236_WPD_ADD_CMD1; CFG_DDR_SGMII_PHY->rpc237.rpc237 = LIBERO_SETTING_RPC237_WPD_ADD_CMD2; CFG_DDR_SGMII_PHY->rpc238.rpc238 = LIBERO_SETTING_RPC238_WPD_DATA0; CFG_DDR_SGMII_PHY->rpc239.rpc239 = LIBERO_SETTING_RPC239_WPD_DATA1; CFG_DDR_SGMII_PHY->rpc240.rpc240 = LIBERO_SETTING_RPC240_WPD_DATA2; CFG_DDR_SGMII_PHY->rpc241.rpc241 = LIBERO_SETTING_RPC241_WPD_DATA3; CFG_DDR_SGMII_PHY->rpc242.rpc242 = LIBERO_SETTING_RPC242_WPD_ECC; /* set the required wpd state- note: associated I/O bit 1=> off, 0=> on */ CFG_DDR_SGMII_PHY->rpc243.rpc243 = LIBERO_SETTING_RPC243_WPU_ADD_CMD0; CFG_DDR_SGMII_PHY->rpc244.rpc244 = LIBERO_SETTING_RPC244_WPU_ADD_CMD1; CFG_DDR_SGMII_PHY->rpc245.rpc245 = LIBERO_SETTING_RPC245_WPU_ADD_CMD2; CFG_DDR_SGMII_PHY->rpc246.rpc246 = LIBERO_SETTING_RPC246_WPU_DATA0; CFG_DDR_SGMII_PHY->rpc247.rpc247 = LIBERO_SETTING_RPC247_WPU_DATA1; CFG_DDR_SGMII_PHY->rpc248.rpc248 = LIBERO_SETTING_RPC248_WPU_DATA2; CFG_DDR_SGMII_PHY->rpc249.rpc249 = LIBERO_SETTING_RPC249_WPU_DATA3; CFG_DDR_SGMII_PHY->rpc250.rpc250 = LIBERO_SETTING_RPC250_WPU_ECC; #endif } } #ifdef DDR_DIAGNOSTICS /* todo: add support for diagnostics below during board bring-up */ /*-------------------------------------------------------------------------*//** The MSS_DDR_status() function is used to return status information to the user. TODO: Define number of request inputs @param option This option chooses status data we wish returned @param return_data Returned data here. This must be within a defined range. todo:Detail on the sharing of data will be system dependent. AMP/SMU detail to be finalized at time of writing @return Returns 0 on success. TODO: Define error codes. Example: The call to MSS_DDR_status(DDR_TYPE, return_data) will return 0 if successful and the DDR type in the first four bytes of the ret_mem area. @code MSS_DDR_status( DDR_TYPE, ret_mem ); @endcode */ uint8_t MSS_DDR_status ( uint8_t option, uint32_t *return_data ) { uint8_t error = 0U; switch (option) { case USR_OPTION_tip_register_dump: /* todo: WIP * add commands here */ break; default: break; } return error; } /*-------------------------------------------------------------------------*//** * MSS_DDR_user_commands commands from the user * * @param command * User command * @param extra_command_data * extra data from user for particular command * @param return_data * data returned via supplied pointer * @return * status 0 => success * * Example: The call to MSS_DDR_user_commands(USR_CMD_INC_DELAY_CYCLES_LINE, 0x01 , return_data) will return 0 id successful and the DDR type in the first four bytes of the ret_mem area. @code MSS_DDR_user_commands(USR_CMD_INC_DELAY_CYCLES_LINE, 0x01 , return_data); @endcode */ uint8_t MSS_DDR_user_commands ( uint8_t command, uint32_t *extra_command_data, uint32_t *return_data, \ uint32_t return_size ) { uint8_t error = 0U; uint32_t *reg_address; switch (command) { case USR_CMD_GET_DDR_STATUS: break; case USR_CMD_GET_MODE_SETTING: break; case USR_CMD_GET_W_CALIBRATION: config_copy(return_data, &calib_data, sizeof(calib_data)); break; case USR_CMD_GET_GREEN_ZONE: /* READ DQ WINDOW MEASUREMENT */ /* READ DQS WINDOW MEASUREMENT */ /* READ VREF WINDOW MAX MEASUREMENT */ break; case USR_CMD_GET_REG: /* * First check if address valid */ config_copy(reg_address, extra_command_data, 4U); reg_address = (uint32_t *)((uint32_t)reg_address &\ (uint32_t)(0xFFFFFFFCUL)); if ((reg_address >=\ &CFG_DDR_SGMII_PHY->SOFT_RESET_DDR_PHY.SOFT_RESET_DDR_PHY)\ && (reg_address < &CFG_DDR_SGMII_PHY->SPARE_STAT.SPARE_STAT)) { config_copy(return_data, reg_address, sizeof(uint32_t)); } else { error = 1U; } break; /* * And set commands */ case USR_CMD_SET_GREEN_ZONE_DQ: /* READ DQ WINDOW MEASUREMENT */ /* * This procedure is uses reads/writes & DQ delayline controls, to * measure the maximum DQ offset before failure. */ break; case USR_CMD_SET_GREEN_ZONE_DQS: /* READ DQS WINDOW MEASUREMENT */ /* * This procedure is uses reads/writes & DQS delayline controls, to * measure the maximum DQS offset before failure. */ break; case USR_CMD_SET_GREEN_ZONE_VREF_MAX: /* READ VREF WINDOW MAX MEASUREMENT */ /* * This procedure is uses reads/writes & VREF controller delayline * controls, to measure the max VREF level. */ break; case USR_CMD_SET_GREEN_ZONE_VREF_MIN: /* READ VREF WINDOW MIN MEASUREMENT */ /* * This procedure is uses reads/writes & VREF controller delayline * controls, to measure the minimum VREF level. */ break; case USR_CMD_SET_RETRAIN: /* Incremental, In-System Retraining Procedures */ /* * This procedure adjusts the read window to re-center clock and * data. * It should be triggered when the DLL code value passes a certain * threshold, during a refresh cycle. * Added here to allow the user to trigger. */ break; case USR_CMD_SET_REG: break; default: error = 1U; break; } return error; } #endif #ifdef DEBUG_DDR_INIT void debug_read_ddrcfg(void) { (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->ADDR_MAP,\ (sizeof(DDRCFG->ADDR_MAP)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->MC_BASE3,\ (sizeof(DDRCFG->MC_BASE3)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->MC_BASE1,\ (sizeof(DDRCFG->MC_BASE1)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->MC_BASE2,\ (sizeof(DDRCFG->MC_BASE2)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->MPFE,\ (sizeof(DDRCFG->MPFE)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->REORDER,\ (sizeof(DDRCFG->REORDER)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->RMW,\ (sizeof(DDRCFG->RMW)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->ECC,\ (sizeof(DDRCFG->ECC)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->READ_CAPT,\ (sizeof(DDRCFG->READ_CAPT)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->MTA,\ (sizeof(DDRCFG->MTA)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->DYN_WIDTH_ADJ,\ (sizeof(DDRCFG->DYN_WIDTH_ADJ)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->CA_PAR_ERR,\ (sizeof(DDRCFG->CA_PAR_ERR)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->DFI,\ (sizeof(DDRCFG->DFI)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->AXI_IF,\ (sizeof(DDRCFG->AXI_IF)/4U)); (void)print_reg_array(g_debug_uart , (uint32_t *)&DDRCFG->csr_custom,\ (sizeof(DDRCFG->csr_custom)/4U)); return; } #endif const uint8_t REFCLK_OFFSETS[][5U] = { {LIBERO_SETTING_REFCLK_DDR3_1333_NUM_OFFSETS, LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_0, LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_1, LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_2, LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_3}, { LIBERO_SETTING_REFCLK_DDR3L_1333_NUM_OFFSETS, LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_0, LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_1, LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_2, LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_3}, { LIBERO_SETTING_REFCLK_DDR4_1600_NUM_OFFSETS, LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_0, LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_1, LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_2, LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_3}, { LIBERO_SETTING_REFCLK_LPDDR3_1600_NUM_OFFSETS, LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_0, LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_1, LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_2, LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_3}, { LIBERO_SETTING_REFCLK_LPDDR4_1600_NUM_OFFSETS, LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_0, LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_1, LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_2, LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_3}, {LIBERO_SETTING_REFCLK_DDR3_1067_NUM_OFFSETS, LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_0, LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_1, LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_2, LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_3}, { LIBERO_SETTING_REFCLK_DDR3L_1067_NUM_OFFSETS, LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_0, LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_1, LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_2, LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_3}, { LIBERO_SETTING_REFCLK_DDR4_1333_NUM_OFFSETS, LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_0, LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_1, LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_2, LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_3}, { LIBERO_SETTING_REFCLK_LPDDR3_1333_NUM_OFFSETS, LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_0, LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_1, LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_2, LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_3}, { LIBERO_SETTING_REFCLK_LPDDR4_1333_NUM_OFFSETS, LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_0, LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_1, LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_2, LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_3}, }; /** * ddr_manual_addcmd_refclk_offset This function determines current * sweep offset based on DDR type * @param ddr_type * @param refclk_sweep_index * @return */ #ifdef MANUAL_ADDCMD_TRAINIG static uint8_t ddr_manual_addcmd_refclk_offset(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index) { uint8_t refclk_offset; uint8_t type_array_index; type_array_index = (uint8_t)ddr_type; switch (ddr_type) { case DDR3L: case DDR3: if(LIBERO_SETTING_DDR_CLK + DDR_FREQ_MARGIN < DDR_1333_MHZ) { type_array_index = (uint8_t)(type_array_index + (uint8_t)LPDDR4 + (uint8_t)1U); } break; case DDR4: case LPDDR3: case LPDDR4: if(LIBERO_SETTING_DDR_CLK + DDR_FREQ_MARGIN < DDR_1600_MHZ) { type_array_index = (uint8_t)(type_array_index + (uint8_t)LPDDR4 + (uint8_t)1U); } break; default: case DDR_OFF_MODE: break; } if (*refclk_sweep_index >= REFCLK_OFFSETS[type_array_index][0U]) { *refclk_sweep_index = 0U; } refclk_offset = REFCLK_OFFSETS[type_array_index][*refclk_sweep_index + 1U]; *refclk_sweep_index = (uint8_t)(*refclk_sweep_index + 1U); return refclk_offset; } #endif //ALISTER 7/16/21 static uint32_t mode_register_masked_write(uint32_t address) { DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_MR_WR_MASK.INIT_MR_WR_MASK=0xFFFFF; DDRCFG->MC_BASE2.INIT_MR_ADDR.INIT_MR_ADDR=address; DDRCFG->MC_BASE2.INIT_MR_WR_DATA.INIT_MR_WR_DATA=0x0; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ=0x1; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ=0x0; delay(DELAY_CYCLES_5_MICRO); if(DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK!=0){ return 0; } else { return 1; } } static uint32_t mode_register_masked_write_x5(uint32_t address) { uint32_t i; uint32_t error=0; for(i=0; i<10;i++) { error |= mode_register_masked_write(address); } return error; } #ifdef MODE_WRITE1_USED static uint32_t mode_register_write1(uint32_t address, uint32_t data) { DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_MR_WR_MASK.INIT_MR_WR_MASK=0x00000; DDRCFG->MC_BASE2.INIT_MR_ADDR.INIT_MR_ADDR=address; DDRCFG->MC_BASE2.INIT_MR_WR_DATA.INIT_MR_WR_DATA= data; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ=0x1; DDRCFG->MC_BASE2.INIT_MR_W_REQ.INIT_MR_W_REQ=0x0; delay(DELAY_CYCLES_5_MICRO); if(DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK!=0){ return 0; } else { return 1; } } #endif #ifdef ZQ_CAL static uint32_t zq_cal(void) { uint32_t error=0; DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_ZQ_CAL_START.INIT_ZQ_CAL_START=0x1; DDRCFG->MC_BASE2.INIT_ZQ_CAL_START.INIT_ZQ_CAL_START=0x0; delay(DELAY_CYCLES_500_MICRO); error= (DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK==0x0); DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_ZQ_CAL_REQ.INIT_ZQ_CAL_REQ=0x1; DDRCFG->MC_BASE2.INIT_ZQ_CAL_REQ.INIT_ZQ_CAL_REQ=0x0; delay(DELAY_CYCLES_500_MICRO); error |= (DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK==0x0); delay(DELAY_CYCLES_500_MICRO); return error; } #endif /** * LPDDR4 traing exclusive * @param ddr_type * @param refclk_sweep_index */ static void lpddr4_manual_training(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index, uint32_t retry_count, uint8_t *refclk_offset) { //ALISTER 7/16/2021 DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; //moved up from below jan7th delay(DELAY_CYCLES_5_MICRO); DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x1; DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N = 1; delay(DELAY_CYCLES_250_MICRO); /* requirement 200 uS */ DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x0; delay(DELAY_CYCLES_2MS); /* require min. 2 ms */ DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x0; delay(DELAY_CYCLES_150_MICRO); DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.CFG_AUTO_ZQ_CAL_EN.CFG_AUTO_ZQ_CAL_EN=0; delay(DELAY_CYCLES_5_MICRO); /* Assert FORCE_RESET */ delay(DELAY_CYCLES_5_MICRO); uint32_t div0=MSS_SCB_DDR_PLL->PLL_DIV_0_1 & 0x3F00; uint32_t div1=MSS_SCB_DDR_PLL->PLL_DIV_0_1 & 0x3F000000; uint32_t div2=MSS_SCB_DDR_PLL->PLL_DIV_2_3 & 0x3F00; uint32_t div3=MSS_SCB_DDR_PLL->PLL_DIV_2_3 & 0x3F000000; DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; delay(DELAY_CYCLES_50_MICRO); uint32_t mult=2; MSS_SCB_DDR_PLL->PLL_DIV_0_1 = (div0 | div1)*mult; MSS_SCB_DDR_PLL->PLL_DIV_2_3 = (div2 | div3)*mult; while ((CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN=CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN & 0x2000000UL) ==0){} delay(DELAY_CYCLES_50_MICRO); CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN=(uint32_t)(CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN & (~(0x0000003CUL))); CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN=CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN | ((0x0000003CUL)); CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x9U; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x0000003FU ; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x00000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x8U; delay(DELAY_CYCLES_50_MICRO); DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x0; delay(DELAY_CYCLES_500_MICRO); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r\n\r pll_phadj_during_init_2_3 ",\ MSS_SCB_DDR_PLL->PLL_DIV_2_3); (void)uprint32(g_debug_uart, \ "\n\r\n\r pll_phadj_during_init_0_1 ",\ MSS_SCB_DDR_PLL->PLL_DIV_0_1); #endif DDRCFG->MC_BASE2.INIT_CS.INIT_CS = 0x1; DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; //moved up from below jan7th delay(DELAY_CYCLES_5_MICRO); DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x1; DDRCFG->MC_BASE2.CTRLR_SOFT_RESET_N.CTRLR_SOFT_RESET_N = 1; delay(DELAY_CYCLES_250_MICRO); /* req. 200uS */ DDRCFG->MC_BASE2.INIT_FORCE_RESET.INIT_FORCE_RESET = 0x0; delay(DELAY_CYCLES_2MS); /* req. 2MS */ DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x0; delay(DELAY_CYCLES_150_MICRO); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r Writing MR1 ", mode_register_masked_write_x5(1)); (void)uprint32(g_debug_uart, "\n\r Writing MR2 ", mode_register_masked_write_x5(2)); (void)uprint32(g_debug_uart, "\n\r Writing MR3 ", mode_register_masked_write_x5(3)); (void)uprint32(g_debug_uart, "\n\r Writing MR4 ", mode_register_masked_write_x5(4)); (void)uprint32(g_debug_uart, "\n\r Writing MR11 ", mode_register_masked_write_x5(11)); (void)uprint32(g_debug_uart, "\n\r Writing MR16 ", mode_register_masked_write_x5(16)); (void)uprint32(g_debug_uart, "\n\r Writing MR17 ", mode_register_masked_write_x5(17)); (void)uprint32(g_debug_uart, "\n\r Writing MR22 ", mode_register_masked_write_x5(22)); (void)uprint32(g_debug_uart, "\n\r Writing MR13 ", mode_register_masked_write_x5(13)); #else mode_register_masked_write_x5(1); mode_register_masked_write_x5(2); mode_register_masked_write_x5(3); mode_register_masked_write_x5(4); mode_register_masked_write_x5(11); mode_register_masked_write_x5(16); mode_register_masked_write_x5(17); mode_register_masked_write_x5(22); mode_register_masked_write_x5(13); #endif DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; delay(DELAY_CYCLES_50_MICRO); /* Revert to normal speed after mode reg writes */ MSS_SCB_DDR_PLL->PLL_DIV_0_1 = div0 | div1; MSS_SCB_DDR_PLL->PLL_DIV_2_3 = div2 | div3; while ((CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN=CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN & 0x2000000) ==0){} delay(DELAY_CYCLES_50_MICRO); CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN=(uint32_t)(CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN & (~(0x0000003CUL))); CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN=CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN | ((0x0000003C)); CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x9U; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x0000003FU ; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause =\ 0x00000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x8U; delay(DELAY_CYCLES_50_MICRO); DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x1; delay(DELAY_CYCLES_500_MICRO); { /* vref training begins */ uint32_t dpc_bits_new; uint32_t vref_answer; uint32_t transition_a5_min_last = 129U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000021U; CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x00000000U; for (uint32_t ca_indly=0;ca_indly < 30; ca_indly=ca_indly+5) { CFG_DDR_SGMII_PHY->rpc145.rpc145 = ca_indly;//TEMPORARY CFG_DDR_SGMII_PHY->rpc147.rpc147 = ca_indly;//TEMPORARY uint32_t break_loop=1; uint32_t in_window=0; vref_answer=128; for (uint32_t vref=5;vref <30;vref++) //begin vref training { uint32_t transition_a5_max=0; uint32_t transition_a5_min=128; uint32_t rx_a5_last,rx_a5; uint32_t transition_a5; uint32_t range_a5=0; if(transition_a5_min_last > 128U) { transition_a5_min_last=128U; } IOSCB_BANKCONT_DDR->soft_reset = 0U; /* DPC_BITS NV_MAP reset */ //SET VREF HERE delay(DELAY_CYCLES_500_NS); dpc_bits_new=( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (vref <<12) | (0x1<<18); CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS=dpc_bits_new; delay(DELAY_CYCLES_500_NS); IOSCB_BANKCONT_DDR->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ delay(DELAY_CYCLES_500_NS); uint32_t deltat = 128UL; for (uint32_t j = 0; j<20 ; j++) { //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; // rx_a5_last=0x0; rx_a5_last=0xF; transition_a5=0; deltat=128; delay(DELAY_CYCLES_500_NS); for (uint32_t i=0; i < (128-ca_indly);i++) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; delay(DELAY_CYCLES_500_NS); rx_a5 = (CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x0300) >> 8; if (transition_a5 != 0){ if (((i - transition_a5) > 8) ){ //was 8 //////////// break; } } if (transition_a5 ==0) { if ( ((rx_a5 ^ rx_a5_last) & rx_a5 ) ){ transition_a5 = i; } else{ rx_a5_last=rx_a5; } } else { if ((i - transition_a5) == 4) //was 4 //////////// if(!((rx_a5 ^ rx_a5_last) & rx_a5 )) { transition_a5=0; //Continue looking for transition rx_a5_last=rx_a5; } } }//delay loop ends here if (transition_a5 !=0) { if (transition_a5 > transition_a5_max) { transition_a5_max = transition_a5; } if (transition_a5 < transition_a5_min) { transition_a5_min = transition_a5; } } }//Sample loop ends here range_a5=transition_a5_max-transition_a5_min; if (transition_a5_min < 10){ break_loop=0; } if (range_a5 <=5) { //(min(transition_a5_min - transition_a5_min_last,transition_a5_min_last-transition_a5_min) <=4)) if (transition_a5_min > transition_a5_min_last) { deltat=transition_a5_min-transition_a5_min_last; } else { deltat=transition_a5_min_last-transition_a5_min; } if (deltat <=5) { in_window=(in_window<<1)|1; } } else { in_window=(in_window<<1)|0; } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r ca_indly ", ca_indly); (void)uprint32(g_debug_uart, " vref ", vref); (void)uprint32(g_debug_uart, " a5_dly_max:", transition_a5_max); (void)uprint32(g_debug_uart, " a5_dly_min:", transition_a5_min); (void)uprint32(g_debug_uart, " a5_dly_min_last:", transition_a5_min_last); (void)uprint32(g_debug_uart, " range_a5:", range_a5); (void)uprint32(g_debug_uart, " deltat:", deltat); (void)uprint32(g_debug_uart, " in_window:", in_window); (void)uprint32(g_debug_uart, " vref_answer:", vref_answer); #endif if(vref_answer==128) { if ((in_window &0x3)==0x3) //ALISTER CHANGE 2/17/2021 { vref_answer=vref; //ALISTER CHANGE #ifndef PRINT_CA_VREF_WINDOW break; #endif } } transition_a5_min_last=transition_a5_min; } if (break_loop) { break; } } #ifdef DEBUG_DDR_INIT if (vref_answer!=128U) { (void)uprint32(g_debug_uart, "\n\r vref_answer found", vref_answer); } else { (void)uprint32(g_debug_uart, "\n\r CA_VREF training failed! ", vref_answer); } #endif IOSCB_BANKCONT_DDR->soft_reset = 0U; /* DPC_BITS NV_MAP reset */ /* SET VREF HERE */ delay(DELAY_CYCLES_500_NS); if(vref_answer == 128U) { vref_answer = 0x10U; dpc_bits_new=( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (vref_answer <<12U) | (0x1<<18U); } else { //vref_answer = vref_answer; dpc_bits_new=( CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS & 0xFFFC0FFF ) | (vref_answer <<12) | (0x1<<18U); } CFG_DDR_SGMII_PHY->DPC_BITS.DPC_BITS=dpc_bits_new; delay(DELAY_CYCLES_500_NS); IOSCB_BANKCONT_DDR->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ delay(DELAY_CYCLES_500_MICRO); }/* end vref_training; */ { /* Begin MANUAL ADDCMD TRAINING */ uint32_t init_del_offset = 0x8U; uint32_t a5_offset_status; uint32_t rpc147_offset = 0x1U; uint32_t rpc145_offset = 0x0U; uint32_t bclk_phase=MSS_SCB_DDR_PLL->PLL_PHADJ & 0x700; uint32_t bclk90_phase=MSS_SCB_DDR_PLL->PLL_PHADJ & 0x3800; uint32_t refclk_phase; //ALISTER 1/12/2022 SWEEPING CK OFFSET BEFORE CHANING refclk_offset if ((retry_count % 6) == 0){ *refclk_offset = ddr_manual_addcmd_refclk_offset(ddr_type, refclk_sweep_index); } a5_offset_status = DDR_ADD_CMD_A5_OFFSET_FAIL; while(a5_offset_status != DDR_ADD_CMD_A5_OFFSET_PASS) { a5_offset_status = DDR_ADD_CMD_A5_OFFSET_PASS; //ADDCMD Training improvement , adds delay on DDR clock loopback path CFG_DDR_SGMII_PHY->rpc147.rpc147 = init_del_offset + rpc147_offset; //ADDCMD Training improvement , adds delay on A9 loopback path CFG_DDR_SGMII_PHY->rpc145.rpc145 = init_del_offset + rpc145_offset; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000023U; //ENABLE DLY Control & PLL Control uint32_t rx_a5; uint32_t rx_a5_last; uint32_t rx_ck; uint32_t rx_ck_last; uint32_t transition_a5; uint32_t transition_ck; uint32_t i; uint32_t j; uint32_t difference [8]={0}; uint32_t transition_ck_array [8]={0}; uint32_t transitions_found; uint32_t transition_a5_max = 0U; for (j = 0U; j<16U ; j++) { //Increase J loop to increase number of samples on transition_a5 (for noisy CA in LPDDR4) //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; refclk_phase = (j % 8U) << 2U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase | refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | bclk_phase | bclk90_phase | refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase | refclk_phase); rx_a5_last=0xFU; rx_ck_last=0x5U; transition_a5=0U; transition_ck=0U; delay(100U); transitions_found = 0U; i = 0U; while((!transitions_found) & (i < 128U)) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; delay(DELAY_CYCLES_500_NS); rx_a5 = (CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x0300U) >> 8U; rx_ck = CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x000F; if ((transition_a5 != 0U) && (transition_ck != 0U)) { if (((i - transition_a5) > 8U) && ((i - transition_ck) > 8U)) { //break; transitions_found = 1U; } } if (transition_ck == 0U) { if (rx_ck_last != 0x5U) //IF EDGE DETECTED if (rx_ck == 0x5U) transition_ck=i; //SET TRANSITION DETECTED AT I rx_ck_last=rx_ck; } else { if ( (i - transition_ck ) == 4U) if (rx_ck != rx_ck_last) //IF rx_ck not stable after 4 increments, set transition detected to 0 (false transition) { transition_ck = 0U; //Continue looking for transition rx_ck_last=rx_ck; } } if (transition_a5 == 0U) { if ( ((rx_a5 ^ rx_a5_last) & rx_a5 ) ){ transition_a5 = i; } else{ rx_a5_last=rx_a5; } } else { if ((i - transition_a5) == 4U) { if(!((rx_a5 ^ rx_a5_last) & rx_a5 )) { transition_a5=0; //Continue looking for transition rx_a5_last=rx_a5; } } } if ((transition_a5 != 0U) && (transition_ck != 0U)) if ((i==transition_a5) || (i==transition_ck)) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r rx_a5 ",\ rx_a5); (void)uprint32(g_debug_uart, \ " rx_ck ",\ rx_ck); (void)uprint32(g_debug_uart, \ " rx_ck_last ",\ rx_ck_last); (void)uprint32(g_debug_uart, \ " transition_a5 ",\ transition_a5); (void)uprint32(g_debug_uart, \ " transition_ck ",\ transition_ck); (void)uprint32(g_debug_uart, \ " Iteration: ",\ i); (void)uprint32(g_debug_uart, \ " REFCLK_PHASE: ",\ j); #endif } i++; }/* delay loop ends here */ if(transition_a5 > transition_a5_max) transition_a5_max =transition_a5; if ((transition_a5 != 0U) && (transition_ck != 0U) && (j<8U)) { transition_ck_array[j]=transition_ck; /* difference now calculated in separate loop with max a5 intstead of per offset-AL*/ } }/* phase loop ends here */ uint32_t min_diff=0xFFU; uint32_t min_diffp1=0xFFU; uint32_t min_diffp2=0xFFU; uint32_t min_refclk=0x8U; uint32_t min_refclkp1=0x8U; uint32_t min_refclkp2=0x8U; if(transition_a5_max < TRANSITION_A5_THRESHOLD) { a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL; } for (uint32_t k = 0U;k<8U;k++) { if(transition_a5_max >= transition_ck_array[k]) difference[k]= transition_a5_max-transition_ck_array[k]; else difference[k]=0xff; } for (uint32_t k = 0U;k<8U;k++) { if (difference[k] < min_diff){ //updated on Jan10 min_refclk=k; min_refclkp1=(k+1)&0x7UL; min_refclkp2=(k+2)&0x7UL; min_diff = difference[min_refclk]; min_diffp1 = difference[min_refclkp1]; min_diffp2 = difference[min_refclkp2]; } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r difference ", difference[k]); (void)uprint32(g_debug_uart, " REFCLK_PHASE ", k); #endif } if(min_diff == 0xFFU) { a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL; } if (min_refclk==0x8U) { //If ADDCMD training fails due to extremely low frequency, use PLL to provide offset. a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL_LOW_FREQ; } #ifdef MOVE_CK if ((retry_count%3) == LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ZERO){ //toggles between minimum CA delay and second smallest every 4 retrains. //min_diff=second_diff; min_diffp1=min_diff; //min_refclk=(min_refclk-0x1UL)&&(0x7UL); min_refclk=(min_refclk-0x1UL)&(0x7UL); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r CK_PUSH = 0 degrees", 0x0UL); #endif } else if ((retry_count%3) == LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ONE){ #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r CK_PUSH = 45 degrees", 0x0UL); #endif } else if ((retry_count%3) == LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_TWO){ //toggles between minimum CA delay and second smallest every 4 retrains. //min_diff=second_diff; min_diffp1=min_diffp2; //min_refclk=(min_refclk-0x1UL)&&(0x7UL); min_refclk=min_refclkp1; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r CK_PUSH = 90 degrees", 0x0UL); #endif } #endif if(a5_offset_status == DDR_ADD_CMD_A5_OFFSET_PASS) { refclk_phase =((*refclk_offset+min_refclk) & 0x7U)<<2U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase | refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | bclk_phase | bclk90_phase | refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | bclk_phase | bclk90_phase | refclk_phase); //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; for (uint32_t m=0U;m < min_diffp1; m++) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; } CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000000U; //DISABLE DLY Control & PLL Control #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r MANUAL ADDCMD TRAINING Results:\r\n PLL OFFSET: ",min_refclk); (void)uprint32(g_debug_uart, "\n\r transition_a5_max: ", transition_a5_max); (void)uprint32(g_debug_uart, "\n\r CA Output Delay: ", min_diffp1); (void)uprint32(g_debug_uart, "\n\r CA Offset: ", *refclk_offset); #endif } else { if(a5_offset_status & DDR_ADD_CMD_A5_OFFSET_FAIL) { if(init_del_offset < 0xFFU ) { init_del_offset = init_del_offset + (transition_a5_max) + 5U; //if transition_a5 too low, increase indly offset on CK and CA and retrain } else { break; } } } /* end of for (j = 0U; j<16U ; j++) */ } // while(a5_offset_status != DDR_ADD_CMD_A5_OFFSET_PASS) } //END MANUAL ADDCMD TRAINING CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x0000008U; CFG_DDR_SGMII_PHY->expert_dfi_status_override_to_shim.expert_dfi_status_override_to_shim = 0x00000000U; //POST_INITIALIZATION CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x9U; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause = 0x0000003FU ; CFG_DDR_SGMII_PHY->expert_dlycnt_pause.expert_dlycnt_pause = 0x00000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x8U; delay(DELAY_CYCLES_500_NS); DDRCFG->MC_BASE2.INIT_DISABLE_CKE.INIT_DISABLE_CKE = 0x0; delay(DELAY_CYCLES_500_MICRO); #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r Writing MR1 ", mode_register_masked_write_x5(1)); (void)uprint32(g_debug_uart, "\n\r Writing MR2 ", mode_register_masked_write_x5(2)); (void)uprint32(g_debug_uart, "\n\r Writing MR3 ", mode_register_masked_write_x5(3)); (void)uprint32(g_debug_uart, "\n\r Writing MR4 ", mode_register_masked_write_x5(4)); (void)uprint32(g_debug_uart, "\n\r Writing MR11 ", mode_register_masked_write_x5(11)); (void)uprint32(g_debug_uart, "\n\r Writing MR16 ", mode_register_masked_write_x5(16)); (void)uprint32(g_debug_uart, "\n\r Writing MR17 ", mode_register_masked_write_x5(17)); (void)uprint32(g_debug_uart, "\n\r Writing MR22 ", mode_register_masked_write_x5(22)); (void)uprint32(g_debug_uart, "\n\r Writing MR13 ", mode_register_masked_write_x5(13)); #else mode_register_masked_write_x5(1); mode_register_masked_write_x5(2); mode_register_masked_write_x5(3); mode_register_masked_write_x5(4); mode_register_masked_write_x5(11); mode_register_masked_write_x5(16); mode_register_masked_write_x5(17); mode_register_masked_write_x5(22); mode_register_masked_write_x5(13); #endif delay(10U); DDRCFG->MC_BASE2.INIT_ZQ_CAL_START.INIT_ZQ_CAL_START = 1U; DDRCFG->MC_BASE2.INIT_AUTOINIT_DISABLE.INIT_AUTOINIT_DISABLE=0x0U; volatile uint32_t timeout = 0U; while((DDRCFG->MC_BASE2.INIT_ACK.INIT_ACK==0) && (timeout < 0xFFU)) { delay(10U); timeout++; } DDRCFG->MC_BASE2.INIT_ZQ_CAL_START.INIT_ZQ_CAL_START = 0U; DDRCFG->MC_BASE2.CFG_AUTO_ZQ_CAL_EN.CFG_AUTO_ZQ_CAL_EN =\ LIBERO_SETTING_CFG_AUTO_ZQ_CAL_EN; } /* end of LPDDR4 exclusive */ /** * used for LPDDR3 and DDR4 only * @param ddr_type * @param refclk_sweep_index refclk index which is swept * @param bclk_phase * @param bclk90_phase * @param refclk_phase */ static void non_lpddr4_address_cmd_training(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index, uint32_t *bclk_phase, uint32_t *bclk90_phase, uint32_t *refclk_phase ) { /* Begin MANUAL ADDCMD TRAINING */ uint8_t refclk_offset; uint32_t init_del_offset = 0x8U; uint32_t a5_offset_status; uint32_t rpc147_offset = 0x2U; //4 //0 uint32_t rpc145_offset = 0x0U; //0 //4 refclk_offset = ddr_manual_addcmd_refclk_offset(ddr_type, refclk_sweep_index); a5_offset_status = DDR_ADD_CMD_A5_OFFSET_FAIL; while(a5_offset_status != DDR_ADD_CMD_A5_OFFSET_PASS) { a5_offset_status = DDR_ADD_CMD_A5_OFFSET_PASS; //ADDCMD Training improvement , adds delay on DDR clock loopback path - Suggested by Alister CFG_DDR_SGMII_PHY->rpc147.rpc147 = init_del_offset + rpc147_offset; //ADDCMD Training improvement , adds delay on A9 loopback path - Suggested by Alister CFG_DDR_SGMII_PHY->rpc145.rpc145 = init_del_offset + rpc145_offset; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000003U; //ENABLE DLY Control & PLL Control uint32_t rx_a5; uint32_t rx_a5_last; uint32_t rx_ck; uint32_t rx_ck_last; uint32_t transition_a5; uint32_t transition_ck; uint32_t i; uint32_t j; uint32_t difference [8]={0}; uint32_t transition_ck_array [8]={0}; uint32_t transitions_found; uint32_t transition_a5_max = 0U; for (j = 0U; j<16U ; j++) { //Increase J loop to increase number of samples on transition_a5 (for noisy CA in LPDDR4) //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; *refclk_phase = (j % 8U) << 2U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); rx_a5_last=0xFU; rx_ck_last=0x5U; transition_a5=0U; transition_ck=0U; delay(100U); transitions_found = 0U; i = 0U; while((!transitions_found) & (i < 128U)) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; delay(DELAY_CYCLES_500_NS); rx_a5 = (CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x0300U) >> 8U; rx_ck = CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x000F; if ((transition_a5 != 0U) && (transition_ck != 0U)) { if (((i - transition_a5) > 8U) && ((i - transition_ck) > 8U)) { //break; transitions_found = 1U; } } if (transition_ck == 0U) { if (rx_ck_last != 0x5U) //IF EDGE DETECTED if (rx_ck == 0x5U) transition_ck=i; //SET TRANSITION DETECTED AT I rx_ck_last=rx_ck; } else { if ( (i - transition_ck ) == 4U) if (rx_ck != rx_ck_last) //IF rx_ck not stable after 4 increments, set transition detected to 0 (false transition) { transition_ck = 0U; //Continue looking for transition rx_ck_last=rx_ck; } } if (transition_a5 == 0U) { if ( ((rx_a5 ^ rx_a5_last) & rx_a5 ) ){ transition_a5 = i; } else{ rx_a5_last=rx_a5; } } else { if ((i - transition_a5) == 4U) if(!((rx_a5 ^ rx_a5_last) & rx_a5 )) { transition_a5=0; //Continue looking for transition rx_a5_last=rx_a5; } } if ((transition_a5 != 0U) && (transition_ck != 0U)) if ((i==transition_a5) || (i==transition_ck)) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r rx_a5 ",\ rx_a5); (void)uprint32(g_debug_uart, \ " rx_ck ",\ rx_ck); (void)uprint32(g_debug_uart, \ " rx_ck_last ",\ rx_ck_last); (void)uprint32(g_debug_uart, \ " transition_a5 ",\ transition_a5); (void)uprint32(g_debug_uart, \ " transition_ck ",\ transition_ck); (void)uprint32(g_debug_uart, \ " Iteration: ",\ i); (void)uprint32(g_debug_uart, \ " REFCLK_PHASE: ",\ j); #endif } i++; }/* delay loop ends here */ if(transition_a5 > transition_a5_max) transition_a5_max =transition_a5; if ((transition_a5 != 0U) && (transition_ck != 0U) && (j<8U)) { transition_ck_array[j]=transition_ck; /* difference now calculated in separate loop with max a5 intstead of per offset-AL*/ } }/* phase loop ends here */ uint32_t min_diff=0xFFU; uint32_t min_refclk=0x8U; if(transition_a5_max < 5U) { a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL; } for (uint32_t k = 0U;k<8U;k++) { if(transition_a5_max >= transition_ck_array[k]) difference[k]= transition_a5_max-transition_ck_array[k]; else difference[k]=0xff; if (difference[k] < min_diff){ min_diff=difference[k]; min_refclk=k; } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r difference ", difference[k]); (void)uprint32(g_debug_uart, " REFCLK_PHASE ", k); #endif } if(min_diff == 0xFFU) { a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL; } if (min_refclk==0x8U) { //If ADDCMD training fails due to extremely low frequency, use PLL to provide offset. a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL_LOW_FREQ; } if(a5_offset_status == DDR_ADD_CMD_A5_OFFSET_PASS) { *refclk_phase =((refclk_offset+min_refclk) & 0x7U)<<2U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; for (uint32_t m=0U;m < min_diff; m++) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; } CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000000U; //DISABLE DLY Control & PLL Control #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r MANUAL ADDCMD TRAINING Results:\r\n PLL OFFSET: ",min_refclk); (void)uprint32(g_debug_uart, "\n\r transition_a5_max: ", transition_a5_max); (void)uprint32(g_debug_uart, "\n\r CA Output Delay: ", min_diff); #endif } else { if(a5_offset_status & DDR_ADD_CMD_A5_OFFSET_FAIL) { if(init_del_offset < 0xFFU ) { //if transition_a5 too low, increase indly offset on CK and CA and retrain init_del_offset = init_del_offset + (transition_a5_max) + 5U; } else { break; } } } } } /* END MANUAL BCLKSCLK TRAINING */ /** * ddr3_address_cmd_training() * @param ddr_type DDR3 * @param refclk_sweep_index * @param retry_count * @param bclk_phase * @param bclk90_phase * @param refclk_phase * @param refclk_offset */ static void ddr3_address_cmd_training(DDR_TYPE ddr_type, uint8_t * refclk_sweep_index, uint32_t retry_count, uint32_t *bclk_phase, uint32_t *bclk90_phase, uint32_t *refclk_phase, uint8_t *refclk_offset ) { /* Begin MANUAL ADDCMD TRAINING */ uint32_t init_del_offset = 0x8U; uint32_t a5_offset_status; uint32_t rpc147_offset = 0x2U; //4 //0 input delays, cmd and clk uint32_t rpc145_offset = 0x0U; //0 //4 if( (retry_count%3)==0) { *refclk_offset = ddr_manual_addcmd_refclk_offset(ddr_type, refclk_sweep_index); } a5_offset_status = DDR_ADD_CMD_A5_OFFSET_FAIL; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r\n\r\r ADDCMD_OFFSET used in this testing ", *refclk_offset); (void)uprint32(g_debug_uart, "\n\r\n\r\r BCLK_OFFSET used in this testing ",bclk_sclk_offset(ddr_type)); #endif while(a5_offset_status != DDR_ADD_CMD_A5_OFFSET_PASS) { a5_offset_status = DDR_ADD_CMD_A5_OFFSET_PASS; //ADDCMD Training improvement , adds delay on DDR clock loopback path CFG_DDR_SGMII_PHY->rpc147.rpc147 = init_del_offset + rpc147_offset; //ADDCMD Training improvement , adds delay on A9 loopback path CFG_DDR_SGMII_PHY->rpc145.rpc145 = init_del_offset + rpc145_offset; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000003U; //ENABLE DLY Control & PLL Control uint32_t rx_a5; uint32_t rx_a5_last; uint32_t rx_ck; uint32_t rx_ck_last; uint32_t transition_a5; uint32_t transition_ck; uint32_t i; uint32_t j; uint32_t difference [8]={0}; uint32_t transition_ck_array [8]={0}; uint32_t transitions_found; uint32_t transition_a5_max = 0U; for (j = 0U; j<16U ; j++) { //Increase J loop to increase number of samples on transition_a5 (for noisy CA in LPDDR4) //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; *refclk_phase = (j % 8U) << 2U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); rx_a5_last=0xFU; rx_ck_last=0x5U; transition_a5=0U; transition_ck=0U; delay(100U); transitions_found = 0U; i = 0U; while((!transitions_found) & (i < 128U)) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; delay(DELAY_CYCLES_500_NS); rx_a5 = (CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x0300U) >> 8U; rx_ck = CFG_DDR_SGMII_PHY->expert_addcmd_ln_readback.expert_addcmd_ln_readback & 0x000F; if ((transition_a5 != 0U) && (transition_ck != 0U)) { if (((i - transition_a5) > 8U) && ((i - transition_ck) > 8U)) { //break; transitions_found = 1U; } } if (transition_ck == 0U) { if (rx_ck_last != 0x5U) //IF EDGE DETECTED if (rx_ck == 0x5U) transition_ck=i; //SET TRANSITION DETECTED AT I rx_ck_last=rx_ck; } else { if ( (i - transition_ck ) == 4U) if (rx_ck != rx_ck_last) //IF rx_ck not stable after 4 increments, set transition detected to 0 (false transition) { transition_ck = 0U; //Continue looking for transition rx_ck_last=rx_ck; } } if (transition_a5 == 0U) { if ( ((rx_a5 ^ rx_a5_last) & rx_a5 ) ){ transition_a5 = i; } else{ rx_a5_last=rx_a5; } } else { if ((i - transition_a5) == 4U) if(!((rx_a5 ^ rx_a5_last) & rx_a5 )) { transition_a5=0; //Continue looking for transition rx_a5_last=rx_a5; } } if ((transition_a5 != 0U) && (transition_ck != 0U)) if ((i==transition_a5) || (i==transition_ck)) { #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, \ "\n\r rx_a5 ",\ rx_a5); (void)uprint32(g_debug_uart, \ " rx_ck ",\ rx_ck); (void)uprint32(g_debug_uart, \ " rx_ck_last ",\ rx_ck_last); (void)uprint32(g_debug_uart, \ " transition_a5 ",\ transition_a5); (void)uprint32(g_debug_uart, \ " transition_ck ",\ transition_ck); (void)uprint32(g_debug_uart, \ " Iteration: ",\ i); (void)uprint32(g_debug_uart, \ " REFCLK_PHASE: ",\ j); #endif } i++; }/* delay loop ends here */ if(transition_a5 > transition_a5_max) transition_a5_max =transition_a5; if ((transition_a5 != 0U) && (transition_ck != 0U) && (j<8U)) { transition_ck_array[j]=transition_ck; /* difference now calculated in separate loop with max a5 intstead of per offset-AL*/ } }/* phase loop ends here */ uint32_t min_diff=0xFFU; uint32_t min_refclk=0x8U; #ifdef MOVE_CK uint32_t second_diff=0xFFU; uint32_t second_refclk=0x8U; uint32_t third_diff=0xFFU; uint32_t third_refclk=0x8U; #endif if(transition_a5_max < TRANSITION_A5_THRESHOLD) { a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL; } for (uint32_t l = 0U;l<8U;l++) { uint32_t k=7-l; if(transition_a5_max >= transition_ck_array[k]) difference[k]= transition_a5_max-transition_ck_array[k]; else difference[k]=0xff; } for (uint32_t l = 0U;l<8U;l++) { uint32_t k=7-l; if (difference[k] < min_diff){ //ALISTER ADDED TO MOVE CK without changing CK/CA offset #ifdef MOVE_CK second_refclk=(k+1)&0x7UL; second_diff=difference[second_refclk]; third_refclk=(k+2)&0x7UL; third_diff=difference[third_refclk]; #endif min_refclk=k; min_diff=difference[min_refclk]; } #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r difference ", difference[k]); (void)uprint32(g_debug_uart, " REFCLK_PHASE ", k); #endif } #ifdef MOVE_CK if (((retry_count)%3) == 0x1){ min_diff=second_diff; min_refclk=second_refclk; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r CK_PUSH = 45 degrees", 0x0UL); #endif } else if (((retry_count )%3) == 0x2){ min_diff=third_diff; min_refclk=third_refclk; #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r CK_PUSH = 90 degrees", 0x0UL); #endif } #endif if(min_diff == 0xFFU) { a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL; } if (min_refclk==0x8U) { //If ADDCMD training fails due to extremely low frequency, use PLL to provide offset. a5_offset_status |= DDR_ADD_CMD_A5_OFFSET_FAIL_LOW_FREQ; } if(a5_offset_status == DDR_ADD_CMD_A5_OFFSET_PASS) { *refclk_phase =((*refclk_offset+min_refclk) & 0x7U)<<2U; MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00000003UL | *bclk_phase | *bclk90_phase | *refclk_phase); MSS_SCB_DDR_PLL->PLL_PHADJ = (0x00004003UL | *bclk_phase | *bclk90_phase | *refclk_phase); //LOAD INDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; //LOAD OUTDLY CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_load_reg1.expert_dlycnt_load_reg1 = 0x000000U; for (uint32_t m=0U;m < min_diff; m++) { CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x180000U; CFG_DDR_SGMII_PHY->expert_dlycnt_move_reg1.expert_dlycnt_move_reg1 = 0x0U; } CFG_DDR_SGMII_PHY->expert_dlycnt_direction_reg1.expert_dlycnt_direction_reg1 = 0x000000U; CFG_DDR_SGMII_PHY->expert_mode_en.expert_mode_en = 0x00000000U; //DISABLE DLY Control & PLL Control #ifdef DEBUG_DDR_INIT (void)uprint32(g_debug_uart, "\n\r MANUAL ADDCMD TRAINING Results:\r\n PLL OFFSET: ",min_refclk); (void)uprint32(g_debug_uart, "\n\r transition_a5_max: ", transition_a5_max); (void)uprint32(g_debug_uart, "\n\r CA Output Delay: ", min_diff); #endif } else { if(a5_offset_status & DDR_ADD_CMD_A5_OFFSET_FAIL) { if(init_del_offset < 0xFFU ) { /* * if transition_a5 too low, increase indly offset on CK * and CA and retrain */ init_del_offset = init_del_offset + (transition_a5_max) + 5U; } else { break; } } } } } /* END MANUAL BCLKSCLK TRAINING */ #endif /* DDR_SUPPORT */ mss_ddr.h000066400000000000000000001271431432224323300364570ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_ddr.h * @author Microchip-FPGA Embedded Systems Solutions * @brief DDR related defines * */ /*=========================================================================*//** @page DDR setup and monitoring ============================================================================== @section intro_sec Introduction ============================================================================== The MPFS microcontroller subsystem (MSS) includes a number of hard core components physically located in the north west corner of the MSS on the die. This includes the DDR Phy. ============================================================================== @section Items located in the north west corner ============================================================================== - MSS PLL - SGMII - DDR phy - MSSIO ============================================================================== @section Overview of DDR related hardware ============================================================================== Simplified IP diagram +--+ +--++ +-----+ +---v--+ |o | |H0 | |H1-H4+--------> AXI | |t | ++--+ +-+---+ |switch<---+h | | | | | |e | | | +--+---+ |r | +v------v-------+ | | | |L2 cache | non-cache |m | +------------+--+ | |a | +---v----+ +---v---+ |s | |seg 0 | | seg 1 | |t | +----^---+ +---^---+ |e | | | |r | +-----------+------+----v---------v---+ |s | |Training IP|MTC |DDR controller | +--+ +-----------+------+--------+---------+ |DFI | +---------v--------+ | DDR Phy | +------------------+ | Bank 6 I/O | +-------+----------+ | +----------v---------------+ | +--+ +--+ +--+ +--+ +--+ | | |D | |D | |R | | | | | | | +--+ +--+ +--+ +--+ +--+ | +--------------------------+ ----------- Hart0 E51 ----------- In most systems, the E51 will will setup and monitor the DDR ----------- L2 Cache ----------- Specific address range is used to access DDR via cache ----------- AXI switch ----------- DDR access via AXI switch for non-cached read/write ----------- SEG regs ----------- Used to map internal DDR address range to external fixed mapping. Note: DDR address ranges are at 32 bit and 64 bits ----------- DDR controller ----------- Manages DDR, refresh rates etc ----------- DDR Training IP ----------- Used to carry out training using IP state machines - BCLKSCLK_TIP_TRAINING . - addcmd_TIP_TRAINING - wrlvl_TIP_TRAINING - rdgate_TIP_TRAINING - dq_dqs_opt_TIP_TRAINING ----------- DDR MTC - Memory test controller ----------- Sends/receives test patterns to DDR. More efficient than using software. Used during write calibration and in DDR test routines. ----------- DFI ----------- Industry standard interface between phy, DDRC ----------- DDR phy ----------- PolarFire-SoC DDR phy manges data paath between pins and DFI ============================================================================== @section Overview of DDR embedded software ============================================================================== ----------- Setup ----------- - phy and IO - DDRC ----------- Use Training IP ----------- - kick-off RTL training IP state machine - Verify all training complete - BCLKSCLK_TIP_TRAINING . - addcmd_TIP_TRAINING This is a coarse training that moves the DDRCLK with PLL phase rotations in relation to the Address/Command bits to achieve the desired offset on the FPGA side. - wrlvl_TIP_TRAINING - rdgate_TIP_TRAINING - dq_dqs_opt_TIP_TRAINING Test this reg to determine training status: DDRCFG->DFI.STAT_DFI_TRAINING_COMPLETE.STAT_DFI_TRAINING_COMPLETE; ----------- Write Calibration ----------- The Memory Test Core plugged in to the front end of the DDR controller is used to perform lane-based writes and read backs and increment write calibration offset for each lane until data match occurs. The settings are recorded by the driver and available to be read using by an API function call. ----------- VREF Calibration (optional) ----------- VREF (DDR4 + LPDDR4 only) Set Remote VREF via mode register writes (MRW). In DDR4 and LPDDR4, VREF training may be done by writing to Mode Register 6 as defined by the JEDEC spec and, for example, Micron's datasheet for its 4Gb DDR4 RAM's: MR6 register definition from DDR4 datasheet | Mode Reg | Description | | ------------- |:---------------------------------------------------:| | 13,9,8 | DQ RX EQ must be 000 | | 7 | Vref calib enable = => disables, 1 ==> enabled | | 6 | Vref Calibration range 0 = Range 0, 1 - Range 2 | | 5:0 | Vref Calibration value | This step is not implemented in the current driver. It can be implemented in the same way as write Calibration and will be added during board verification. ----------- FPGA VREF (Local VREF training) (optional) ----------- In addition to memory VREFDQ training, or remote training, it is possible to train the VREFDQ on the FPGA device. WE refer to this training as local VREF training. Train FPGA VREF using the vrgen_h and vrgen_v registers To manipulate the FPGA VREF value, firmware must write to the DPC_BITS register, located at physical address 0x2000 7184. CFG_DDR_SGMII_PHY->DPC_BITS.bitfield.dpc_vrgen_h; CFG_DDR_SGMII_PHY->DPC_BITS.bitfield.dpc_vrgen_v; Like memory VREFDQ training, FPGA VREFDQ training seeks to find an average/ optimal VREF value by sweeping across the full range and finding a left edge and a right edge. This step is not implemented in the current driver. It can be implemented in the same way as write Calibration and will be added during board verification. ----------- DQ Write Offset ----------- (LPDDR4 only) ), there must be an offset at the input to the LPDDR4 memory device between DQ and DQS. Unlike other flavors of DDR, which match DQ and DQS at the SDRAM, for LPDDR4 this relationship must be trained, because it will vary between 200ps and 600ps, which, depending on the data rate, could be as much as one whole bit period. This training is integrated with write calibration, because it, too, is done on a per-lane basis. That is, each lane is trained separately by sweeping the DQ output delay to find a valid range and of DQ output delays and center it. DQ output delays are swept using the expert_dlycnt_move_reg0 register located in the MSS DDR TIP. ----------- Overview Flow diagram of Embedded software setup ----------- +--------------------------------------------+ | Some Preconditions | | DCE, CORE_UP, FLASH VALID, MSS_IO_EN | | MSS PLL setup, Clks to MSS setup | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Check if in off mode, ret if so | +--------------------+-----------------------+ | +--------------------v-----------------------+ | set ddr mode and VS bits | +--------------------+-----------------------+ | +--------------------v-----------------------+ | soft reset I/O decoders | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Set RPC registers that need manual setup | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Soft reset IP- to load RPC ->SCB regs | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Calibrate I/O - as they are now setup | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Configure the DDR PLL - Using SCB writes | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Setup the SEG regs - NB May move this down| +--------------------+-----------------------+ | +--------------------v-----------------------+ | Set-up the DDRC - Using Libero values | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Reset training IP | +--------------------+-----------------------+ | +----------------- --v-----------------------+ | Rotate BCLK by programmed amount (degrees)| +--------------------+-----------------------+ | +--------------------v-----------------------+ | Set training parameters | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Assert traing reset | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Wait until traing complete | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Write calibrate | +--------------------+-----------------------+ | +--------------------v-----------------------+ | If LPDDR4, calibrate DQ | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Sanity check training | +--------------------+-----------------------+ | +--------------------v-----------------------+ | Return 0 if all went OK | +--------------------------------------------+ *//*=========================================================================*/ #ifndef __MSS_DDRC_H_ #define __MSS_DDRC_H_ 1 #include #include #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** */ typedef enum DDR_TYPE_ { DDR3 = 0x00, /*!< 0 DDR3 */ DDR3L = 0x01, /*!< 1 DDR3L */ DDR4 = 0x02, /*!< 2 DDR4 */ LPDDR3 = 0x03, /*!< 3 LPDDR3 */ LPDDR4 = 0x04, /*!< 4 LPDDR4 */ DDR_OFF_MODE = 0x07 /*!< 4 LPDDR4 */ } DDR_TYPE; typedef enum DDR_MEMORY_ACCESS_ { DDR_NC_256MB, DDR_NC_WCB_256MB, DDR_NC_2GB, DDR_NC_WCB_2GB, } DDR_MEMORY_ACCESS; /* DDR clk frequency - should come from */ #if !defined (LIBERO_SETTING_DDR_CLK) #define LIBERO_SETTING_DDR_CLK DDR_1600_MHZ #endif /* this is a fixed value, currently only 5 supported in the TIP */ #define MAX_POSSIBLE_TIP_TRAININGS 0x05U /* LIBERO_SETTING_TIP_CFG_PARAMS * ADDCMD_OFFSET [0:3] RW value */ #define ADDRESS_CMD_OFFSETT_MASK (0x7U<<0U) #define BCLK_SCLK_OFFSET_SHIFT (3U) #define BCLK_SCLK_OFFSET_MASK (0x7U<<3U) #define BCLK_DPC_VRGEN_V_SHIFT (12U) #define BCLK_DPC_VRGEN_V_MASK (0x3FU<<12U) #define BCLK_DPC_VRGEN_H_SHIFT (4U) #define BCLK_DPC_VRGEN_H_MASK (0x3FU<<4U) #define BCLK_DPC_VRGEN_VS_SHIFT (0U) #define BCLK_DPC_VRGEN_VS_MASK (0xFU<<0U) /* offsets and masks LIBERO_SETTING_DPC_BITS */ #define DDR_DPC_VS_SHIFT 0U #define DDR_DPC_VRGEN_H_SHIFT 4U #define DDR_DPC_VRGEN_EN_H_SHIFT 10U #define DDR_DPC_MOVE_EN_H_SHIFT 11U #define DDR_DPC_VRGEN_V_SHIFT 12U #define DDR_DPC_VRGEN_EN_V_SHIFT 18U #define DDR_DPC_MOVE_EN_V_SHIFT 19U #define DDR_DPC_VS_MASK (0xFU << DDR_DPC_VS_SHIFT) #define DDR_DPC_VRGEN_H_MASK (0x3FU << DDR_DPC_VRGEN_H_SHIFT) #define DDR_DPC_VRGEN_EN_H_MASK (0x1U << DDR_DPC_VRGEN_EN_H_SHIFT) #define DDR_DPC_MOVE_EN_H_MASK (0x1U << DDR_DPC_MOVE_EN_H_SHIFT) #define DDR_DPC_VRGEN_V_MASK (0xFU << DDR_DPC_VRGEN_V_SHIFT) #define DDR_DPC_VRGEN_EN_V_MASK (0x1U << DDR_DPC_VRGEN_EN_V_SHIFT) #define DDR_DPC_MOVE_EN_V_MASK (0x1U << DDR_DPC_MOVE_EN_V_SHIFT) /* masks and associated values used with DDRPHY_MODE register */ #define DDRPHY_MODE_MASK 0x7U /* ECC */ #define DDRPHY_MODE_ECC_MASK (0x1U<<3U) #define DDRPHY_MODE_ECC_ON (0x1U<<3U) /* Bus width */ #define DDRPHY_MODE_BUS_WIDTH_4_LANE (0x1U<<5U) #define DDRPHY_MODE_BUS_WIDTH_MASK (0x7U<<5U) /* Number of ranks, 1 or 2 supported */ #define DDRPHY_MODE_RANK_MASK (0x1U<<26U) #define DDRPHY_MODE_ONE_RANK (0x0U<<26U) #define DDRPHY_MODE_TWO_RANKS (0x1U<<26U) #define DMI_DBI_MASK (~(0x1U<<8U)) /* Write latency min/max settings If write calibration fails * For Libero setting, we iterate through these values looking for a * Calibration pass */ #define DDR_CAL_MIN_LATENCY 0UL #define DDR_CAL_MAX_LATENCY 3UL #define MTC_TIMEOUT_ERROR 0x02U #define DDR_MODE_REG_VREF 0xCU #define DDR_CALIBRATION_PASSED 0xFF #define DDR_CALIBRATION_FAILED 0xFE #define DDR_CALIBRATION_SUCCESS 0xFC /* * Some settings that are only used during testing in new DDR setup */ /* #define LANE_ALIGNMENT_RESET_REQUIRED leave commented, not required */ #define ABNORMAL_RETRAIN_CA_DECREASE_COUNT 2U #define ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT 2U #define DQ_DQS_NUM_TAPS 5U #if !defined (LIBERO_SETTING_MIN_RPC_156_VALUE) #define LIBERO_SETTING_MIN_RPC_156_VALUE 1U #endif #if !defined (LIBERO_SETTING_MAX_RPC_156_VALUE) #define LIBERO_SETTING_MAX_RPC_156_VALUE 9U #endif #if !defined (LIBERO_SETTING_RPC_156_VALUE) /* DDR clk frequency - should come from */ #if (LIBERO_SETTING_DDR_CLK == DDR_1600_MHZ) #define LIBERO_SETTING_RPC_156_VALUE 6U #else #define LIBERO_SETTING_RPC_156_VALUE 1U #endif #endif /* #define SW_CONFIG_LPDDR_WR_CALIB_FN */ #if !defined (LIBERO_SETTING_MAX_MANUAL_REF_CLK_PHASE_OFFSET) #define LIBERO_SETTING_MAX_MANUAL_REF_CLK_PHASE_OFFSET 4U #endif #if !defined (LIBERO_SETTING_MIN_MANUAL_REF_CLK_PHASE_OFFSET) #define LIBERO_SETTING_MIN_MANUAL_REF_CLK_PHASE_OFFSET 2U #endif #if !defined (LIBERO_SETTING_MANUAL_REF_CLK_PHASE_OFFSET) /* If skipping add/cmd training, this value is used */ /* The value used may be trained. The value here should be determined */ /* for the board design by performing a manual sweep. */ #define LIBERO_SETTING_MANUAL_REF_CLK_PHASE_OFFSET 0x00000006UL /* CA_BUS_RX_OFF_POST_TRAINING [0:1] RW value= 0x1 */ #endif #ifndef TRANSITION_A5_THRESHOLD #define TRANSITION_A5_THRESHOLD 18U #endif /* Value used during write leveling */ #ifndef DPC_VRGEN_H_LPDDR4_WR_LVL_VAL #define DPC_VRGEN_H_LPDDR4_WR_LVL_VAL 0x5U #endif /* Value used during write leveling */ #ifndef DPC_VRGEN_H_DDR3_WR_LVL_VAL #define DPC_VRGEN_H_DDR3_WR_LVL_VAL 0x2U #endif #if !defined (DDR_FULL_32BIT_NC_CHECK_EN) #define DDR_FULL_32BIT_NC_CHECK_EN 1 #endif #if !defined (DDR_FULL_32BIT_CACHED_CHECK_EN) #define DDR_FULL_32BIT_CACHED_CHECK_EN 0 #endif #if !defined (NO_PATTERN_IN_CACHE_READS) #define NO_PATTERN_IN_CACHE_READS 1 #endif #if !defined (SIZE_OF_PATTERN_TEST) #define SIZE_OF_PATTERN_TEST 0x02000000UL #endif #if !defined (SIZE_OF_PATTERN_OFFSET) #define SIZE_OF_PATTERN_OFFSET 12U #endif #if !defined (DEFAULT_RPC_166_VALUE) #define DEFAULT_RPC_166_VALUE 2UL #endif /* set to 0 if you want to turn off tuning */ #if !defined (TUNE_RPC_166_VALUE) #define TUNE_RPC_166_VALUE 1 #endif #if !defined (MIN_RPC_166_VALUE) #define MIN_RPC_166_VALUE 2UL #endif #if !defined (MAX_RPC_166_VALUE) #define MAX_RPC_166_VALUE 4UL #endif #define NUM_RPC_166_VALUES (MAX_RPC_166_VALUE - MIN_RPC_166_VALUE) /* Offsets for each mem type- fixed values */ #if !defined (LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR4) #define LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR4 0x00000005UL #endif #if !defined (LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR3) #define LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_LPDDR3 0x00000007UL #endif #if !defined (LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR4) #define LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR4 0x00000006UL #endif #if !defined (LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR3) #define LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR3 0x00000006UL #endif #if !defined (LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR3L) #define LIBERO_SETTING_SW_TRAING_BCLK_SCLK_OFFSET_DDR3L 0x00000006UL #endif /* * 0x6DU => setting vref_ca to 40% * This (0x6DU) is the default setting. * Currently not being used, here for possible future use. * */ #if !defined (DDR_MODE_REG_VREF_VALUE) #define DDR_MODE_REG_VREF_VALUE 0x6DU #endif /* number of test writes to perform */ #if !defined (SW_CFG_NUM_READS_WRITES) #define SW_CFG_NUM_READS_WRITES 0x20000U #endif #if !defined (SW_CFG_NUM_READS_WRITES_FAST_START) #define SW_CFG_NUM_READS_WRITES_FAST_START 0x2000U #endif /* * what test patterns to write/read on start-up * */ #if !defined (SW_CONFIG_PATTERN) #define SW_CONFIG_PATTERN (PATTERN_INCREMENTAL|\ PATTERN_WALKING_ONE|\ PATTERN_WALKING_ZERO|\ PATTERN_RANDOM|\ PATTERN_0xCCCCCCCC|\ PATTERN_0x55555555) #endif #if !defined (SW_CONFIG_PATTERN_FAST_START) #define SW_CONFIG_PATTERN_FAST_START (PATTERN_INCREMENTAL|\ PATTERN_WALKING_ZERO) #endif #if !defined (LIBERO_FAST_START) #define LIBERO_FAST_START 0U #endif /* * Default order of ADDCMD clk pushes * These will be overwritten when supported in Libero * Currently (2022.03) if change of order required, define in mss_sw_config.h * Define in mss_sw_config.h will take precedence */ #if (LIBERO_SETTING_DDR_CLK == DDR_1600_MHZ) #if !defined (LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ZERO) #define LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ZERO 1U #endif #if !defined (LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ONE) #define LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ONE 2U #endif #if !defined (LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_TWO) #define LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_TWO 0U #endif #else #if !defined (LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ZERO) #define LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ZERO 0U #endif #if !defined (LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ONE) #define LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_ONE 1U #endif #if !defined (LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_TWO) #define LIBERO_SETTING_ADD_CMD_CLK_MOVE_ORDER_TWO 2U #endif #endif /* * Sweep offsets * They currently are not coming from MSS Configurator (v12.7 and earlier) * They may at some point * * Determined ( 5th Feb 2021 ) * DDR3@1066 = 3,2,1 * DDR4@1600 = 7,0,1 * LPDDR3@1066 = 7,0,1 * LPDDR4@1600 = 5,4,6,3 * * DDR3@1333 = 0,1 //1,7,0,2 * DDR4@1333 = 0,7,1 * LPDDR3@1333 = 0,1 //7,0,6 * LPDDR4@1333 = 1,2,3 * */ #if !defined (VREF_TRAINING_MIN) #define VREF_TRAINING_MIN 5U #endif #if !defined (VREF_TRAINING_MAX) #define VREF_TRAINING_MAX 30U #endif #if !defined (CA_SWEEP_START) #define CA_SWEEP_START 0U #endif #if !defined (CA_SWEEP_END) #define CA_SWEEP_END 30U #endif #if !defined (CA_SWEEP_INCREMENT) #define CA_SWEEP_INCREMENT 5U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1333_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_DDR3_1333_NUM_OFFSETS 3U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1333_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_DDR3L_1333_NUM_OFFSETS 3U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1600_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_DDR4_1600_NUM_OFFSETS 4U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1600_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_LPDDR3_1600_NUM_OFFSETS 3U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1600_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_LPDDR4_1600_NUM_OFFSETS 4U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1067_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_DDR3_1067_NUM_OFFSETS 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1067_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_DDR3L_1067_NUM_OFFSETS 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1333_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_DDR4_1333_NUM_OFFSETS 4U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1333_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_LPDDR3_1333_NUM_OFFSETS 2U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1333_NUM_OFFSETS) #define LIBERO_SETTING_REFCLK_LPDDR4_1333_NUM_OFFSETS 3U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_0) #define LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_0 0U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_1) #define LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_1 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_2) #define LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_2 7U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_3) #define LIBERO_SETTING_REFCLK_DDR3_1333_OFFSET_3 0U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_0) #define LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_0 0U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_1) #define LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_1 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_2) #define LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_2 0U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_3) #define LIBERO_SETTING_REFCLK_DDR3L_1333_OFFSET_3 0U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_0) #define LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_0 7U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_1) #define LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_1 6U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_2) #define LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_2 5U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_3) #define LIBERO_SETTING_REFCLK_DDR4_1600_OFFSET_3 0U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_0) #define LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_0 7U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_1) #define LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_1 0U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_2) #define LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_2 1U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_3) #define LIBERO_SETTING_REFCLK_LPDDR3_1600_OFFSET_3 2U #endif //LPDDR4@1600 = 5,4,6,3 changed to 5,4,6,2 16th Feb Alister //AUG Offsets changed to 4324 //LPDDR4@1600 = 4,3,2,4 changed to 3,4,2,5 Feb 2022 #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_0) #define LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_0 3U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_1) #define LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_1 4U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_2) #define LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_2 2U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_3) #define LIBERO_SETTING_REFCLK_LPDDR4_1600_OFFSET_3 5U #endif /* * 1333 offset */ #if !defined (LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_0) #define LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_0 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_1) #define LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_1 2U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_2) #define LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_2 3U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_3) #define LIBERO_SETTING_REFCLK_DDR3_1067_OFFSET_3 2U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_0) #define LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_0 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_1) #define LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_1 2U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_2) #define LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_2 3U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_3) #define LIBERO_SETTING_REFCLK_DDR3L_1067_OFFSET_3 2U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_0) #define LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_0 0U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_1) #define LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_1 1U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_2) #define LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_2 6U #endif #if !defined (LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_3) #define LIBERO_SETTING_REFCLK_DDR4_1333_OFFSET_3 7U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_0) #define LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_0 0U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_1) #define LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_1 1U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_2) #define LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_2 6U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_3) #define LIBERO_SETTING_REFCLK_LPDDR3_1333_OFFSET_3 0U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_0) #define LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_0 2U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_1) #define LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_1 1U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_2) #define LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_2 3U #endif #if !defined (LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_3) #define LIBERO_SETTING_REFCLK_LPDDR4_1333_OFFSET_3 0U #endif #ifndef NOT_A_FULL_RETRAIN #define NOT_A_FULL_RETRAIN #endif #if !defined (RPC_OVERRIDE_166_LANE_FIFO) #define RPC_OVERRIDE_166_LANE_FIFO 0 #endif #define ONE_GB_MTC 30U #define HALF_GB_MTC 29U #define ONE_MB_MTC 20U /*Cached access at 0x00_8000_0000 (-0x80+0x00) */ #define INIT_SETTING_SEG0_0 0x00007F80UL /* ADDRESS_OFFSET [0:15] RW value= 0x7F80 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*Cached access at 0x10_0000_000 */ #define INIT_SETTING_SEG0_1 0x00007000UL /* ADDRESS_OFFSET [0:15] RW value= 0x7000 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG0_2 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG0_3 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG0_4 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG0_5 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:6] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG0_6 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG0_7 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG1_0 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG1_1 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*Non-Cached access at 0x00_c000_0000 */ #define INIT_SETTING_SEG1_2 0x00007F40UL /* ADDRESS_OFFSET [0:15] RW value= 0x7F40 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*Non-Cached access at 0x14_0000_0000 */ #define INIT_SETTING_SEG1_3 0x00006C00UL /* ADDRESS_OFFSET [0:15] RW value= 0x6C00 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*Non-Cached WCB access at 0x00_d000_0000 */ #define INIT_SETTING_SEG1_4 0x00007F30UL /* ADDRESS_OFFSET [0:15] RW value= 0x7F30 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*Non-Cached WCB 0x18_0000_0000 */ #define INIT_SETTING_SEG1_5 0x00006800UL /* ADDRESS_OFFSET [0:15] RW value= 0x6800 */ /* RESERVED [15:6] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*Trace - Trace not in use here so can be left as 0 */ #define INIT_SETTING_SEG1_6 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /*not used */ #define INIT_SETTING_SEG1_7 0x00000000UL /* ADDRESS_OFFSET [0:15] RW value= 0x0 */ /* RESERVED [15:16] RW value= 0x0 */ /* LOCKED [31:1] RW value= 0x0 */ /***************************************************************************//** */ typedef enum MTC_PATTERN_ { MTC_COUNTING_PATTERN = 0x00, /*!< */ MTC_WALKING_ONE = 0x01, /*!< */ MTC_PSEUDO_RANDOM = 0x02, /*!< */ MTC_NO_REPEATING_PSEUDO_RANDOM = 0x03, /*!< */ MTC_ALT_ONES_ZEROS = 0x04, /*!< */ MTC_ALT_5_A = 0x05, /*!< */ MTC_USER = 0x06, /*!< */ MTC_PSEUDO_RANDOM_16BIT = 0x07, /*!< */ MTC_PSEUDO_RANDOM_8BIT = 0x08, /*!< */ } MTC_PATTERN; typedef enum MTC_ADD_PATTERN_ { MTC_ADD_SEQUENTIAL = 0x00, /*!< */ MTC_ADD_RANDOM = 0x01, /*!< */ } MTC_ADD_PATTERN; /***************************************************************************//** */ typedef enum DDR_SM_STATES_ { DDR_STATE_INIT = 0x00, /*!< 0 DDR_STATE_INIT*/ DDR_STATE_MONITOR = 0x01, /*!< 1 DDR_STATE_MONITOR */ DDR_STATE_TRAINING = 0x02, /*!< 2 DDR_STATE_TRAINING */ DDR_STATE_VERIFY = 0x03, /*!< 3 DDR_STATE_VERIFY */ } DDR_SM_STATES; /***************************************************************************//** */ typedef enum DDR_SS_COMMAND_ { DDR_SS__INIT = 0x00, /*!< 0 DDR_SS__INIT */ DDR_SS_MONITOR = 0x01, /*!< 1 DDR_SS_MONITOR */ } DDR_SS_COMMAND; /***************************************************************************//** */ typedef enum DDR_SS_STATUS_ { DDR_SETUP_DONE = 0x01, /*!< 0 DDR_SETUP_DONE */ DDR_SETUP_FAIL = 0x02, /*!< 1 DDR_SETUP_FAIL */ DDR_SETUP_SUCCESS = 0x04, /*!< 2 DDR_SETUP_SUCCESS */ DDR_SETUP_OFF_MODE = 0x08, /*!< 4 DDR_SETUP_OFF_MODE */ } DDR_SS_STATUS; /***************************************************************************//** */ typedef enum DDR_TRAINING_SM_ { DDR_TRAINING_INIT, /*!< DDR_TRAINING_INIT */ DDR_TRAINING_FAIL, DDR_CHECK_TRAINING_SWEEP, DDR_TRAINING_SWEEP, DDR_TRAINING_CHECK_FOR_OFFMODE, /*!< DDR_TRAINING_OFFMODE */ DDR_TRAINING_SET_MODE_VS_BITS, DDR_TRAINING_FLASH_REGS, DDR_TRAINING_CORRECT_RPC, DDR_TRAINING_SOFT_RESET, DDR_TRAINING_CALIBRATE_IO, DDR_TRAINING_CONFIG_PLL, DDR_TRAINING_SETUP_SEGS, DDR_TRAINING_VERIFY_PLL_LOCK, DDR_TRAINING_SETUP_DDRC, DDR_TRAINING_RESET, DDR_TRAINING_ROTATE_CLK, DDR_TRAINING_SET_TRAINING_PARAMETERS, DDR_TRAINING_IP_SM_BCLKSCLK_SW, DDR_MANUAL_ADDCMD_TRAINING_SW, DDR_TRAINING_IP_SM_START, DDR_TRAINING_IP_SM_START_CHECK, DDR_TRAINING_IP_SM_BCLKSCLK, DDR_TRAINING_IP_SM_ADDCMD, DDR_TRAINING_IP_SM_WRLVL, DDR_TRAINING_IP_SM_RDGATE, DDR_TRAINING_IP_SM_DQ_DQS, DDR_TRAINING_IP_SM_VERIFY, DDR_TRAINING_SET_FINAL_MODE, DDR_TRAINING_WRITE_CALIBRATION, DDR_TRAINING_WRITE_CALIBRATION_RETRY, /*!< Retry on calibration fail */ DDR_SWEEP_CHECK, DDR_SANITY_CHECKS, DDR_FULL_MTC_CHECK, DDR_FULL_32BIT_NC_CHECK, DDR_FULL_32BIT_CACHE_CHECK, DDR_LOAD_PATTERN_TO_CACHE, DDR_VERIFY_PATTERN_IN_CACHE, DDR_FULL_32BIT_WRC_CHECK, DDR_FULL_64BIT_NC_CHECK, DDR_FULL_64BIT_CACHE_CHECK, DDR_FULL_64BIT_WRC_CHECK, DDR_TRAINING_VREFDQ_CALIB, DDR_TRAINING_FPGA_VREFDQ_CALIB, DDR_TRAINING_FINISH_CHECK, DDR_TRAINING_FINISHED, DDR_TRAINING_FAIL_SM2_VERIFY, DDR_TRAINING_FAIL_SM_VERIFY, DDR_TRAINING_FAIL_SM_DQ_DQS, DDR_TRAINING_FAIL_SM_RDGATE, DDR_TRAINING_FAIL_SM_WRLVL, DDR_TRAINING_FAIL_SM_ADDCMD, DDR_TRAINING_FAIL_SM_BCLKSCLK, DDR_TRAINING_FAIL_BCLKSCLK_SW, DDR_TRAINING_FAIL_FULL_32BIT_NC_CHECK, DDR_TRAINING_FAIL_32BIT_CACHE_CHECK, DDR_TRAINING_FAIL_MIN_LATENCY, DDR_TRAINING_FAIL_START_CHECK, DDR_TRAINING_FAIL_PLL_LOCK, DDR_TRAINING_FAIL_DDR_SANITY_CHECKS, DDR_SWEEP_AGAIN } DDR_TRAINING_SM; /***************************************************************************//** */ typedef enum { USR_CMD_GET_DDR_STATUS = 0x00, //!< USR_CMD_GET_DDR_STATUS USR_CMD_GET_MODE_SETTING = 0x01, //!< USR_CMD_GET_MODE_SETTING USR_CMD_GET_W_CALIBRATION = 0x02, //!< USR_CMD_GET_W_CALIBRATION USR_CMD_GET_GREEN_ZONE = 0x03, //!< USR_CMD_GET_GREEN_ZONE USR_CMD_GET_REG = 0x04 //!< USR_CMD_GET_REG } DDR_USER_GET_COMMANDS_t; /***************************************************************************//** */ typedef enum { USR_CMD_SET_GREEN_ZONE_DQ = 0x80, //!< USR_CMD_SET_GREEN_ZONE_DQ USR_CMD_SET_GREEN_ZONE_DQS = 0x81, //!< USR_CMD_SET_GREEN_ZONE_DQS USR_CMD_SET_GREEN_ZONE_VREF_MAX = 0x82, //!< USR_CMD_SET_GREEN_ZONE_VREF USR_CMD_SET_GREEN_ZONE_VREF_MIN = 0x83, //!< USR_CMD_SET_GREEN_ZONE_VREF USR_CMD_SET_RETRAIN = 0x84, //!< USR_CMD_SET_RETRAIN USR_CMD_SET_REG = 0x85 //!< USR_CMD_SET_REG } DDR_USER_SET_COMMANDS_t; /***************************************************************************//** */ typedef enum SWEEP_STATES_{ INIT_SWEEP, //!< start the sweep ADDR_CMD_OFFSET_SWEEP, //!< sweep address command BCLK_SCLK_OFFSET_SWEEP, //!< sweep bclk sclk DPC_VRGEN_V_SWEEP, //!< sweep vgen_v DPC_VRGEN_H_SWEEP, //!< sweep vgen_h DPC_VRGEN_VS_SWEEP, //!< VS sweep FINISHED_SWEEP, //!< finished sweep } SWEEP_STATES; /***************************************************************************//** */ typedef enum { USR_OPTION_tip_register_dump = 0x00 //!< USR_OPTION_tip_register_dump } USR_STATUS_OPTION_t; #define MAX_LANES 5 /***************************************************************************//** */ typedef enum SEG_SETUP_{ DEFAULT_SEG_SETUP = 0x00, LIBERO_SEG_SETUP } SEG_SETUP; /***************************************************************************//** */ typedef struct mss_ddr_diags_{ uint64_t train_time; uint32_t num_retrains; uint32_t padding; } mss_ddr_diag; /***************************************************************************//** */ typedef struct mss_ddr_fpga_vref_{ uint32_t status_lower; uint32_t status_upper; uint32_t lower; uint32_t upper; uint32_t vref_result; } mss_ddr_vref; /** * \brief dll sgmii SCB regs */ typedef struct IOSCB_BANKCONT_DDR_ { /* bit0 - This when asserted resets all the non-volatile register bits e.g. RW-P bits, the bit self clears i.e. is similar to a W1P bit */ /* bit1 - This when asserted resets all the register bits apart from the non-volatile registers, the bit self clears. i.e. is similar to a W1P bit */ __IO uint32_t soft_reset; /* bit8 - This asserts the functional reset of the block. It is asserted at power up. When written is stays asserted until written to 0. */ __IO uint32_t dpc_bits; /* bit 3:0: dpc_vs bank voltage select for pvt calibration */ /* : dpc_vrgen_h */ /* : dpc_vrgen_en_h */ /* : dpc_move_en_h */ /* : dpc_vrgen_v */ /* : dpc_vrgen_en_v */ /* : dpc_move_en_v */ __IO uint32_t bank_status; /* bit 0: Bank power on complete (active low for polling) */ /* bit 1: Bank calibration complete (active low for polling) */ } IOSCB_BANKCONT_DDR_STRUCT; #define IOSCB_BANKCONT_DDR_BASE 0x3E020000UL #define IOSCB_BANKCONT_DDR ((volatile IOSCB_BANKCONT_DDR_STRUCT *) IOSCB_BANKCONT_DDR_BASE) /***************************************************************************//** */ typedef struct mss_ddr_write_calibration_{ uint32_t status_lower; uint32_t lower[MAX_LANES]; uint32_t lane_calib_result; } mss_ddr_write_calibration; /***************************************************************************//** */ typedef struct mss_lpddr4_dq_calibration_{ uint32_t lower[MAX_LANES]; uint32_t upper[MAX_LANES]; uint32_t calibration_found[MAX_LANES]; } mss_lpddr4_dq_calibration; /***************************************************************************//** Calibration settings derived during write training */ typedef struct mss_ddr_calibration_{ /* CMSIS related defines identifying the UART hardware. */ mss_ddr_write_calibration write_cal; mss_lpddr4_dq_calibration dq_cal; mss_ddr_vref fpga_vref; mss_ddr_vref mem_vref; } mss_ddr_calibration; /***************************************************************************//** sweep index's */ typedef struct sweep_index_{ uint8_t cmd_index; uint8_t bclk_sclk_index; uint8_t dpc_vgen_index; uint8_t dpc_vgen_h_index; uint8_t dpc_vgen_vs_index; } sweep_index; /***************************************************************************//** */ uint8_t MSS_DDR_init_simulation ( void ); /***************************************************************************//** */ uint8_t MSS_DDR_training ( uint8_t ddr_type ); /***************************************************************************//** The ddr_state_machine() function runs a state machine which initializes and monitors the DDR @return This function returns status, see DDR_SS_STATUS enum Example: @code uint32_t ddr_status; ddr_status = ddr_state_machine(DDR_SS__INIT); while((ddr_status & DDR_SETUP_DONE) != DDR_SETUP_DONE) { ddr_status = ddr_state_machine(DDR_SS_MONITOR); } if ((ddr_status & DDR_SETUP_FAIL) != DDR_SETUP_FAIL) { error |= (0x1U << 2U); } @endcode */ uint32_t ddr_state_machine ( DDR_SS_COMMAND command ); /***************************************************************************//** The debug_read_ddrcfg() prints out the ddrcfg register values @return This function returns status, see DDR_SS_STATUS enum Example: @code debug_read_ddrcfg(); @endcode */ void debug_read_ddrcfg ( void ); /***************************************************************************//** The setup_ddr_segments() sets up seg regs @return none Example: @code setup_ddr_segments(DEFAULT_SEG_SETUP); @endcode */ void setup_ddr_segments ( SEG_SETUP option ); #ifdef __cplusplus } #endif #endif /* __MSS_DDRC_H_ */ mss_ddr_debug.c000066400000000000000000000672621432224323300376250ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_ddr_debug.h * @author Microchip FPGA Embedded Systems Solutions * @brief DDR write and read test functions * */ #include #include #include #include "mpfs_hal/mss_hal.h" #include "mss_nwc_init.h" /******************************************************************************* * Local Defines */ #define DDR_BASE 0x80000000u #define DDR_SIZE 0x40000000u #define PDMA_CHANNEL0_BASE_ADDRESS 0x3000000ULL #define PDMA_CHANNEL1_BASE_ADDRESS 0x3001000ULL #define PDMA_CHANNEL2_BASE_ADDRESS 0x3002000ULL #define PDMA_CHANNEL3_BASE_ADDRESS 0x3003000ULL const char *progress[3] = {"|\r", "/\r", "-\r"}; typedef void(*pattern_fct_t)(void); static uint32_t g_test_buffer_cached[765]; static uint32_t g_test_buffer_not_cached[765]; /******************************************************************************* * External Defines */ extern const uint32_t ddr_test_pattern[768]; /******************************************************************************* * External function declarations */ extern void pdma_transfer(uint64_t destination, uint64_t source, uint64_t size_in_bytes, uint64_t base_address); extern void pdma_transfer_complete( uint64_t base_address); /******************************************************************************* * Local data declarations */ #ifdef DEBUG_DDR_INIT mss_uart_instance_t *g_debug_uart; #endif uint64_t ddr_test; /******************************************************************************* * Local function declarations */ static uint32_t ddr_write ( volatile uint64_t *DDR_word_ptr,\ uint32_t no_of_access, uint8_t data_ptrn, DDR_ACCESS_SIZE data_size ); static uint32_t ddr_read ( volatile uint64_t *DDR_word_ptr,\ uint32_t no_of_access, uint8_t data_ptrn, DDR_ACCESS_SIZE data_size ); static void load_test_buffers(uint32_t * p_cached_ddr,\ uint32_t * p_not_cached_ddr, uint64_t length); #ifdef HSS __attribute__((weak)) int rand(void) { return(0); } #endif #ifdef DEBUG_DDR_INIT /***************************************************************************//** * Setup serial port if DDR debug required during start-up * @param uart Ref to uart you want to use * @return */ __attribute__((weak))\ uint32_t setup_ddr_debug_port(mss_uart_instance_t * uart) { #ifdef DEBUG_DDR_INIT /* Turn on UART0 clock */ SYSREG->SUBBLK_CLOCK_CR |= (SUBBLK_CLOCK_CR_MMUART0_MASK); /* Remove soft reset */ SYSREG->SOFT_RESET_CR &= (uint32_t)(~SUBBLK_CLOCK_CR_MMUART0_MASK); MSS_UART_init( uart, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); return(0U); #endif } /***************************************************************************//** * Print in number hex format * @param uart * @param b */ static void dumpbyte(mss_uart_instance_t * uart, uint8_t b) { #ifdef DEBUG_DDR_INIT const uint8_t hexchrs[] = { '0','1','2','3','4','5','6','7','8','9','A','B',\ 'C','D','E','F' }; MSS_UART_polled_tx(uart, &hexchrs[b >> 4u] , 1); MSS_UART_polled_tx(uart, &hexchrs[b & 0x0fu] , 1); #endif } /***************************************************************************//** * * @param uart * @param msg * @param d */ __attribute__((weak))\ void uprint32(mss_uart_instance_t * uart, const char* msg, uint32_t d) { MSS_UART_polled_tx_string(uart, (const uint8_t *)msg); for (unsigned i=0; i < 4; i++) { dumpbyte(uart, (d >> (8*(3-i))) & 0xffu); } } /***************************************************************************//** * * @param uart * @param msg * @param d */ __attribute__((weak))\ void uprint64(mss_uart_instance_t * uart, const char* msg, uint64_t d) { MSS_UART_polled_tx_string(uart, (const uint8_t *)msg); for (unsigned i=4; i < 8; i++) { dumpbyte(uart, (d >> (8*(3-i))) & 0xffu); } for (unsigned i=0; i < 4; i++) { dumpbyte(uart, (d >> (8*(3-i))) & 0xffu); } } /***************************************************************************//** * * @param uart * @param msg */ __attribute__((weak))\ void uprint(mss_uart_instance_t * uart, const char* msg) { MSS_UART_polled_tx_string(uart, (const uint8_t *)msg); } /***************************************************************************//** * dump a number of 32bit contiguous registers * @param uart * @param reg_pointer * @param no_of_regs */ void print_reg_array(mss_uart_instance_t * uart, uint32_t *reg_pointer,\ uint32_t no_of_regs) { #ifdef DEBUG_DDR_INIT while(no_of_regs > 0U) { uprint64(uart, "\n\rRegister, 0x", (uint64_t)reg_pointer); uprint32(uart, " ,Value, 0x", *reg_pointer); reg_pointer++; no_of_regs--; } #endif } #endif /***************************************************************************//** * Write data to DDR * @param DDR_word_ptr * @param no_of_access * @param data_ptrn * @return */ static uint32_t ddr_write ( volatile uint64_t *DDR_word_ptr, uint32_t no_of_access, uint8_t data_ptrn, DDR_ACCESS_SIZE data_size ) { uint32_t i; uint64_t DATA; uint32_t error_count = 0U; uint32_t *DDR_32_ptr = (uint32_t *)DDR_word_ptr; uint16_t *DDR_16_ptr = (uint16_t *)DDR_word_ptr; uint8_t *DDR_8_ptr = (uint8_t *)DDR_word_ptr; switch (data_ptrn) { case PATTERN_INCREMENTAL : DATA = 0x00000000; break; case PATTERN_WALKING_ONE : DATA = 0x00000001; break; case PATTERN_WALKING_ZERO : DATA = 0x01; DATA = ~ DATA; break; case PATTERN_RANDOM : DATA = (uint64_t)rand ( ); break; case PATTERN_0xCCCCCCCC : DATA = 0xCCCCCCCCCCCCCCCC; break; case PATTERN_0x55555555 : DATA = 0x5555555555555555; break; case PATTERN_ZEROS : DATA = 0x00000000; break; default : DATA = 0x00000000; break; } for( i = 0; i< (no_of_access); i++) { switch(data_size) { case DDR_8_BIT: DATA &= 0xFFUL; *DDR_8_ptr = (uint8_t)DATA; DDR_8_ptr = DDR_8_ptr + 1; break; case DDR_16_BIT: DATA &= 0xFFFFUL; *DDR_16_ptr = (uint16_t)DATA; DDR_16_ptr = DDR_16_ptr + 1; break; case DDR_32_BIT: DATA &= 0xFFFFFFFFUL; *DDR_32_ptr = (uint32_t)DATA; DDR_32_ptr = DDR_32_ptr + 1; break; default: case DDR_64_BIT: *DDR_word_ptr = DATA; DDR_word_ptr = DDR_word_ptr + 1; break; } #ifdef DEBUG_DDR_INIT if((i%0x1000000UL) ==0UL) { MSS_UART_polled_tx(g_debug_uart, (const uint8_t*)"w", (uint32_t)1UL); } #endif switch (data_ptrn) { case PATTERN_INCREMENTAL : DATA = DATA + 0x00000001; break; case PATTERN_WALKING_ONE : if (DATA == 0x80000000) DATA = 0x00000001; else DATA = (DATA << 1); break; case PATTERN_WALKING_ZERO : DATA = ~DATA; if (DATA == 0x80000000) DATA = 0x00000001; else { DATA = (DATA << 1); } DATA = ~DATA; break; case PATTERN_RANDOM : DATA = (uint64_t)rand ( ); break; case PATTERN_0xCCCCCCCC : DATA = 0xCCCCCCCCCCCCCCCC; break; case PATTERN_0x55555555 : DATA = 0x5555555555555555; break; case PATTERN_ZEROS : DATA = 0x00000000; break; default : break; } } return error_count; } /***************************************************************************//** * Reads and compares with what was written * @param DDR_word_ptr * @param no_of_access * @param data_ptrn * @return 0 => read backs all expected value, otherwise error count */ uint32_t ddr_read ( volatile uint64_t *DDR_word_ptr, uint32_t no_of_access, uint8_t data_ptrn, DDR_ACCESS_SIZE data_size ) { uint32_t i; uint64_t DATA; uint32_t err_cnt; volatile uint64_t ddr_data; volatile uint64_t *DDR_word_pt_t, *first_DDR_word_pt_t; uint32_t rand_addr_offset; uint8_t *DDR_8_pt_t; uint16_t *DDR_16_pt_t; uint32_t *DDR_32_pt_t; err_cnt = 0U; first_DDR_word_pt_t = DDR_word_ptr; DDR_8_pt_t = (uint8_t *)DDR_word_ptr; DDR_16_pt_t = (uint16_t *)DDR_word_ptr; DDR_32_pt_t = (uint32_t *)DDR_word_ptr; switch (data_ptrn) { case PATTERN_INCREMENTAL : DATA = 0x00000000; break; case PATTERN_WALKING_ONE : DATA = 0x00000001; break; case PATTERN_WALKING_ZERO : DATA = 0x01; DATA = ~ DATA; break; case PATTERN_RANDOM : DATA = (uint64_t)rand ( ); *DDR_word_ptr = DATA; *DDR_8_pt_t = (uint8_t)DATA; *DDR_16_pt_t = (uint16_t)DATA; *DDR_32_pt_t = (uint32_t)DATA; break; case PATTERN_0xCCCCCCCC : DATA = 0xCCCCCCCCCCCCCCCC; break; case PATTERN_0x55555555 : DATA = 0x5555555555555555; break; case PATTERN_ZEROS : DATA = 0x00000000; break; default : DATA = 0x00000000; break; } if (data_ptrn == '4') { delay(DELAY_CYCLES_500_NS); } for( i = 0; i< (no_of_access); i++) { switch(data_size) { case DDR_8_BIT: DATA &= 0xFFUL; ddr_data = *DDR_8_pt_t; break; case DDR_16_BIT: DATA &= 0xFFFFUL; ddr_data = *DDR_16_pt_t; break; case DDR_32_BIT: DATA &= 0xFFFFFFFFUL; ddr_data = *DDR_32_pt_t; break; default: case DDR_64_BIT: DDR_word_pt_t = DDR_word_ptr; ddr_data = *DDR_word_pt_t; break; } #ifdef DEBUG_DDR_INIT if((i%0x1000000UL) ==0UL) { MSS_UART_polled_tx(g_debug_uart, (const uint8_t*)"r", (uint32_t)1UL); } #endif if (ddr_data != DATA) { #ifdef DEBUG_DDR_INIT #ifdef DEBUG_DDR_RD_RW_FAIL if (err_cnt <=0xF) { uprint64(g_debug_uart,\ "\n\r READ/ WRITE ACCESS FAILED AT ADDR: 0x ",\ (uintptr_t)DDR_word_ptr); uprint64(g_debug_uart,"\t Expected Data 0x ", DATA); uprint64(g_debug_uart,"\t READ DATA: 0x ", ddr_data); uprint64(g_debug_uart,"\t READ DATA: 0x ", *DDR_word_ptr); uprint64(g_debug_uart,"\t READ DATA: 0x ", *DDR_word_ptr); } #endif #endif err_cnt++; } else { #ifdef DEBUG_DDR_RD_RW_PASS //printf("\n\r READ/ WRITE ACCESS passED AT ADDR: 0x%x expected data = 0x%x, Data read 0x%x",DDR_word_ptr, DATA, *DDR_word_ptr); uprint64(g_debug_uart, "\n\r READ/ WRITE ACCESS PASSED AT ADDR: 0x"\ , (uintptr_t)DDR_word_ptr); uprint64(g_debug_uart,"\t READ DATA: 0x", *DDR_word_ptr); #endif } DDR_word_ptr = DDR_word_ptr + 1U; DDR_8_pt_t = DDR_8_pt_t +1U; DDR_16_pt_t = DDR_16_pt_t +1U; DDR_32_pt_t = DDR_32_pt_t +1U; switch (data_ptrn) { case PATTERN_INCREMENTAL : DATA = DATA + 0x01; break; case PATTERN_WALKING_ONE : if (DATA == 0x80000000) DATA = 0x00000001; else DATA = (DATA << 1); break; case PATTERN_WALKING_ZERO : DATA = ~DATA; if (DATA == 0x80000000) { DATA = 0x00000001; } else { DATA = (DATA << 1); } DATA = ~DATA; break; case PATTERN_RANDOM : DATA = (uint64_t)rand ( ); rand_addr_offset = (uint32_t)(rand() & 0xFFFFCUL); DDR_word_ptr = first_DDR_word_pt_t + rand_addr_offset; DDR_8_pt_t = (uint8_t *)(first_DDR_word_pt_t + rand_addr_offset); DDR_16_pt_t = (uint16_t *)(first_DDR_word_pt_t + rand_addr_offset); DDR_32_pt_t = (uint32_t *)(first_DDR_word_pt_t + rand_addr_offset); *DDR_word_ptr = DATA; *DDR_8_pt_t = (uint8_t)DATA; *DDR_16_pt_t = (uint16_t)DATA; *DDR_32_pt_t = (uint32_t)DATA; break; case PATTERN_0xCCCCCCCC : DATA = 0xCCCCCCCCCCCCCCCC; break; case PATTERN_0x55555555 : DATA = 0x5555555555555555; break; case PATTERN_ZEROS : DATA = 0x00000000; break; default : break; } } return (err_cnt); } /***************************************************************************//** * * @param DDR_word_ptr Address * @param no_access Number of addresses * @param pattern bit mask with patterns you want to test against * @return */ uint32_t ddr_read_write_fn (uint64_t* DDR_word_ptr, uint32_t no_access,\ uint32_t pattern) { uint32_t error_cnt = 0U; uint8_t pattern_mask; for (unsigned i=0; i < 1; i++) { for (uint32_t pattern_shift=0U; pattern_shift < MAX_NO_PATTERNS;\ pattern_shift++) { pattern_mask = (uint8_t)(0x01U << pattern_shift); if(pattern & pattern_mask) { #ifdef DEBUG_DDR_INIT uprint32(g_debug_uart,"\n\r\t Pattern: 0x", pattern_shift); #endif #if TEST_64BIT_ACCESS == 1 /* write the pattern */ error_cnt += ddr_write ((uint64_t *)DDR_word_ptr,\ no_access, pattern_mask, DDR_64_BIT); /* read back and verifies */ error_cnt += ddr_read ((uint64_t *)DDR_word_ptr, \ no_access, pattern_mask, DDR_64_BIT); #endif #if TEST_32BIT_ACCESS == 1 /* write the pattern */ error_cnt += ddr_write ((uint64_t *)DDR_word_ptr,\ no_access, pattern_mask, DDR_32_BIT); /* read back and verifies */ error_cnt += ddr_read ((uint64_t *)DDR_word_ptr, \ no_access, pattern_mask, DDR_32_BIT); #endif } } DDR_word_ptr++; /* increment the address */ } return error_cnt; } /***************************************************************************//** * * @param error * @return */ #ifdef DEBUG_DDR_INIT uint32_t error_status(mss_uart_instance_t *g_mss_uart_debug_pt, uint32_t error) { uprint32(g_mss_uart_debug_pt, "\n\r ERROR_RESULT: ", error); return (0U); } #endif /***************************************************************************//** * Calibration status * @return */ #ifdef DEBUG_DDR_INIT uint32_t wrcalib_status(mss_uart_instance_t *g_mss_uart_debug_pt) { uprint32(g_mss_uart_debug_pt, "\n\r WRCALIB_RESULT: ",\ CFG_DDR_SGMII_PHY->expert_wrcalib.expert_wrcalib); return (0U); } #endif #ifdef DEBUG_DDR_INIT /***************************************************************************//** * Prints out DDR status * @return */ uint32_t tip_register_status (mss_uart_instance_t *g_mss_uart_debug_pt) { uint32_t t_status = 0U; uint32_t MSS_DDR_APB_ADDR; uint32_t ddr_lane_sel; uint32_t rank_sel; uint32_t dq0_dly = 0U; uint32_t dq1_dly = 0U; uint32_t dq2_dly = 0U; uint32_t dq3_dly = 0U; uint32_t dq4_dly = 0U; uint32_t dq5_dly = 0U; /* MSS_UART_polled_tx_string(g_mss_uart_debug_pt, "\n\n\r TIP register status \n"); delay(DELAY_CYCLES_50_MICRO);*/ uprint32(g_mss_uart_debug_pt, "\n\r\n\r training status = ",\ CFG_DDR_SGMII_PHY->training_status.training_status); uprint32(g_mss_uart_debug_pt, "\n\r PCODE = ",\ (CFG_DDR_SGMII_PHY->IOC_REG2.IOC_REG2 & 0x7F)); uprint32(g_mss_uart_debug_pt, "\n\r NCODE = ",\ (((CFG_DDR_SGMII_PHY->IOC_REG2.IOC_REG2) >> 7) & 0x7F)); uprint32(g_mss_uart_debug_pt, "\n\r WRCALIB_RESULT: "\ , CFG_DDR_SGMII_PHY->expert_wrcalib.expert_wrcalib); uprint32(g_mss_uart_debug_pt, "\n\r sro_ref_slewr = ",\ (((CFG_DDR_SGMII_PHY->IOC_REG5.IOC_REG5) >> 0) & 0x3F)); uprint32(g_mss_uart_debug_pt, "\n\r sro_ref_slewf = ",\ (((CFG_DDR_SGMII_PHY->IOC_REG5.IOC_REG5) >> 6) & 0xFFF)); uprint32(g_mss_uart_debug_pt, "\n\r sro_slewr = ",\ (((CFG_DDR_SGMII_PHY->IOC_REG5.IOC_REG5) >> 18) & 0x3F)); uprint32(g_mss_uart_debug_pt, "\n\r sro_slewf = ",\ (((CFG_DDR_SGMII_PHY->IOC_REG5.IOC_REG5) >> 24) & 0x3F)); for (rank_sel=0; rank_sel < LIBERO_SETTING_CFG_NUM_RANKS; rank_sel++) { CFG_DDR_SGMII_PHY->rank_select.rank_select=rank_sel; uprint32(g_mss_uart_debug_pt, "\n\r\n\r rank number", rank_sel); MSS_UART_polled_tx_string(g_mss_uart_debug_pt, \ (const uint8_t*)"\n\n\r lane_select \t gt_err_comb \t gt_txdly \t gt_steps_180 \t gt_state \t wl_delay_0 \t dqdqs_err_done \t dqdqs_state \t delta0 \t delta1"); for (ddr_lane_sel=0U; ddr_lane_sel < LIBERO_SETTING_DATA_LANES_USED; ddr_lane_sel++) { CFG_DDR_SGMII_PHY->lane_select.lane_select = ddr_lane_sel; uprint32(g_mss_uart_debug_pt, "\n\r ", CFG_DDR_SGMII_PHY->lane_select.lane_select); delay(DELAY_CYCLES_50_MICRO); MSS_DDR_APB_ADDR = CFG_DDR_SGMII_PHY->gt_err_comb.gt_err_comb; uprint32(g_mss_uart_debug_pt, "\t ", MSS_DDR_APB_ADDR); t_status = t_status | MSS_DDR_APB_ADDR; MSS_DDR_APB_ADDR = CFG_DDR_SGMII_PHY->gt_txdly.gt_txdly; uprint32(g_mss_uart_debug_pt, "\t ", MSS_DDR_APB_ADDR); if((MSS_DDR_APB_ADDR & 0xFF) == 0) t_status = 1; if((MSS_DDR_APB_ADDR & 0xFF00) == 0) t_status = 1; if((MSS_DDR_APB_ADDR & 0xFF0000) == 0) t_status = 1; if((MSS_DDR_APB_ADDR & 0xFF000000) == 0) t_status = 1; uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->gt_steps_180.gt_steps_180); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->gt_state.gt_state); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->wl_delay_0.wl_delay_0); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->dq_dqs_err_done.dq_dqs_err_done); t_status = t_status | (MSS_DDR_APB_ADDR != 8); uprint32(g_mss_uart_debug_pt, "\t\t ",\ CFG_DDR_SGMII_PHY->dqdqs_state.dqdqs_state); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->delta0.delta0); dq0_dly = (MSS_DDR_APB_ADDR & 0xFF); dq1_dly = (MSS_DDR_APB_ADDR & 0xFF00) >> 8; dq2_dly = (MSS_DDR_APB_ADDR & 0xFF0000) >> 16; dq3_dly = (MSS_DDR_APB_ADDR & 0xFF000000) >> 24; uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->delta1.delta1); dq4_dly = (MSS_DDR_APB_ADDR & 0xFF); dq5_dly = (MSS_DDR_APB_ADDR & 0xFF00) >> 8; dq2_dly = (MSS_DDR_APB_ADDR & 0xFF0000) >> 16; dq3_dly = (MSS_DDR_APB_ADDR & 0xFF000000) >> 24; } MSS_UART_polled_tx_string(g_mss_uart_debug_pt, (const uint8_t*)"\n\r\n\r lane_select\t rdqdqs_status2\t addcmd_status0\t addcmd_status1\t addcmd_answer1\t dqdqs_status1\n\r"); for (ddr_lane_sel=0U; ddr_lane_sel < LIBERO_SETTING_DATA_LANES_USED;\ ddr_lane_sel++) { CFG_DDR_SGMII_PHY->lane_select.lane_select = ddr_lane_sel; uprint32(g_mss_uart_debug_pt, "\n\r ",\ CFG_DDR_SGMII_PHY->lane_select.lane_select); delay(DELAY_CYCLES_50_MICRO); if(dq0_dly > 20) t_status = 1; if(dq1_dly > 20) t_status = 1; if(dq2_dly > 20) t_status = 1; if(dq3_dly > 20) t_status = 1; if(dq4_dly > 20) t_status = 1; if(dq5_dly > 20) t_status = 1; uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->dqdqs_status2.dqdqs_status2); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->addcmd_status0.addcmd_status0); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->addcmd_status1.addcmd_status1); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->addcmd_answer.addcmd_answer); uprint32(g_mss_uart_debug_pt, "\t ",\ CFG_DDR_SGMII_PHY->dqdqs_status1.dqdqs_status1); } } /* end rank select */ return(t_status); } #endif /** * Load a pattern to DDR */ void load_ddr_pattern(uint64_t base, uint32_t size, uint8_t pattern_offset) { int alive = 0; uint8_t *p_ddr = (uint8_t *)base; uint32_t pattern_length = (uint32_t)(sizeof(ddr_test_pattern) - pattern_offset) ; #ifdef DEBUG_DDR_INIT uprint(g_debug_uart, (const char*)(const uint8_t*)"\r\nLoading test pattern\r\n"); #endif while(((uint64_t)p_ddr + pattern_length) < (base + size)) { switch ( ((uint64_t)p_ddr)%8U ) { case 0: case 4: pdma_transfer_complete(PDMA_CHANNEL0_BASE_ADDRESS); pdma_transfer((uint64_t)p_ddr, (uint64_t)ddr_test_pattern, pattern_length, PDMA_CHANNEL0_BASE_ADDRESS); break; case 1: case 5: pdma_transfer_complete(PDMA_CHANNEL1_BASE_ADDRESS); pdma_transfer((uint64_t)p_ddr, (uint64_t)ddr_test_pattern, pattern_length, PDMA_CHANNEL1_BASE_ADDRESS); break; case 2: case 6: pdma_transfer_complete(PDMA_CHANNEL2_BASE_ADDRESS); pdma_transfer((uint64_t)p_ddr, (uint64_t)ddr_test_pattern, pattern_length, PDMA_CHANNEL2_BASE_ADDRESS); break; case 3: case 7: pdma_transfer_complete(PDMA_CHANNEL3_BASE_ADDRESS); pdma_transfer((uint64_t)p_ddr, (uint64_t)ddr_test_pattern, pattern_length, PDMA_CHANNEL3_BASE_ADDRESS); break; } p_ddr = p_ddr + (pattern_length); alive++; if (alive > 1000) { alive = 0; #ifdef DEBUG_DDR_INIT uprint(g_debug_uart, (const char*)"."); #endif } } #ifdef DEBUG_DDR_INIT uprint(g_debug_uart, (const char*)"\r\nFinished loading test pattern\r\n"); #endif pdma_transfer_complete(PDMA_CHANNEL0_BASE_ADDRESS); pdma_transfer_complete(PDMA_CHANNEL1_BASE_ADDRESS); pdma_transfer_complete(PDMA_CHANNEL2_BASE_ADDRESS); pdma_transfer_complete(PDMA_CHANNEL3_BASE_ADDRESS); } /** * Run from address * @param start_addr address to run from. */ void execute_ddr_pattern(uint64_t start_addr) { pattern_fct_t p_pattern_fct = (pattern_fct_t)start_addr; (*p_pattern_fct)(); } /** * Loads DDR with a pattern that triggers read issues if not enough margin. * Used to verify training is successful. * @param p_cached_ddr * @param p_not_cached_ddr * @param length */ static void load_test_buffers(uint32_t * p_cached_ddr, uint32_t * p_not_cached_ddr, uint64_t length) { (void)length; pdma_transfer((uint64_t)g_test_buffer_cached, (uint64_t)p_cached_ddr, length, PDMA_CHANNEL0_BASE_ADDRESS); pdma_transfer((uint64_t)g_test_buffer_not_cached, (uint64_t)p_not_cached_ddr, length, PDMA_CHANNEL1_BASE_ADDRESS); pdma_transfer_complete(PDMA_CHANNEL0_BASE_ADDRESS); pdma_transfer_complete(PDMA_CHANNEL1_BASE_ADDRESS); } /** * test_ddr reads from cached and non cached DDR and compares * @param no_of_iterations * @param size * @return returns 1 if compare fails */ uint32_t test_ddr(uint32_t no_of_iterations, uint32_t size) { uint32_t pattern_length = sizeof(ddr_test_pattern) - (3 * sizeof(uint32_t)); uint32_t * p_ddr_cached = (uint32_t *)0x80000000; uint32_t * p_ddr_noncached = (uint32_t *)0x1400000000; uint32_t word_offset; uint32_t alive = 0; uint32_t alive_idx = 0U; uint32_t iteration = 0U; uint32_t error = 0U; #ifdef DEBUG_DDR_INIT uprint(g_debug_uart, (const char*)"\r\nStarting ddr test\r\n"); #endif while(iteration < no_of_iterations) { int different = 0; load_test_buffers(p_ddr_cached, p_ddr_noncached, pattern_length); different = memcmp(g_test_buffer_cached, g_test_buffer_not_cached, pattern_length); if(different != 0) { for(word_offset = 0; word_offset < (pattern_length / sizeof(uint32_t)); word_offset++) { if(g_test_buffer_cached[word_offset] != g_test_buffer_not_cached[word_offset]) { #ifdef DEBUG_DDR_INIT uprint64(g_debug_uart, " Mismatch, 0x", (uint64_t)p_ddr_cached); uprint32(g_debug_uart, " offset:, 0x", (uint64_t)word_offset); uprint64(g_debug_uart, " address: 0x", (uint64_t)(p_ddr_cached + word_offset)); uprint32(g_debug_uart, " expected (non-cached): 0x", g_test_buffer_not_cached[word_offset]); uprint32(g_debug_uart, " found (cached): 0x", (uint64_t)g_test_buffer_cached[word_offset]); uprint32(g_debug_uart, " direct cached read: 0x", (uint32_t)*(p_ddr_cached + word_offset)); uprint32(g_debug_uart, " direct non-cached read: 0x", (uint32_t)*(p_ddr_noncached + word_offset)); #endif break; } } error = 1U; return error; } if (((uint64_t)p_ddr_cached + ( 2 * pattern_length)) < (LIBERO_SETTING_DDR_32_CACHE + size)) { p_ddr_cached += (pattern_length / sizeof(uint32_t)); p_ddr_noncached += (pattern_length / sizeof(uint32_t)); } else { p_ddr_cached = (uint32_t *)0x80000000; p_ddr_noncached = (uint32_t *)0x1400000000; iteration++; #ifdef DEBUG_DDR_INIT uprint32(g_debug_uart, " Iteration ", (uint64_t)(unsigned int)iteration); #endif } alive++; if(alive > 10000U) { alive = 0; #ifdef DEBUG_DDR_INIT uprint(g_debug_uart, (const char*)"\r"); uprint(g_debug_uart, (const char*)progress[alive_idx]); #endif alive_idx++; if(alive_idx >= 3U) { alive_idx = 0; } if(ddr_test == 2U) { #ifdef DEBUG_DDR_INIT uprint(g_debug_uart, (const char*)"\r\nEnding ddr test. Press 0 to display the menu\r\n"); #endif return error; } } } return error; } mss_ddr_debug.h000066400000000000000000000127341432224323300376240ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_ddr_debug.h * @author Microchip-FPGA Embedded Systems Solutions * @brief mss_ddr_debug related defines * */ /*=========================================================================*//** @page DDR setup and monitoring ============================================================================== @section intro_sec Introduction ============================================================================== DDR debug helper functions ============================================================================== @section Items located in the north west corner ============================================================================== - ============================================================================== @section Overview of DDR related hardware ============================================================================== *//*=========================================================================*/ #include #include #ifndef __MSS_DDr_DEBUG_H_ #define __MSS_DDr_DEBUG_H_ 1 #ifdef DEBUG_DDR_INIT #include "drivers/mss/mss_mmuart/mss_uart.h" #endif #ifdef __cplusplus extern "C" { #endif #ifndef TEST_64BIT_ACCESS #define TEST_64BIT_ACCESS 1 #endif #ifndef TEST_32BIT_ACCESS #define TEST_32BIT_ACCESS 1 #endif typedef enum DDR_ACCESS_SIZE_ { DDR_8_BIT, DDR_16_BIT, DDR_32_BIT, DDR_64_BIT } DDR_ACCESS_SIZE; /***************************************************************************//** The ddr_read_write_fn function is used to write/read test patterns to the DDR @return This function returns 0 if successful, number of errors if not. Example: @code if (ddr_read_write_fn() != 0U) { .. warn the user, increment error count , wait for watchdog reset } @endcode */ uint32_t ddr_read_write_fn ( uint64_t* DDR_word_ptr, uint32_t no_access, uint32_t pattern ); #ifdef DEBUG_DDR_INIT /***************************************************************************//** The uprint32() function is used to print to the designated debug port Example: @code (void)uprint32(g_debug_uart, "\n\r DDR_TRAINING_FAIL: ", error); @endcode */ void uprint32 ( mss_uart_instance_t * uart, const char* msg, uint32_t d ); /***************************************************************************//** The uprint64() function is used to print to the designated debug port Example: @code (void)uprint64(g_debug_uart, "\n\r DDR_TRAINING_FAIL: ", error); @endcode */ void uprint64 ( mss_uart_instance_t * uart, const char* msg, uint64_t d ); /***************************************************************************//** The uprint() function is used to print to the designated debug port Example: @code (void)uprint(g_debug_uart, "\n\r DDR_TRAINING_FAIL: "); @endcode */ void uprint ( mss_uart_instance_t * uart, const char* msg ); /***************************************************************************//** The error_status() function is used to print to the designated debug port Example: @code (void)error_status(g_debug_uart, "\n\r DDR_TRAINING_FAIL: ", error); @endcode */ uint32_t error_status(mss_uart_instance_t *g_mss_uart_debug_pt, uint32_t error); /***************************************************************************//** The wrcalib_status() function is used to print to the designated debug port Example: @code (void)wrcalib_status(mss_uart_instance_t *g_mss_uart_debug_pt); @endcode */ uint32_t wrcalib_status(mss_uart_instance_t *g_mss_uart_debug_pt); /***************************************************************************//** The tip_register_status() function is used to print ddr TIP status to the designated debug port Example: @code (void)tip_register_status(mss_uart_instance_t *g_mss_uart_debug_pt); @endcode */ uint32_t tip_register_status (mss_uart_instance_t *g_mss_uart_debug_pt); /***************************************************************************//** The setup_ddr_debug_port() function is used to setup a serial port dedicated to printing information on the DDR start-up. @return This function returns 0 if successful Example: @code if (ddr_setup() != 0U) { .. warn the user, increment error count , wait for watchdog reset } @endcode */ uint32_t setup_ddr_debug_port ( mss_uart_instance_t * uart ); /***************************************************************************//** * */ void sweep_status ( mss_uart_instance_t *g_mss_uart_debug_pt ); /***************************************************************************//** * */ void print_reg_array ( mss_uart_instance_t * uart, uint32_t *reg_pointer, uint32_t no_of_regs ); #endif /***************************************************************************//** * */ void load_ddr_pattern ( uint64_t base, uint32_t size, uint8_t pattern_offset ); /***************************************************************************//** * */ uint32_t test_ddr ( uint32_t no_of_iterations, uint32_t size ); /***************************************************************************//** * */ void execute_ddr_pattern ( uint64_t start_addr ); #ifdef __cplusplus } #endif #endif /* __MSS_DDRC_H_ */ mss_ddr_defs.h000066400000000000000000000042461432224323300374560ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_ddr_defs.h * @author Microchip-FPGA Embedded Systems Solutions * @brief mss_ddr_debug related defines * */ #ifndef SRC_PLATFORM_MPFS_HAL_NWC_MSS_DDR_DEFS_H_ #define SRC_PLATFORM_MPFS_HAL_NWC_MSS_DDR_DEFS_H_ #define PATTERN_INCREMENTAL (0x01U << 0U) #define PATTERN_WALKING_ONE (0x01U << 1U) #define PATTERN_WALKING_ZERO (0x01U << 2U) #define PATTERN_RANDOM (0x01U << 3U) #define PATTERN_0xCCCCCCCC (0x01U << 4U) #define PATTERN_0x55555555 (0x01U << 5U) #define PATTERN_ZEROS (0x01U << 6U) #define MAX_NO_PATTERNS 7U /* Training types status offsets */ #define BCLK_SCLK_BIT (0x1U<<0U) #define ADDCMD_BIT (0x1U<<1U) #define WRLVL_BIT (0x1U<<2U) #define RDGATE_BIT (0x1U<<3U) #define DQ_DQS_BIT (0x1U<<4U) /* The first five bits represent the currently supported training in the TIP */ /* This value will not change unless more training possibilities are added to * the TIP */ #define TRAINING_MASK (BCLK_SCLK_BIT|\ ADDCMD_BIT|\ WRLVL_BIT|\ RDGATE_BIT|\ DQ_DQS_BIT) /* supported clk speeds, these values come from the MSS Configurator in the following define - LIBERO_SETTING_DDR_CLK */ #define DDR_1067_MHZ 1067000000UL #define DDR_1333_MHZ 1332000000UL #define DDR_1600_MHZ 1600000000UL #define DDR_FREQ_MARGIN 10UL /* * Error flags for ADD_CMD */ #define DDR_ADD_CMD_A5_OFFSET_PASS 0x00 #define DDR_ADD_CMD_A5_OFFSET_FAIL 0x01 #define DDR_ADD_CMD_A5_OFFSET_FAIL_LOW_FREQ 0x04 #endif /* SRC_PLATFORM_MPFS_HAL_NWC_MSS_DDR_DEFS_H_ */ mss_ddr_sgmii_phy_defs.h000066400000000000000000007147411432224323300415360ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_ddr_sgmii_phy_defs.h * @author Microchip-FPGA Embedded Systems Solutions * @brief Register bit offsets and masks definitions for MPFS MSS DDR * This was generated directly from the RTL * */ #ifndef MSS_DDR_SGMII_PHY_DEFS_H_ #define MSS_DDR_SGMII_PHY_DEFS_H_ #include "mpfs_hal/mss_hal.h" #ifdef __cplusplus extern "C" { #endif #ifndef __I #define __I const volatile #endif #ifndef __IO #define __IO volatile #endif #ifndef __O #define __O volatile #endif /*----------------------------------------------------------------------------*/ /*----------------------------------- DDR -----------------------------------*/ /*----------------------------------------------------------------------------*/ /*============================== CFG_DDR_SGMII_PHY definitions ===========================*/ typedef enum { /*!< SOFT_RESET_DDR_PHY.PERIPH_DDR_PHY bitfield definition*/ scb_periph_not_in_soft_reset_ddr_phy = 0, scb_periph_reset_ddr_phy = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_PERIPH_DDR_PHY_TypeDef; typedef enum { /*!< SOFT_RESET_DDR_PHY.V_MAP_DDR_PHY bitfield definition*/ scb_v_regs_not_in_soft_reset_ddr_phy = 0, scb_v_regs_reset_ddr_phy = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_V_MAP_DDR_PHY_TypeDef; typedef enum { /*!< SOFT_RESET_DDR_PHY.NV_MAP_DDR_PHY bitfield definition*/ scb_nv_regs_not_in_soft_reset_ddr_phy = 0, scb_nv_regs_reset_ddr_phy = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_NV_MAP_DDR_PHY_TypeDef; typedef enum { /*!< SOFT_RESET_MAIN_PLL.BLOCKID_MAIN_PLL bitfield definition*/ block_address_main_pll = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_BLOCKID_MAIN_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_MAIN_PLL.PERIPH_MAIN_PLL bitfield definition*/ scb_periph_not_in_soft_reset_main_pll = 0, scb_periph_reset_main_pll = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_PERIPH_MAIN_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_MAIN_PLL.V_MAP_MAIN_PLL bitfield definition*/ scb_v_regs_not_in_soft_reset_main_pll = 0, scb_v_regs_reset_main_pll = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_V_MAP_MAIN_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_MAIN_PLL.NV_MAP_MAIN_PLL bitfield definition*/ scb_nv_regs_not_in_soft_reset_main_pll = 0, scb_nv_regs_reset_main_pll = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_NV_MAP_MAIN_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_IOSCB_PLL.BLOCKID_IOSCB_PLL bitfield definition*/ block_address_ioscb_pll = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_BLOCKID_IOSCB_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_IOSCB_PLL.PERIPH_IOSCB_PLL bitfield definition*/ scb_periph_not_in_soft_reset_ioscb_pll = 0, scb_periph_reset_ioscb_pll = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_PERIPH_IOSCB_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_IOSCB_PLL.V_MAP_IOSCB_PLL bitfield definition*/ scb_v_regs_not_in_soft_reset_ioscb_pll = 0, scb_v_regs_reset_ioscb_pll = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_V_MAP_IOSCB_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_IOSCB_PLL.NV_MAP_IOSCB_PLL bitfield definition*/ scb_nv_regs_not_in_soft_reset_ioscb_pll = 0, scb_nv_regs_reset_ioscb_pll = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_NV_MAP_IOSCB_PLL_TypeDef; typedef enum { /*!< SOFT_RESET_BANK_CTRL.BLOCKID_BANK_CTRL bitfield definition*/ block_address_bank_ctrl = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_BLOCKID_BANK_CTRL_TypeDef; typedef enum { /*!< SOFT_RESET_BANK_CTRL.PERIPH_BANK_CTRL bitfield definition*/ scb_periph_not_in_soft_reset_bank_ctrl = 0, scb_periph_reset_bank_ctrl = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_PERIPH_BANK_CTRL_TypeDef; typedef enum { /*!< SOFT_RESET_BANK_CTRL.V_MAP_BANK_CTRL bitfield definition*/ scb_v_regs_not_in_soft_reset_bank_ctrl = 0, scb_v_regs_reset_bank_ctrl = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_V_MAP_BANK_CTRL_TypeDef; typedef enum { /*!< SOFT_RESET_BANK_CTRL.NV_MAP_BANK_CTRL bitfield definition*/ scb_nv_regs_not_in_soft_reset_bank_ctrl = 0, scb_nv_regs_reset_bank_ctrl = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_NV_MAP_BANK_CTRL_TypeDef; typedef enum { /*!< SOFT_RESET_IOCALIB.BLOCKID_IOCALIB bitfield definition*/ block_address_iocalib = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_BLOCKID_IOCALIB_TypeDef; typedef enum { /*!< SOFT_RESET_IOCALIB.PERIPH_IOCALIB bitfield definition*/ scb_periph_not_in_soft_reset_iocalib = 0, scb_periph_reset_iocalib = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_PERIPH_IOCALIB_TypeDef; typedef enum { /*!< SOFT_RESET_IOCALIB.V_MAP_IOCALIB bitfield definition*/ scb_v_regs_not_in_soft_reset_iocalib = 0, scb_v_regs_reset_iocalib = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_V_MAP_IOCALIB_TypeDef; typedef enum { /*!< SOFT_RESET_IOCALIB.NV_MAP_IOCALIB bitfield definition*/ scb_nv_regs_not_in_soft_reset_iocalib = 0, scb_nv_regs_reset_iocalib = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_NV_MAP_IOCALIB_TypeDef; typedef enum { /*!< SOFT_RESET_CFM.BLOCKID_CFM bitfield definition*/ block_address_cfm = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_BLOCKID_CFM_TypeDef; typedef enum { /*!< SOFT_RESET_CFM.PERIPH_CFM bitfield definition*/ scb_periph_not_in_soft_reset_cfm = 0, scb_periph_reset_cfm = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_PERIPH_CFM_TypeDef; typedef enum { /*!< SOFT_RESET_CFM.V_MAP_CFM bitfield definition*/ scb_v_regs_not_in_soft_reset_cfm = 0, scb_v_regs_reset_cfm = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_V_MAP_CFM_TypeDef; typedef enum { /*!< SOFT_RESET_CFM.NV_MAP_CFM bitfield definition*/ scb_nv_regs_not_in_soft_reset_cfm = 0, scb_nv_regs_reset_cfm = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_NV_MAP_CFM_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_DRIVER.BLOCKID_DECODER_DRIVER bitfield definition*/ block_address_decoder_driver = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_BLOCKID_DECODER_DRIVER_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_DRIVER.PERIPH_DECODER_DRIVER bitfield definition*/ scb_periph_not_in_soft_reset_decoder_driver = 0, scb_periph_reset_decoder_driver = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_PERIPH_DECODER_DRIVER_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_DRIVER.V_MAP_DECODER_DRIVER bitfield definition*/ scb_v_regs_not_in_soft_reset_decoder_driver = 0, scb_v_regs_reset_decoder_driver = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_V_MAP_DECODER_DRIVER_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_DRIVER.NV_MAP_DECODER_DRIVER bitfield definition*/ scb_nv_regs_not_in_soft_reset_decoder_driver = 0, scb_nv_regs_reset_decoder_driver = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_NV_MAP_DECODER_DRIVER_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_ODT.BLOCKID_DECODER_ODT bitfield definition*/ block_address_decoder_odt = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_BLOCKID_DECODER_ODT_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_ODT.PERIPH_DECODER_ODT bitfield definition*/ scb_periph_not_in_soft_reset_decoder_odt = 0, scb_periph_reset_decoder_odt = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_PERIPH_DECODER_ODT_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_ODT.V_MAP_DECODER_ODT bitfield definition*/ scb_v_regs_not_in_soft_reset_decoder_odt = 0, scb_v_regs_reset_decoder_odt = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_V_MAP_DECODER_ODT_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_ODT.NV_MAP_DECODER_ODT bitfield definition*/ scb_nv_regs_not_in_soft_reset_decoder_odt = 0, scb_nv_regs_reset_decoder_odt = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_NV_MAP_DECODER_ODT_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_IO.BLOCKID_DECODER_IO bitfield definition*/ block_address_decoder_io = 0 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_BLOCKID_DECODER_IO_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_IO.PERIPH_DECODER_IO bitfield definition*/ scb_periph_not_in_soft_reset_decoder_io = 0, scb_periph_reset_decoder_io = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_PERIPH_DECODER_IO_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_IO.V_MAP_DECODER_IO bitfield definition*/ scb_v_regs_not_in_soft_reset_decoder_io = 0, scb_v_regs_reset_decoder_io = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_V_MAP_DECODER_IO_TypeDef; typedef enum { /*!< SOFT_RESET_DECODER_IO.NV_MAP_DECODER_IO bitfield definition*/ scb_nv_regs_not_in_soft_reset_decoder_io = 0, scb_nv_regs_reset_decoder_io = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_NV_MAP_DECODER_IO_TypeDef; typedef enum { /*!< SOFT_RESET_TIP.PERIPH_TIP bitfield definition*/ scb_periph_not_in_soft_reset_ddr_tip = 0, scb_periph_reset_ddr_tip = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_PERIPH_TIP_TypeDef; typedef enum { /*!< SOFT_RESET_TIP.V_MAP_TIP bitfield definition*/ scb_v_regs_not_in_soft_reset_ddr_tip = 0, scb_v_regs_reset_ddr_tip = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_V_MAP_TIP_TypeDef; typedef enum { /*!< SOFT_RESET_TIP.NV_MAP_TIP bitfield definition*/ scb_nv_regs_not_in_soft_reset_ddr_tip = 0, scb_nv_regs_reset_ddr_tip = 1 } CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_NV_MAP_TIP_TypeDef; typedef union{ /*!< SOFT_RESET_DDR_PHY register definition*/ __IO uint32_t SOFT_RESET_DDR_PHY; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_NV_MAP_DDR_PHY_TypeDef NV_MAP_DDR_PHY :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_V_MAP_DDR_PHY_TypeDef V_MAP_DDR_PHY :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_PERIPH_DDR_PHY_TypeDef PERIPH_DDR_PHY :1; __I uint32_t reserved_02 :7; __I uint32_t BLOCKID_DDR_PHY :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_TypeDef; typedef union{ /*!< DDRPHY_MODE register definition*/ __IO uint32_t DDRPHY_MODE; struct { __IO uint32_t DDRMODE :3; __IO uint32_t ECC :1; __IO uint32_t CRC :1; __IO uint32_t Bus_width :3; __IO uint32_t DMI_DBI :1; __IO uint32_t DQ_drive :2; __IO uint32_t DQS_drive :2; __IO uint32_t ADD_CMD_drive :2; __IO uint32_t Clock_out_drive :2; __IO uint32_t DQ_termination :2; __IO uint32_t DQS_termination :2; __IO uint32_t ADD_CMD_input_pin_termination :2; __IO uint32_t preset_odt_clk :2; __IO uint32_t Power_down :1; __IO uint32_t rank :1; __IO uint32_t Command_Address_Pipe :2; __I uint32_t Reserved :3; } bitfield; } CFG_DDR_SGMII_PHY_DDRPHY_MODE_TypeDef; typedef union{ /*!< DDRPHY_STARTUP register definition*/ __IO uint32_t DDRPHY_STARTUP; struct { __IO uint32_t ADD_CMD_Lockdn :1; __IO uint32_t DATA_Lockdn :1; __IO uint32_t PERSIST_ADD_CMD :1; __IO uint32_t Persist_CLKOUT :1; __IO uint32_t Persist_DATA :1; __I uint32_t reserved :3; __IO uint32_t DYNEN_SCB_PLL0 :1; __IO uint32_t DYNEN_SCB_PLL1 :1; __IO uint32_t DYNEN_SCB_CFM :1; __IO uint32_t DYNEN_SCB_IO_CALIB :1; __IO uint32_t DYNEN_SCB_BANKCNTL :1; __I uint32_t reserved2 :3; __IO uint32_t DYNEN_APB_PLL0 :1; __IO uint32_t DYNEN_APB_PLL1 :1; __IO uint32_t DYNEN_APB_CFM :1; __IO uint32_t DYNEN_APB_IO_CALIB :1; __IO uint32_t DYNEN_APB_BANKCNTL :1; __IO uint32_t DYNEN_APB_DECODER_PRESETS :1; __IO uint32_t reserved3 :10; } bitfield; } CFG_DDR_SGMII_PHY_DDRPHY_STARTUP_TypeDef; typedef union{ /*!< SOFT_RESET_MAIN_PLL register definition*/ __IO uint32_t SOFT_RESET_MAIN_PLL; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_NV_MAP_MAIN_PLL_TypeDef NV_MAP_MAIN_PLL :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_V_MAP_MAIN_PLL_TypeDef V_MAP_MAIN_PLL :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_PERIPH_MAIN_PLL_TypeDef PERIPH_MAIN_PLL :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_BLOCKID_MAIN_PLL_TypeDef BLOCKID_MAIN_PLL :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_TypeDef; typedef union{ /*!< PLL_CTRL_MAIN register definition*/ __IO uint32_t PLL_CTRL_MAIN; struct { __IO uint32_t REG_POWERDOWN_B :1; __IO uint32_t REG_RFDIV_EN :1; __IO uint32_t REG_DIVQ0_EN :1; __IO uint32_t REG_DIVQ1_EN :1; __IO uint32_t REG_DIVQ2_EN :1; __IO uint32_t REG_DIVQ3_EN :1; __IO uint32_t REG_RFCLK_SEL :1; __I uint32_t RESETONLOCK :1; __I uint32_t BYPCK_SEL :4; __I uint32_t REG_BYPASS_GO_B :1; __I uint32_t reserve10 :3; __I uint32_t REG_BYPASSPRE :4; __I uint32_t REG_BYPASSPOST :4; __IO uint32_t LP_REQUIRES_LOCK :1; __I uint32_t LOCK :1; __I uint32_t LOCK_INT_EN :1; __I uint32_t UNLOCK_INT_EN :1; __I uint32_t LOCK_INT :1; __I uint32_t UNLOCK_INT :1; __I uint32_t reserve11 :1; __I uint32_t LOCK_B :1; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CTRL_MAIN_TypeDef; typedef union{ /*!< PLL_REF_FB_MAIN register definition*/ __IO uint32_t PLL_REF_FB_MAIN; struct { __I uint32_t FSE_B :1; __I uint32_t FBCK_SEL :2; __I uint32_t FOUTFB_SELMUX_EN :1; __I uint32_t reserve12 :4; __IO uint32_t RFDIV :6; __I uint32_t reserve13 :2; __I uint32_t reserve14 :12; __I uint32_t reserve15 :4; } bitfield; } CFG_DDR_SGMII_PHY_PLL_REF_FB_MAIN_TypeDef; typedef union{ /*!< PLL_FRACN_MAIN register definition*/ __IO uint32_t PLL_FRACN_MAIN; struct { __I uint32_t FRACN_EN :1; __I uint32_t FRACN_DAC_EN :1; __I uint32_t reserve16 :6; __I uint32_t reserve17 :24; } bitfield; } CFG_DDR_SGMII_PHY_PLL_FRACN_MAIN_TypeDef; typedef union{ /*!< PLL_DIV_0_1_MAIN register definition*/ __IO uint32_t PLL_DIV_0_1_MAIN; struct { __I uint32_t VCO0PH_SEL :3; __I uint32_t DIV0_START :3; __I uint32_t reserve18 :2; __IO uint32_t POST0DIV :7; __I uint32_t reserve19 :1; __I uint32_t VCO1PH_SEL :3; __I uint32_t DIV1_START :3; __I uint32_t reserve20 :2; __IO uint32_t POST1DIV :7; __I uint32_t reserve21 :1; } bitfield; } CFG_DDR_SGMII_PHY_PLL_DIV_0_1_MAIN_TypeDef; typedef union{ /*!< PLL_DIV_2_3_MAIN register definition*/ __IO uint32_t PLL_DIV_2_3_MAIN; struct { __I uint32_t VCO2PH_SEL :3; __I uint32_t DIV2_START :3; __I uint32_t reserve22 :2; __IO uint32_t POST2DIV :7; __I uint32_t reserve23 :1; __I uint32_t VCO3PH_SEL :3; __I uint32_t DIV3_START :3; __I uint32_t reserve24 :2; __IO uint32_t POST3DIV :7; __I uint32_t CKPOST3_SEL :1; } bitfield; } CFG_DDR_SGMII_PHY_PLL_DIV_2_3_MAIN_TypeDef; typedef union{ /*!< PLL_CTRL2_MAIN register definition*/ __IO uint32_t PLL_CTRL2_MAIN; struct { __IO uint32_t BWI :2; __IO uint32_t BWP :2; __I uint32_t IREF_EN :1; __I uint32_t IREF_TOGGLE :1; __I uint32_t reserve25 :3; __I uint32_t LOCKCNT :4; __I uint32_t reserve26 :4; __I uint32_t ATEST_EN :1; __I uint32_t ATEST_SEL :3; __I uint32_t reserve27 :11; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CTRL2_MAIN_TypeDef; typedef union{ /*!< PLL_CAL_MAIN register definition*/ __I uint32_t PLL_CAL_MAIN; struct { __I uint32_t DSKEWCALCNT :3; __I uint32_t DSKEWCAL_EN :1; __I uint32_t DSKEWCALBYP :1; __I uint32_t reserve28 :3; __I uint32_t DSKEWCALIN :7; __I uint32_t reserve29 :1; __I uint32_t DSKEWCALOUT :7; __I uint32_t reserve30 :9; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CAL_MAIN_TypeDef; typedef union{ /*!< PLL_PHADJ_MAIN register definition*/ __IO uint32_t PLL_PHADJ_MAIN; struct { __I uint32_t PLL_REG_SYNCREFDIV_EN :1; __I uint32_t PLL_REG_ENABLE_SYNCREFDIV :1; __IO uint32_t REG_OUT0_PHSINIT :3; __IO uint32_t REG_OUT1_PHSINIT :3; __IO uint32_t REG_OUT2_PHSINIT :3; __IO uint32_t REG_OUT3_PHSINIT :3; __IO uint32_t REG_LOADPHS_B :1; __I uint32_t reserve31 :17; } bitfield; } CFG_DDR_SGMII_PHY_PLL_PHADJ_MAIN_TypeDef; typedef union{ /*!< SSCG_REG_0_MAIN register definition*/ __IO uint32_t SSCG_REG_0_MAIN; /* todo: verify should be r/w, it is not in source file from Duolog */ struct { __I uint32_t DIVVAL :6; __I uint32_t FRACIN :24; __I uint32_t reserve00 :2; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_0_MAIN_TypeDef; typedef union{ /*!< SSCG_REG_1_MAIN register definition*/ __I uint32_t SSCG_REG_1_MAIN; struct { __I uint32_t DOWNSPREAD :1; __I uint32_t SSMD :5; __I uint32_t FRACMOD :24; __I uint32_t reserve01 :2; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_1_MAIN_TypeDef; typedef union{ /*!< SSCG_REG_2_MAIN register definition*/ __IO uint32_t SSCG_REG_2_MAIN; struct { __IO uint32_t INTIN :12; __I uint32_t INTMOD :12; __I uint32_t reserve02 :8; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_2_MAIN_TypeDef; typedef union{ /*!< SSCG_REG_3_MAIN register definition*/ __IO uint32_t SSCG_REG_3_MAIN; /* todo: verify if should be __IO */ struct { __I uint32_t SSE_B :1; __I uint32_t SEL_EXTWAVE :2; __I uint32_t EXT_MAXADDR :8; __I uint32_t TBLADDR :8; __I uint32_t RANDOM_FILTER :1; __I uint32_t RANDOM_SEL :2; __I uint32_t reserve03 :1; __I uint32_t reserve04 :9; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_3_MAIN_TypeDef; typedef union{ /*!< RPC_RESET_MAIN_PLL register definition*/ __IO uint32_t RPC_RESET_MAIN_PLL; struct { __IO uint32_t soft_reset_periph_MAIN_PLL :1; __I uint32_t Reserved :31; } bitfield; } CFG_DDR_SGMII_PHY_RPC_RESET_MAIN_PLL_TypeDef; typedef union{ /*!< SOFT_RESET_IOSCB_PLL register definition*/ __IO uint32_t SOFT_RESET_IOSCB_PLL; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_NV_MAP_IOSCB_PLL_TypeDef NV_MAP_IOSCB_PLL :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_V_MAP_IOSCB_PLL_TypeDef V_MAP_IOSCB_PLL :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_PERIPH_IOSCB_PLL_TypeDef PERIPH_IOSCB_PLL :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_BLOCKID_IOSCB_PLL_TypeDef BLOCKID_IOSCB_PLL :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_TypeDef; typedef union{ /*!< PLL_CTRL_IOSCB register definition*/ __IO uint32_t PLL_CTRL_IOSCB; struct { __IO uint32_t REG_POWERDOWN_B :1; __IO uint32_t REG_RFDIV_EN :1; __IO uint32_t REG_DIVQ0_EN :1; __IO uint32_t REG_DIVQ1_EN :1; __IO uint32_t REG_DIVQ2_EN :1; __IO uint32_t REG_DIVQ3_EN :1; __IO uint32_t REG_RFCLK_SEL :1; __I uint32_t RESETONLOCK :1; __I uint32_t BYPCK_SEL :4; __I uint32_t REG_BYPASS_GO_B :1; __I uint32_t reserve10 :3; __I uint32_t REG_BYPASSPRE :4; __I uint32_t REG_BYPASSPOST :4; __IO uint32_t LP_REQUIRES_LOCK :1; __I uint32_t LOCK :1; __I uint32_t LOCK_INT_EN :1; __I uint32_t UNLOCK_INT_EN :1; __I uint32_t LOCK_INT :1; __I uint32_t UNLOCK_INT :1; __I uint32_t reserve11 :1; __I uint32_t LOCK_B :1; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CTRL_IOSCB_TypeDef; typedef union{ /*!< PLL_REF_FB_IOSCB register definition*/ __IO uint32_t PLL_REF_FB_IOSCB; struct { __I uint32_t FSE_B :1; __I uint32_t FBCK_SEL :2; __I uint32_t FOUTFB_SELMUX_EN :1; __I uint32_t reserve12 :4; __IO uint32_t RFDIV :6; __I uint32_t reserve13 :2; __I uint32_t reserve14 :12; __I uint32_t reserve15 :4; } bitfield; } CFG_DDR_SGMII_PHY_PLL_REF_FB_IOSCB_TypeDef; typedef union{ /*!< PLL_FRACN_IOSCB register definition*/ __I uint32_t PLL_FRACN_IOSCB; struct { __I uint32_t FRACN_EN :1; __I uint32_t FRACN_DAC_EN :1; __I uint32_t reserve16 :6; __I uint32_t reserve17 :24; } bitfield; } CFG_DDR_SGMII_PHY_PLL_FRACN_IOSCB_TypeDef; typedef union{ /*!< PLL_DIV_0_1_IOSCB register definition*/ __IO uint32_t PLL_DIV_0_1_IOSCB; struct { __I uint32_t VCO0PH_SEL :3; __I uint32_t DIV0_START :3; __I uint32_t reserve18 :2; __IO uint32_t POST0DIV :7; __I uint32_t reserve19 :1; __I uint32_t VCO1PH_SEL :3; __I uint32_t DIV1_START :3; __I uint32_t reserve20 :2; __IO uint32_t POST1DIV :7; __I uint32_t reserve21 :1; } bitfield; } CFG_DDR_SGMII_PHY_PLL_DIV_0_1_IOSCB_TypeDef; typedef union{ /*!< PLL_DIV_2_3_IOSCB register definition*/ __IO uint32_t PLL_DIV_2_3_IOSCB; struct { __I uint32_t VCO2PH_SEL :3; __I uint32_t DIV2_START :3; __I uint32_t reserve22 :2; __IO uint32_t POST2DIV :7; __I uint32_t reserve23 :1; __I uint32_t VCO3PH_SEL :3; __I uint32_t DIV3_START :3; __I uint32_t reserve24 :2; __IO uint32_t POST3DIV :7; __I uint32_t CKPOST3_SEL :1; } bitfield; } CFG_DDR_SGMII_PHY_PLL_DIV_2_3_IOSCB_TypeDef; typedef union{ /*!< PLL_CTRL2_IOSCB register definition*/ __IO uint32_t PLL_CTRL2_IOSCB; struct { __IO uint32_t BWI :2; __IO uint32_t BWP :2; __I uint32_t IREF_EN :1; __I uint32_t IREF_TOGGLE :1; __I uint32_t reserve25 :3; __I uint32_t LOCKCNT :4; __I uint32_t reserve26 :4; __I uint32_t ATEST_EN :1; __I uint32_t ATEST_SEL :3; __I uint32_t reserve27 :11; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CTRL2_IOSCB_TypeDef; typedef union{ /*!< PLL_CAL_IOSCB register definition*/ __I uint32_t PLL_CAL_IOSCB; struct { __I uint32_t DSKEWCALCNT :3; __I uint32_t DSKEWCAL_EN :1; __I uint32_t DSKEWCALBYP :1; __I uint32_t reserve28 :3; __I uint32_t DSKEWCALIN :7; __I uint32_t reserve29 :1; __I uint32_t DSKEWCALOUT :7; __I uint32_t reserve30 :9; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CAL_IOSCB_TypeDef; typedef union{ /*!< PLL_PHADJ_IOSCB register definition*/ __IO uint32_t PLL_PHADJ_IOSCB; struct { __I uint32_t PLL_REG_SYNCREFDIV_EN :1; __I uint32_t PLL_REG_ENABLE_SYNCREFDIV :1; __IO uint32_t REG_OUT0_PHSINIT :3; __IO uint32_t REG_OUT1_PHSINIT :3; __IO uint32_t REG_OUT2_PHSINIT :3; __IO uint32_t REG_OUT3_PHSINIT :3; __IO uint32_t REG_LOADPHS_B :1; __I uint32_t reserve31 :17; } bitfield; } CFG_DDR_SGMII_PHY_PLL_PHADJ_IOSCB_TypeDef; typedef union{ /*!< SSCG_REG_0_IOSCB register definition*/ __I uint32_t SSCG_REG_0_IOSCB; struct { __I uint32_t DIVVAL :6; __I uint32_t FRACIN :24; __I uint32_t reserve00 :2; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_0_IOSCB_TypeDef; typedef union{ /*!< SSCG_REG_1_IOSCB register definition*/ __I uint32_t SSCG_REG_1_IOSCB; struct { __I uint32_t DOWNSPREAD :1; __I uint32_t SSMD :5; __I uint32_t FRACMOD :24; __I uint32_t reserve01 :2; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_1_IOSCB_TypeDef; typedef union{ /*!< SSCG_REG_2_IOSCB register definition*/ __IO uint32_t SSCG_REG_2_IOSCB; struct { __IO uint32_t INTIN :12; __I uint32_t INTMOD :12; __I uint32_t reserve02 :8; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_2_IOSCB_TypeDef; typedef union{ /*!< SSCG_REG_3_IOSCB register definition*/ __I uint32_t SSCG_REG_3_IOSCB; struct { __I uint32_t SSE_B :1; __I uint32_t SEL_EXTWAVE :2; __I uint32_t EXT_MAXADDR :8; __I uint32_t TBLADDR :8; __I uint32_t RANDOM_FILTER :1; __I uint32_t RANDOM_SEL :2; __I uint32_t reserve03 :1; __I uint32_t reserve04 :9; } bitfield; } CFG_DDR_SGMII_PHY_SSCG_REG_3_IOSCB_TypeDef; typedef union{ /*!< RPC_RESET_IOSCB register definition*/ __IO uint32_t RPC_RESET_IOSCB; struct { __IO uint32_t soft_reset_periph_IOSCB :1; __I uint32_t Reserved :31; } bitfield; } CFG_DDR_SGMII_PHY_RPC_RESET_IOSCB_TypeDef; typedef union{ /*!< SOFT_RESET_BANK_CTRL register definition*/ __IO uint32_t SOFT_RESET_BANK_CTRL; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_NV_MAP_BANK_CTRL_TypeDef NV_MAP_BANK_CTRL :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_V_MAP_BANK_CTRL_TypeDef V_MAP_BANK_CTRL :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_PERIPH_BANK_CTRL_TypeDef PERIPH_BANK_CTRL :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_BLOCKID_BANK_CTRL_TypeDef BLOCKID_BANK_CTRL :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_TypeDef; typedef union{ /*!< DPC_BITS register definition*/ __IO uint32_t DPC_BITS; struct { __IO uint32_t dpc_vs :4; __IO uint32_t dpc_vrgen_h :6; __IO uint32_t dpc_vrgen_en_h :1; __IO uint32_t dpc_move_en_h :1; __IO uint32_t dpc_vrgen_v :6; __IO uint32_t dpc_vrgen_en_v :1; __IO uint32_t dpc_move_en_v :1; __I uint32_t reserve01 :12; } bitfield; } CFG_DDR_SGMII_PHY_DPC_BITS_TypeDef; typedef union{ /*!< BANK_STATUS register definition*/ __I uint32_t BANK_STATUS; struct { __I uint32_t sro_calib_status_b :1; __I uint32_t sro_ioen_bnk_b :1; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_BANK_STATUS_TypeDef; typedef union{ /*!< RPC_RESET_BANK_CTRL register definition*/ __IO uint32_t RPC_RESET_BANK_CTRL; struct { __IO uint32_t soft_reset_periph_BANK_CTRL :1; __I uint32_t Reserved :31; } bitfield; } CFG_DDR_SGMII_PHY_RPC_RESET_BANK_CTRL_TypeDef; typedef union{ /*!< SOFT_RESET_IOCALIB register definition*/ __IO uint32_t SOFT_RESET_IOCALIB; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_NV_MAP_IOCALIB_TypeDef NV_MAP_IOCALIB :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_V_MAP_IOCALIB_TypeDef V_MAP_IOCALIB :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_PERIPH_IOCALIB_TypeDef PERIPH_IOCALIB :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_BLOCKID_IOCALIB_TypeDef BLOCKID_IOCALIB :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_TypeDef; typedef union{ /*!< IOC_REG0 register definition*/ __IO uint32_t IOC_REG0; struct { __IO uint32_t reg_pcode :6; __IO uint32_t reg_ncode :6; __I uint32_t reg_calib_trim :1; __IO uint32_t reg_calib_start :1; __IO uint32_t reg_calib_lock :1; __I uint32_t reg_calib_load :1; __I uint32_t reg_calib_direction :1; __I uint32_t reg_calib_move_pcode :1; __I uint32_t reg_calib_move_ncode :1; __I uint32_t reserve01 :13; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG0_TypeDef; typedef union{ /*!< IOC_REG1 register definition*/ __I uint32_t IOC_REG1; struct { __I uint32_t sro_code_done_p :1; __I uint32_t sro_code_done_n :1; __I uint32_t sro_calib_status :1; __I uint32_t sro_calib_intrpt :1; __I uint32_t sro_ioen_out :1; __I uint32_t sro_power_on :1; __I uint32_t sro_comp_sel :1; __I uint32_t sro_comp_en :1; __I uint32_t reserve02 :24; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG1_TypeDef; typedef union{ /*!< IOC_REG2 register definition*/ __I uint32_t IOC_REG2; struct { __I uint32_t sro_pcode :7; __I uint32_t sro_ncode :7; __I uint32_t sro_ref_pcode :7; __I uint32_t sro_ref_ncode :7; __I uint32_t sro_comp_out :1; __I uint32_t reserve03 :3; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG2_TypeDef; typedef union{ /*!< IOC_REG3 register definition*/ __I uint32_t IOC_REG3; struct { __I uint32_t reserve04 :5; __I uint32_t reg_calib_poffset :6; __I uint32_t reg_calib_poffset_dir :1; __I uint32_t reg_calib_noffset :6; __I uint32_t reg_calib_noffset_dir :1; __I uint32_t reg_calib_move_slewr :1; __I uint32_t reg_calib_move_slewf :1; __I uint32_t reg_calib_roffset_dir :1; __I uint32_t reg_calib_foffset_dir :1; __I uint32_t reserve05 :9; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG3_TypeDef; typedef union{ /*!< IOC_REG4 register definition*/ __I uint32_t IOC_REG4; struct { __I uint32_t reg_roffset :6; __I uint32_t reg_foffset :6; __I uint32_t reg_slewr :6; __I uint32_t reg_slewf :6; __I uint32_t sro_slew_intrpt :1; __I uint32_t sro_slew_status :1; __I uint32_t sro_slew_comp_out :1; __I uint32_t sro_slew_comp_en :1; __I uint32_t sro_slew_comp_sel :1; __I uint32_t sro_slew_ioen_out :1; __I uint32_t sro_slew_power_on :1; __I uint32_t reserve06 :1; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG4_TypeDef; typedef union{ /*!< IOC_REG5 register definition*/ __I uint32_t IOC_REG5; struct { __I uint32_t sro_ref_slewr :6; __I uint32_t sro_ref_slewf :12; __I uint32_t sro_slewr :6; __I uint32_t sro_slewf :6; __I uint32_t reserve07 :2; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG5_TypeDef; typedef union{ /*!< IOC_REG6 register definition*/ __IO uint32_t IOC_REG6; struct { __IO uint32_t reg_calib_reset :1; __IO uint32_t reg_calib_clkdiv :2; __I uint32_t reserve08 :29; } bitfield; } CFG_DDR_SGMII_PHY_IOC_REG6_TypeDef; typedef union{ /*!< RPC_RESET_IOCALIB register definition*/ __IO uint32_t RPC_RESET_IOCALIB; struct { __IO uint32_t soft_reset_periph_IOCALIB :1; __I uint32_t Reserved :31; } bitfield; } CFG_DDR_SGMII_PHY_RPC_RESET_IOCALIB_TypeDef; typedef union{ /*!< rpc_calib register definition*/ __IO uint32_t rpc_calib; struct { __IO uint32_t start_pvt :1; __IO uint32_t lock_pvt :1; __I uint32_t Reserved :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc_calib_TypeDef; typedef union{ /*!< SOFT_RESET_CFM register definition*/ __IO uint32_t SOFT_RESET_CFM; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_NV_MAP_CFM_TypeDef NV_MAP_CFM :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_V_MAP_CFM_TypeDef V_MAP_CFM :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_PERIPH_CFM_TypeDef PERIPH_CFM :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_BLOCKID_CFM_TypeDef BLOCKID_CFM :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_TypeDef; typedef union{ /*!< BCLKMUX register definition*/ __IO uint32_t BCLKMUX; struct { __IO uint32_t bclk0_sel :5; __IO uint32_t bclk1_sel :5; __IO uint32_t bclk2_sel :5; __IO uint32_t bclk3_sel :5; __IO uint32_t bclk4_sel :5; __IO uint32_t bclk5_sel :5; __I uint32_t reserve0 :2; } bitfield; } CFG_DDR_SGMII_PHY_BCLKMUX_TypeDef; typedef union{ /*!< PLL_CKMUX register definition*/ __IO uint32_t PLL_CKMUX; struct { __IO uint32_t clk_in_mac_tsu :2; __IO uint32_t pll0_rfclk0_sel :2; __IO uint32_t pll0_rfclk1_sel :2; __IO uint32_t pll1_rfclk0_sel :2; __IO uint32_t pll1_rfclk1_sel :2; __IO uint32_t pll1_fdr_sel :5; __I uint32_t reserve1 :17; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CKMUX_TypeDef; typedef union{ /*!< MSSCLKMUX register definition*/ __IO uint32_t MSSCLKMUX; struct { __IO uint32_t mssclk_mux_sel :2; __IO uint32_t mssclk_mux_md :2; __IO uint32_t clk_standby_sel :1; __I uint32_t reserve2 :27; } bitfield; } CFG_DDR_SGMII_PHY_MSSCLKMUX_TypeDef; typedef union{ /*!< SPARE0 register definition*/ __IO uint32_t SPARE0; struct { __IO uint32_t spare0 :32; } bitfield; } CFG_DDR_SGMII_PHY_SPARE0_TypeDef; typedef union{ /*!< FMETER_ADDR register definition*/ __I uint32_t FMETER_ADDR; struct { __I uint32_t addr10 :2; __I uint32_t addr :4; __I uint32_t reserve3 :26; } bitfield; } CFG_DDR_SGMII_PHY_FMETER_ADDR_TypeDef; typedef union{ /*!< FMETER_DATAW register definition*/ __I uint32_t FMETER_DATAW; struct { __I uint32_t data :24; __I uint32_t strobe :1; __I uint32_t reserve4 :7; } bitfield; } CFG_DDR_SGMII_PHY_FMETER_DATAW_TypeDef; typedef union{ /*!< FMETER_DATAR register definition*/ __I uint32_t FMETER_DATAR; struct { __I uint32_t data :24; __I uint32_t reserve5 :8; } bitfield; } CFG_DDR_SGMII_PHY_FMETER_DATAR_TypeDef; typedef union{ /*!< TEST_CTRL register definition*/ __I uint32_t TEST_CTRL; struct { __I uint32_t atest_en :1; __I uint32_t atest_sel :5; __I uint32_t dtest_en :1; __I uint32_t dtest_sel :5; __I uint32_t reserve6 :20; } bitfield; } CFG_DDR_SGMII_PHY_TEST_CTRL_TypeDef; typedef union{ /*!< RPC_RESET_CFM register definition*/ __IO uint32_t RPC_RESET_CFM; struct { __IO uint32_t soft_reset_periph_CFM :1; __I uint32_t Reserved :31; } bitfield; } CFG_DDR_SGMII_PHY_RPC_RESET_CFM_TypeDef; typedef union{ /*!< SOFT_RESET_DECODER_DRIVER register definition*/ __IO uint32_t SOFT_RESET_DECODER_DRIVER; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_NV_MAP_DECODER_DRIVER_TypeDef NV_MAP_DECODER_DRIVER :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_V_MAP_DECODER_DRIVER_TypeDef V_MAP_DECODER_DRIVER :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_PERIPH_DECODER_DRIVER_TypeDef PERIPH_DECODER_DRIVER :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_BLOCKID_DECODER_DRIVER_TypeDef BLOCKID_DECODER_DRIVER :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_TypeDef; typedef union{ /*!< rpc1_DRV register definition*/ __IO uint32_t rpc1_DRV; struct { __IO uint32_t drv_addcmd :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc1_DRV_TypeDef; typedef union{ /*!< rpc2_DRV register definition*/ __IO uint32_t rpc2_DRV; struct { __IO uint32_t drv_clk :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc2_DRV_TypeDef; typedef union{ /*!< rpc3_DRV register definition*/ __IO uint32_t rpc3_DRV; struct { __IO uint32_t drv_dq :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc3_DRV_TypeDef; typedef union{ /*!< rpc4_DRV register definition*/ __IO uint32_t rpc4_DRV; struct { __IO uint32_t drv_dqs :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc4_DRV_TypeDef; typedef union{ /*!< SOFT_RESET_DECODER_ODT register definition*/ __IO uint32_t SOFT_RESET_DECODER_ODT; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_NV_MAP_DECODER_ODT_TypeDef NV_MAP_DECODER_ODT :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_V_MAP_DECODER_ODT_TypeDef V_MAP_DECODER_ODT :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_PERIPH_DECODER_ODT_TypeDef PERIPH_DECODER_ODT :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_BLOCKID_DECODER_ODT_TypeDef BLOCKID_DECODER_ODT :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_TypeDef; typedef union{ /*!< rpc1_ODT register definition*/ __IO uint32_t rpc1_ODT; struct { __IO uint32_t odt_addcmd :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc1_ODT_TypeDef; typedef union{ /*!< rpc2_ODT register definition*/ __IO uint32_t rpc2_ODT; struct { __IO uint32_t odt_clk :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc2_ODT_TypeDef; typedef union{ /*!< rpc3_ODT register definition*/ __IO uint32_t rpc3_ODT; struct { __IO uint32_t odt_dq :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc3_ODT_TypeDef; typedef union{ /*!< rpc4_ODT register definition*/ __IO uint32_t rpc4_ODT; struct { __IO uint32_t odt_dqs :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc4_ODT_TypeDef; typedef union{ /*!< rpc5_ODT register definition*/ __IO uint32_t rpc5_ODT; struct { __IO uint32_t odt_dyn_sel_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc5_ODT_TypeDef; typedef union{ /*!< rpc6_ODT register definition*/ __IO uint32_t rpc6_ODT; struct { __IO uint32_t odt_dyn_sel_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc6_ODT_TypeDef; typedef union{ /*!< rpc7_ODT register definition*/ __IO uint32_t rpc7_ODT; struct { __IO uint32_t odt_static_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc7_ODT_TypeDef; typedef union{ /*!< rpc8_ODT register definition*/ __IO uint32_t rpc8_ODT; struct { __IO uint32_t odt_static_clkn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc8_ODT_TypeDef; typedef union{ /*!< rpc9_ODT register definition*/ __IO uint32_t rpc9_ODT; struct { __IO uint32_t odt_static_clkp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc9_ODT_TypeDef; typedef union{ /*!< rpc10_ODT register definition*/ __IO uint32_t rpc10_ODT; struct { __IO uint32_t odt_static_dq :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc10_ODT_TypeDef; typedef union{ /*!< rpc11_ODT register definition*/ __IO uint32_t rpc11_ODT; struct { __IO uint32_t odt_static_dqs :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc11_ODT_TypeDef; typedef union{ /*!< SOFT_RESET_DECODER_IO register definition*/ __IO uint32_t SOFT_RESET_DECODER_IO; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_NV_MAP_DECODER_IO_TypeDef NV_MAP_DECODER_IO :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_V_MAP_DECODER_IO_TypeDef V_MAP_DECODER_IO :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_PERIPH_DECODER_IO_TypeDef PERIPH_DECODER_IO :1; __I uint32_t reserved_02 :7; __I CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_BLOCKID_DECODER_IO_TypeDef BLOCKID_DECODER_IO :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_TypeDef; typedef union{ /*!< ovrt1 register definition*/ __IO uint32_t ovrt1; struct { __IO uint32_t drv_addcmd0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt1_TypeDef; typedef union{ /*!< ovrt2 register definition*/ __IO uint32_t ovrt2; struct { __IO uint32_t drv_addcmd1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt2_TypeDef; typedef union{ /*!< ovrt3 register definition*/ __IO uint32_t ovrt3; struct { __IO uint32_t drv_addcmd2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt3_TypeDef; typedef union{ /*!< ovrt4 register definition*/ __IO uint32_t ovrt4; struct { __IO uint32_t drv_data0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt4_TypeDef; typedef union{ /*!< ovrt5 register definition*/ __IO uint32_t ovrt5; struct { __IO uint32_t drv_data1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt5_TypeDef; typedef union{ /*!< ovrt6 register definition*/ __IO uint32_t ovrt6; struct { __IO uint32_t drv_data2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt6_TypeDef; typedef union{ /*!< ovrt7 register definition*/ __IO uint32_t ovrt7; struct { __IO uint32_t drv_data3 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt7_TypeDef; typedef union{ /*!< ovrt8 register definition*/ __IO uint32_t ovrt8; struct { __IO uint32_t drv_ecc :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt8_TypeDef; typedef union{ /*!< ovrt9 register definition*/ __IO uint32_t ovrt9; struct { __IO uint32_t en_addcmd0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt9_TypeDef; typedef union{ /*!< ovrt10 register definition*/ __IO uint32_t ovrt10; struct { __IO uint32_t en_addcmd1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt10_TypeDef; typedef union{ /*!< ovrt11 register definition*/ __IO uint32_t ovrt11; struct { __IO uint32_t en_addcmd2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt11_TypeDef; typedef union{ /*!< ovrt12 register definition*/ __IO uint32_t ovrt12; struct { __IO uint32_t en_data0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt12_TypeDef; typedef union{ /*!< ovrt13 register definition*/ __IO uint32_t ovrt13; struct { __IO uint32_t en_data1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt13_TypeDef; typedef union{ /*!< ovrt14 register definition*/ __IO uint32_t ovrt14; struct { __IO uint32_t en_data2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt14_TypeDef; typedef union{ /*!< ovrt15 register definition*/ __IO uint32_t ovrt15; struct { __IO uint32_t en_data3 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt15_TypeDef; typedef union{ /*!< ovrt16 register definition*/ __IO uint32_t ovrt16; struct { __IO uint32_t en_ecc :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_ovrt16_TypeDef; typedef union{ /*!< rpc17 register definition*/ __IO uint32_t rpc17; struct { __IO uint32_t bclk_sel_ac :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc17_TypeDef; typedef union{ /*!< rpc18 register definition*/ __IO uint32_t rpc18; struct { __IO uint32_t bclk_sel_addcmd :9; __I uint32_t reserved_01 :23; } bitfield; } CFG_DDR_SGMII_PHY_rpc18_TypeDef; typedef union{ /*!< rpc19 register definition*/ __IO uint32_t rpc19; struct { __IO uint32_t bclk_sel_clkn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc19_TypeDef; typedef union{ /*!< rpc20 register definition*/ __IO uint32_t rpc20; struct { __IO uint32_t bclk_sel_clkp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc20_TypeDef; typedef union{ /*!< rpc21 register definition*/ __IO uint32_t rpc21; struct { __IO uint32_t bclk_sel_data :9; __I uint32_t reserved_01 :23; } bitfield; } CFG_DDR_SGMII_PHY_rpc21_TypeDef; typedef union{ /*!< rpc22 register definition*/ __IO uint32_t rpc22; struct { __IO uint32_t bclk_sel_dq :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc22_TypeDef; typedef union{ /*!< rpc23 register definition*/ __IO uint32_t rpc23; struct { __IO uint32_t bclk_sel_dqsn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc23_TypeDef; typedef union{ /*!< rpc24 register definition*/ __IO uint32_t rpc24; struct { __IO uint32_t bclk_sel_dqsp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc24_TypeDef; typedef union{ /*!< rpc25 register definition*/ __IO uint32_t rpc25; struct { __IO uint32_t cdr_md_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc25_TypeDef; typedef union{ /*!< rpc26 register definition*/ __IO uint32_t rpc26; struct { __IO uint32_t cdr_md_data :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc26_TypeDef; typedef union{ /*!< rpc27 register definition*/ __IO uint32_t rpc27; struct { __IO uint32_t clk_md_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc27_TypeDef; typedef union{ /*!< rpc28 register definition*/ __IO uint32_t rpc28; struct { __IO uint32_t clk_sel_addcmd :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc28_TypeDef; typedef union{ /*!< rpc29 register definition*/ __IO uint32_t rpc29; struct { __IO uint32_t clk_sel_data :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc29_TypeDef; typedef union{ /*!< rpc30 register definition*/ __IO uint32_t rpc30; struct { __IO uint32_t code_sel_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc30_TypeDef; typedef union{ /*!< rpc31 register definition*/ __IO uint32_t rpc31; struct { __IO uint32_t code_sel_data :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc31_TypeDef; typedef union{ /*!< rpc32 register definition*/ __IO uint32_t rpc32; struct { __IO uint32_t comp_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc32_TypeDef; typedef union{ /*!< rpc33 register definition*/ __IO uint32_t rpc33; struct { __IO uint32_t comp_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc33_TypeDef; typedef union{ /*!< rpc34 register definition*/ __IO uint32_t rpc34; struct { __IO uint32_t comp_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc34_TypeDef; typedef union{ /*!< rpc35 register definition*/ __IO uint32_t rpc35; struct { __IO uint32_t comp_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc35_TypeDef; typedef union{ /*!< rpc36 register definition*/ __IO uint32_t rpc36; struct { __IO uint32_t comp_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc36_TypeDef; typedef union{ /*!< rpc37 register definition*/ __IO uint32_t rpc37; struct { __IO uint32_t comp_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc37_TypeDef; typedef union{ /*!< rpc38 register definition*/ __IO uint32_t rpc38; struct { __IO uint32_t divclk_sel_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc38_TypeDef; typedef union{ /*!< rpc39 register definition*/ __IO uint32_t rpc39; struct { __IO uint32_t divclk_sel_data :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc39_TypeDef; typedef union{ /*!< rpc40 register definition*/ __IO uint32_t rpc40; struct { __IO uint32_t div_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc40_TypeDef; typedef union{ /*!< rpc41 register definition*/ __IO uint32_t rpc41; struct { __IO uint32_t div_data :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc41_TypeDef; typedef union{ /*!< rpc42 register definition*/ __IO uint32_t rpc42; struct { __IO uint32_t dly_md_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc42_TypeDef; typedef union{ /*!< rpc43 register definition*/ __IO uint32_t rpc43; struct { __IO uint32_t dly_md_clkn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc43_TypeDef; typedef union{ /*!< rpc44 register definition*/ __IO uint32_t rpc44; struct { __IO uint32_t dly_md_clkp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc44_TypeDef; typedef union{ /*!< rpc45 register definition*/ __IO uint32_t rpc45; struct { __IO uint32_t dly_md_dq :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc45_TypeDef; typedef union{ /*!< rpc46 register definition*/ __IO uint32_t rpc46; struct { __IO uint32_t dly_md_dqsn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc46_TypeDef; typedef union{ /*!< rpc47 register definition*/ __IO uint32_t rpc47; struct { __IO uint32_t dly_md_dqsp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc47_TypeDef; typedef union{ /*!< rpc48 register definition*/ __IO uint32_t rpc48; struct { __IO uint32_t dqs_md_data :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc48_TypeDef; typedef union{ /*!< rpc49 register definition*/ __IO uint32_t rpc49; struct { __IO uint32_t dynen_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc49_TypeDef; typedef union{ /*!< rpc50 register definition*/ __IO uint32_t rpc50; struct { __IO uint32_t dynen_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc50_TypeDef; typedef union{ /*!< rpc51 register definition*/ __IO uint32_t rpc51; struct { __IO uint32_t dynen_soft_reset_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc51_TypeDef; typedef union{ /*!< rpc52 register definition*/ __IO uint32_t rpc52; struct { __IO uint32_t dynen_soft_reset_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc52_TypeDef; typedef union{ /*!< rpc53 register definition*/ __IO uint32_t rpc53; struct { __IO uint32_t edgedet_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc53_TypeDef; typedef union{ /*!< rpc54 register definition*/ __IO uint32_t rpc54; struct { __IO uint32_t edgedet_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc54_TypeDef; typedef union{ /*!< rpc55 register definition*/ __IO uint32_t rpc55; struct { __IO uint32_t edgedet_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc55_TypeDef; typedef union{ /*!< rpc56 register definition*/ __IO uint32_t rpc56; struct { __IO uint32_t edgedet_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc56_TypeDef; typedef union{ /*!< rpc57 register definition*/ __IO uint32_t rpc57; struct { __IO uint32_t edgedet_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc57_TypeDef; typedef union{ /*!< rpc58 register definition*/ __IO uint32_t rpc58; struct { __IO uint32_t edgedet_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc58_TypeDef; typedef union{ /*!< rpc59 register definition*/ __IO uint32_t rpc59; struct { __IO uint32_t eyewidth_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc59_TypeDef; typedef union{ /*!< rpc60 register definition*/ __IO uint32_t rpc60; struct { __IO uint32_t eyewidth_clkn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc60_TypeDef; typedef union{ /*!< rpc61 register definition*/ __IO uint32_t rpc61; struct { __IO uint32_t eyewidth_clkp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc61_TypeDef; typedef union{ /*!< rpc62 register definition*/ __IO uint32_t rpc62; struct { __IO uint32_t eyewidth_dq :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc62_TypeDef; typedef union{ /*!< rpc63 register definition*/ __IO uint32_t rpc63; struct { __IO uint32_t eyewidth_dqsn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc63_TypeDef; typedef union{ /*!< rpc64 register definition*/ __IO uint32_t rpc64; struct { __IO uint32_t eyewidth_dqsp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc64_TypeDef; typedef union{ /*!< rpc65 register definition*/ __IO uint32_t rpc65; struct { __IO uint32_t eyewidth_sel_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc65_TypeDef; typedef union{ /*!< rpc66 register definition*/ __IO uint32_t rpc66; struct { __IO uint32_t eyewidth_sel_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc66_TypeDef; typedef union{ /*!< rpc67 register definition*/ __IO uint32_t rpc67; struct { __IO uint32_t eyewidth_sel_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc67_TypeDef; typedef union{ /*!< rpc68 register definition*/ __IO uint32_t rpc68; struct { __IO uint32_t eyewidth_sel_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc68_TypeDef; typedef union{ /*!< rpc69 register definition*/ __IO uint32_t rpc69; struct { __IO uint32_t eyewidth_sel_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc69_TypeDef; typedef union{ /*!< rpc70 register definition*/ __IO uint32_t rpc70; struct { __IO uint32_t eyewidth_sel_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc70_TypeDef; typedef union{ /*!< rpc71 register definition*/ __IO uint32_t rpc71; struct { __IO uint32_t eye_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc71_TypeDef; typedef union{ /*!< rpc72 register definition*/ __IO uint32_t rpc72; struct { __IO uint32_t eye_en_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc72_TypeDef; typedef union{ /*!< rpc73 register definition*/ __IO uint32_t rpc73; struct { __IO uint32_t eye_en_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc73_TypeDef; typedef union{ /*!< rpc74 register definition*/ __IO uint32_t rpc74; struct { __IO uint32_t eye_en_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc74_TypeDef; typedef union{ /*!< rpc75 register definition*/ __IO uint32_t rpc75; struct { __IO uint32_t eye_en_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc75_TypeDef; typedef union{ /*!< rpc76 register definition*/ __IO uint32_t rpc76; struct { __IO uint32_t eye_en_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc76_TypeDef; typedef union{ /*!< rpc77 register definition*/ __IO uint32_t rpc77; struct { __IO uint32_t eye_sdr_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc77_TypeDef; typedef union{ /*!< rpc78 register definition*/ __IO uint32_t rpc78; struct { __IO uint32_t eye_sdr_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc78_TypeDef; typedef union{ /*!< rpc79 register definition*/ __IO uint32_t rpc79; struct { __IO uint32_t eye_sdr_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc79_TypeDef; typedef union{ /*!< rpc80 register definition*/ __IO uint32_t rpc80; struct { __IO uint32_t eye_sdr_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc80_TypeDef; typedef union{ /*!< rpc81 register definition*/ __IO uint32_t rpc81; struct { __IO uint32_t eye_sdr_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc81_TypeDef; typedef union{ /*!< rpc82 register definition*/ __IO uint32_t rpc82; struct { __IO uint32_t eye_sdr_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc82_TypeDef; typedef union{ /*!< rpc83 register definition*/ __IO uint32_t rpc83; struct { __IO uint32_t fifowe_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc83_TypeDef; typedef union{ /*!< rpc84 register definition*/ __IO uint32_t rpc84; struct { __IO uint32_t fifowe_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc84_TypeDef; typedef union{ /*!< rpc85 register definition*/ __IO uint32_t rpc85; struct { __IO uint32_t fifowe_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc85_TypeDef; typedef union{ /*!< rpc86 register definition*/ __IO uint32_t rpc86; struct { __IO uint32_t fifowe_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc86_TypeDef; typedef union{ /*!< rpc87 register definition*/ __IO uint32_t rpc87; struct { __IO uint32_t fifowe_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc87_TypeDef; typedef union{ /*!< rpc88 register definition*/ __IO uint32_t rpc88; struct { __IO uint32_t fifowe_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc88_TypeDef; typedef union{ /*!< rpc89 register definition*/ __IO uint32_t rpc89; struct { __IO uint32_t fifo_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc89_TypeDef; typedef union{ /*!< rpc90 register definition*/ __IO uint32_t rpc90; struct { __IO uint32_t fifo_en_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc90_TypeDef; typedef union{ /*!< rpc91 register definition*/ __IO uint32_t rpc91; struct { __IO uint32_t fifo_run_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc91_TypeDef; typedef union{ /*!< rpc92 register definition*/ __IO uint32_t rpc92; struct { __IO uint32_t fifo_run_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc92_TypeDef; typedef union{ /*!< rpc93 register definition*/ __IO uint32_t rpc93; struct { __IO uint32_t gsr_disable_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc93_TypeDef; typedef union{ /*!< rpc94 register definition*/ __IO uint32_t rpc94; struct { __IO uint32_t gsr_disable_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc94_TypeDef; typedef union{ /*!< rpc95 register definition*/ __IO uint32_t rpc95; struct { __IO uint32_t ibufmd_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc95_TypeDef; typedef union{ /*!< rpc96 register definition*/ __IO uint32_t rpc96; struct { __IO uint32_t ibufmd_clk :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc96_TypeDef; typedef union{ /*!< rpc97 register definition*/ __IO uint32_t rpc97; struct { __IO uint32_t ibufmd_dq :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc97_TypeDef; typedef union{ /*!< rpc98 register definition*/ __IO uint32_t rpc98; struct { __IO uint32_t ibufmd_dqs :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc98_TypeDef; typedef union{ /*!< rpc99 register definition*/ __IO uint32_t rpc99; struct { __IO uint32_t indly_sel_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc99_TypeDef; typedef union{ /*!< rpc100 register definition*/ __IO uint32_t rpc100; struct { __IO uint32_t indly_sel_clkn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc100_TypeDef; typedef union{ /*!< rpc101 register definition*/ __IO uint32_t rpc101; struct { __IO uint32_t indly_sel_clkp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc101_TypeDef; typedef union{ /*!< rpc102 register definition*/ __IO uint32_t rpc102; struct { __IO uint32_t indly_sel_dq :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc102_TypeDef; typedef union{ /*!< rpc103 register definition*/ __IO uint32_t rpc103; struct { __IO uint32_t indly_sel_dqsn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc103_TypeDef; typedef union{ /*!< rpc104 register definition*/ __IO uint32_t rpc104; struct { __IO uint32_t indly_sel_dqsp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc104_TypeDef; typedef union{ /*!< rpc105 register definition*/ __IO uint32_t rpc105; struct { __IO uint32_t lane_pvt_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc105_TypeDef; typedef union{ /*!< rpc106 register definition*/ __IO uint32_t rpc106; struct { __IO uint32_t lane_pvt_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc106_TypeDef; typedef union{ /*!< rpc107 register definition*/ __IO uint32_t rpc107; struct { __IO uint32_t lsr_disable_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc107_TypeDef; typedef union{ /*!< rpc108 register definition*/ __IO uint32_t rpc108; struct { __IO uint32_t lsr_disable_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc108_TypeDef; typedef union{ /*!< rpc109 register definition*/ __IO uint32_t rpc109; struct { __IO uint32_t lsr_disable_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc109_TypeDef; typedef union{ /*!< rpc110 register definition*/ __IO uint32_t rpc110; struct { __IO uint32_t lsr_disable_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc110_TypeDef; typedef union{ /*!< rpc111 register definition*/ __IO uint32_t rpc111; struct { __IO uint32_t lsr_disable_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc111_TypeDef; typedef union{ /*!< rpc112 register definition*/ __IO uint32_t rpc112; struct { __IO uint32_t lsr_disable_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc112_TypeDef; typedef union{ /*!< rpc113 register definition*/ __IO uint32_t rpc113; struct { __IO uint32_t mvdly_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc113_TypeDef; typedef union{ /*!< rpc114 register definition*/ __IO uint32_t rpc114; struct { __IO uint32_t mvdly_en_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc114_TypeDef; typedef union{ /*!< rpc115 register definition*/ __IO uint32_t rpc115; struct { __IO uint32_t mvdly_en_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc115_TypeDef; typedef union{ /*!< rpc116 register definition*/ __IO uint32_t rpc116; struct { __IO uint32_t mvdly_en_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc116_TypeDef; typedef union{ /*!< rpc117 register definition*/ __IO uint32_t rpc117; struct { __IO uint32_t mvdly_en_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc117_TypeDef; typedef union{ /*!< rpc118 register definition*/ __IO uint32_t rpc118; struct { __IO uint32_t mvdly_en_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc118_TypeDef; typedef union{ /*!< rpc119 register definition*/ __IO uint32_t rpc119; struct { __IO uint32_t oeclk_inv_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc119_TypeDef; typedef union{ /*!< rpc120 register definition*/ __IO uint32_t rpc120; struct { __IO uint32_t oeclk_inv_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc120_TypeDef; typedef union{ /*!< rpc121 register definition*/ __IO uint32_t rpc121; struct { __IO uint32_t oeclk_inv_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc121_TypeDef; typedef union{ /*!< rpc122 register definition*/ __IO uint32_t rpc122; struct { __IO uint32_t oeclk_inv_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc122_TypeDef; typedef union{ /*!< rpc123 register definition*/ __IO uint32_t rpc123; struct { __IO uint32_t oeclk_inv_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc123_TypeDef; typedef union{ /*!< rpc124 register definition*/ __IO uint32_t rpc124; struct { __IO uint32_t oeclk_inv_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc124_TypeDef; typedef union{ /*!< rpc125 register definition*/ __IO uint32_t rpc125; struct { __IO uint32_t oe_md_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc125_TypeDef; typedef union{ /*!< rpc126 register definition*/ __IO uint32_t rpc126; struct { __IO uint32_t oe_md_clkn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc126_TypeDef; typedef union{ /*!< rpc127 register definition*/ __IO uint32_t rpc127; struct { __IO uint32_t oe_md_clkp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc127_TypeDef; typedef union{ /*!< rpc128 register definition*/ __IO uint32_t rpc128; struct { __IO uint32_t oe_md_dq :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc128_TypeDef; typedef union{ /*!< rpc129 register definition*/ __IO uint32_t rpc129; struct { __IO uint32_t oe_md_dqsn :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc129_TypeDef; typedef union{ /*!< rpc130 register definition*/ __IO uint32_t rpc130; struct { __IO uint32_t oe_md_dqsp :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc130_TypeDef; typedef union{ /*!< rpc131 register definition*/ __IO uint32_t rpc131; struct { __IO uint32_t pause_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc131_TypeDef; typedef union{ /*!< rpc132 register definition*/ __IO uint32_t rpc132; struct { __IO uint32_t pause_en_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc132_TypeDef; typedef union{ /*!< rpc133 register definition*/ __IO uint32_t rpc133; struct { __IO uint32_t qdr_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc133_TypeDef; typedef union{ /*!< rpc134 register definition*/ __IO uint32_t rpc134; struct { __IO uint32_t qdr_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc134_TypeDef; typedef union{ /*!< rpc135 register definition*/ __IO uint32_t rpc135; struct { __IO uint32_t qdr_md_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc135_TypeDef; typedef union{ /*!< rpc136 register definition*/ __IO uint32_t rpc136; struct { __IO uint32_t qdr_md_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc136_TypeDef; typedef union{ /*!< rpc137 register definition*/ __IO uint32_t rpc137; struct { __IO uint32_t qdr_md_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc137_TypeDef; typedef union{ /*!< rpc138 register definition*/ __IO uint32_t rpc138; struct { __IO uint32_t qdr_md_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc138_TypeDef; typedef union{ /*!< rpc139 register definition*/ __IO uint32_t rpc139; struct { __IO uint32_t qdr_md_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc139_TypeDef; typedef union{ /*!< rpc140 register definition*/ __IO uint32_t rpc140; struct { __IO uint32_t qdr_md_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc140_TypeDef; typedef union{ /*!< rpc141 register definition*/ __IO uint32_t rpc141; struct { __IO uint32_t rank2_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc141_TypeDef; typedef union{ /*!< rpc142 register definition*/ __IO uint32_t rpc142; struct { __IO uint32_t rank2_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc142_TypeDef; typedef union{ /*!< rpc143 register definition*/ __IO uint32_t rpc143; struct { __IO uint32_t rst_inv_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc143_TypeDef; typedef union{ /*!< rpc144 register definition*/ __IO uint32_t rpc144; struct { __IO uint32_t rst_inv_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc144_TypeDef; typedef union{ /*!< rpc145 register definition*/ __IO uint32_t rpc145; struct { __IO uint32_t rxdly_addcmd :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc145_TypeDef; typedef union{ /*!< rpc146 register definition*/ __IO uint32_t rpc146; struct { __IO uint32_t rxdly_clkn :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc146_TypeDef; typedef union{ /*!< rpc147 register definition*/ __IO uint32_t rpc147; struct { __IO uint32_t rxdly_clkp :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc147_TypeDef; typedef union{ /*!< rpc148 register definition*/ __IO uint32_t rpc148; struct { __IO uint32_t rxdly_dir_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc148_TypeDef; typedef union{ /*!< rpc149 register definition*/ __IO uint32_t rpc149; struct { __IO uint32_t rxdly_dir_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc149_TypeDef; typedef union{ /*!< rpc150 register definition*/ __IO uint32_t rpc150; struct { __IO uint32_t rxdly_dq :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc150_TypeDef; typedef union{ /*!< rpc151 register definition*/ __IO uint32_t rpc151; struct { __IO uint32_t rxdly_dqsn :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc151_TypeDef; typedef union{ /*!< rpc152 register definition*/ __IO uint32_t rpc152; struct { __IO uint32_t rxdly_dqsp :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc152_TypeDef; typedef union{ /*!< rpc153 register definition*/ __IO uint32_t rpc153; struct { __IO uint32_t rxdly_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc153_TypeDef; typedef union{ /*!< rpc154 register definition*/ __IO uint32_t rpc154; struct { __IO uint32_t rxdly_en_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc154_TypeDef; typedef union{ /*!< rpc155 register definition*/ __IO uint32_t rpc155; struct { __IO uint32_t rxdly_offset_addcmd :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_rpc155_TypeDef; typedef union{ /*!< rpc156 register definition*/ __IO uint32_t rpc156; struct { __IO uint32_t rxdly_offset_data :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_rpc156_TypeDef; typedef union{ /*!< rpc157 register definition*/ __IO uint32_t rpc157; struct { __IO uint32_t rxdly_wide_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc157_TypeDef; typedef union{ /*!< rpc158 register definition*/ __IO uint32_t rpc158; struct { __IO uint32_t rxdly_wide_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc158_TypeDef; typedef union{ /*!< rpc159 register definition*/ __IO uint32_t rpc159; struct { __IO uint32_t rxdly_wide_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc159_TypeDef; typedef union{ /*!< rpc160 register definition*/ __IO uint32_t rpc160; struct { __IO uint32_t rxdly_wide_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc160_TypeDef; typedef union{ /*!< rpc161 register definition*/ __IO uint32_t rpc161; struct { __IO uint32_t rxdly_wide_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc161_TypeDef; typedef union{ /*!< rpc162 register definition*/ __IO uint32_t rpc162; struct { __IO uint32_t rxdly_wide_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc162_TypeDef; typedef union{ /*!< rpc163 register definition*/ __IO uint32_t rpc163; struct { __IO uint32_t rxmvdly_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc163_TypeDef; typedef union{ /*!< rpc164 register definition*/ __IO uint32_t rpc164; struct { __IO uint32_t rxmvdly_en_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc164_TypeDef; typedef union{ /*!< rpc165 register definition*/ __IO uint32_t rpc165; struct { __IO uint32_t rxptr_addcmd :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc165_TypeDef; typedef union{ /*!< rpc166 register definition*/ __IO uint32_t rpc166; struct { __IO uint32_t rxptr_data :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_rpc166_TypeDef; typedef union{ /*!< rpc167 register definition*/ __IO uint32_t rpc167; struct { __IO uint32_t rx_md_addcmd :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc167_TypeDef; typedef union{ /*!< rpc168 register definition*/ __IO uint32_t rpc168; struct { __IO uint32_t rx_md_clkn :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc168_TypeDef; typedef union{ /*!< rpc169 register definition*/ __IO uint32_t rpc169; struct { __IO uint32_t rx_md_clkp :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc169_TypeDef; typedef union{ /*!< rpc170 register definition*/ __IO uint32_t rpc170; struct { __IO uint32_t rx_md_dq :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc170_TypeDef; typedef union{ /*!< rpc171 register definition*/ __IO uint32_t rpc171; struct { __IO uint32_t rx_md_dqsn :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc171_TypeDef; typedef union{ /*!< rpc172 register definition*/ __IO uint32_t rpc172; struct { __IO uint32_t rx_md_dqsp :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_rpc172_TypeDef; typedef union{ /*!< rpc173 register definition*/ __IO uint32_t rpc173; struct { __IO uint32_t sclk0_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc173_TypeDef; typedef union{ /*!< rpc174 register definition*/ __IO uint32_t rpc174; struct { __IO uint32_t sclk0_en_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc174_TypeDef; typedef union{ /*!< rpc175 register definition*/ __IO uint32_t rpc175; struct { __IO uint32_t sclk0_en_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc175_TypeDef; typedef union{ /*!< rpc176 register definition*/ __IO uint32_t rpc176; struct { __IO uint32_t sclk0_en_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc176_TypeDef; typedef union{ /*!< rpc177 register definition*/ __IO uint32_t rpc177; struct { __IO uint32_t sclk0_en_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc177_TypeDef; typedef union{ /*!< rpc178 register definition*/ __IO uint32_t rpc178; struct { __IO uint32_t sclk0_en_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc178_TypeDef; typedef union{ /*!< rpc179 register definition*/ __IO uint32_t rpc179; struct { __IO uint32_t sclk0_inv_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc179_TypeDef; typedef union{ /*!< rpc180 register definition*/ __IO uint32_t rpc180; struct { __IO uint32_t sclk0_inv_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc180_TypeDef; typedef union{ /*!< rpc181 register definition*/ __IO uint32_t rpc181; struct { __IO uint32_t sclk0_inv_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc181_TypeDef; typedef union{ /*!< rpc182 register definition*/ __IO uint32_t rpc182; struct { __IO uint32_t sclk0_inv_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc182_TypeDef; typedef union{ /*!< rpc183 register definition*/ __IO uint32_t rpc183; struct { __IO uint32_t sclk0_inv_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc183_TypeDef; typedef union{ /*!< rpc184 register definition*/ __IO uint32_t rpc184; struct { __IO uint32_t sclk0_inv_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc184_TypeDef; typedef union{ /*!< rpc185 register definition*/ __IO uint32_t rpc185; struct { __IO uint32_t sclk1_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc185_TypeDef; typedef union{ /*!< rpc186 register definition*/ __IO uint32_t rpc186; struct { __IO uint32_t sclk1_en_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc186_TypeDef; typedef union{ /*!< rpc187 register definition*/ __IO uint32_t rpc187; struct { __IO uint32_t sclk1_en_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc187_TypeDef; typedef union{ /*!< rpc188 register definition*/ __IO uint32_t rpc188; struct { __IO uint32_t sclk1_en_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc188_TypeDef; typedef union{ /*!< rpc189 register definition*/ __IO uint32_t rpc189; struct { __IO uint32_t sclk1_en_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc189_TypeDef; typedef union{ /*!< rpc190 register definition*/ __IO uint32_t rpc190; struct { __IO uint32_t sclk1_en_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc190_TypeDef; typedef union{ /*!< rpc191 register definition*/ __IO uint32_t rpc191; struct { __IO uint32_t sclk1_inv_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc191_TypeDef; typedef union{ /*!< rpc192 register definition*/ __IO uint32_t rpc192; struct { __IO uint32_t sclk1_inv_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc192_TypeDef; typedef union{ /*!< rpc193 register definition*/ __IO uint32_t rpc193; struct { __IO uint32_t sclk1_inv_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc193_TypeDef; typedef union{ /*!< rpc194 register definition*/ __IO uint32_t rpc194; struct { __IO uint32_t sclk1_inv_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc194_TypeDef; typedef union{ /*!< rpc195 register definition*/ __IO uint32_t rpc195; struct { __IO uint32_t sclk1_inv_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc195_TypeDef; typedef union{ /*!< rpc196 register definition*/ __IO uint32_t rpc196; struct { __IO uint32_t sclk1_inv_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc196_TypeDef; typedef union{ /*!< rpc197 register definition*/ __IO uint32_t rpc197; struct { __IO uint32_t soft_reset_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc197_TypeDef; typedef union{ /*!< rpc198 register definition*/ __IO uint32_t rpc198; struct { __IO uint32_t soft_reset_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc198_TypeDef; typedef union{ /*!< rpc199 register definition*/ __IO uint32_t rpc199; struct { __IO uint32_t spare_iog_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc199_TypeDef; typedef union{ /*!< rpc200 register definition*/ __IO uint32_t rpc200; struct { __IO uint32_t spare_iog_clkn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc200_TypeDef; typedef union{ /*!< rpc201 register definition*/ __IO uint32_t rpc201; struct { __IO uint32_t spare_iog_clkp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc201_TypeDef; typedef union{ /*!< rpc202 register definition*/ __IO uint32_t rpc202; struct { __IO uint32_t spare_iog_dq :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc202_TypeDef; typedef union{ /*!< rpc203 register definition*/ __IO uint32_t rpc203; struct { __IO uint32_t spare_iog_dqsn :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc203_TypeDef; typedef union{ /*!< rpc204 register definition*/ __IO uint32_t rpc204; struct { __IO uint32_t spare_iog_dqsp :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc204_TypeDef; typedef union{ /*!< rpc205 register definition*/ __IO uint32_t rpc205; struct { __IO uint32_t spio_sel_di_dqsn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc205_TypeDef; typedef union{ /*!< rpc206 register definition*/ __IO uint32_t rpc206; struct { __IO uint32_t spio_sel_di_dqsp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc206_TypeDef; typedef union{ /*!< rpc207 register definition*/ __IO uint32_t rpc207; struct { __IO uint32_t stop_sel_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc207_TypeDef; typedef union{ /*!< rpc208 register definition*/ __IO uint32_t rpc208; struct { __IO uint32_t stop_sel_data :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc208_TypeDef; typedef union{ /*!< rpc209 register definition*/ __IO uint32_t rpc209; struct { __IO uint32_t txclk_sel_addcmd :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc209_TypeDef; typedef union{ /*!< rpc210 register definition*/ __IO uint32_t rpc210; struct { __IO uint32_t txclk_sel_clkn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc210_TypeDef; typedef union{ /*!< rpc211 register definition*/ __IO uint32_t rpc211; struct { __IO uint32_t txclk_sel_clkp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc211_TypeDef; typedef union{ /*!< rpc212 register definition*/ __IO uint32_t rpc212; struct { __IO uint32_t txclk_sel_dq :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc212_TypeDef; typedef union{ /*!< rpc213 register definition*/ __IO uint32_t rpc213; struct { __IO uint32_t txclk_sel_dqsn :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc213_TypeDef; typedef union{ /*!< rpc214 register definition*/ __IO uint32_t rpc214; struct { __IO uint32_t txclk_sel_dqsp :2; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_rpc214_TypeDef; typedef union{ /*!< rpc215 register definition*/ __IO uint32_t rpc215; struct { __IO uint32_t txdly_addcmd :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc215_TypeDef; typedef union{ /*!< rpc216 register definition*/ __IO uint32_t rpc216; struct { __IO uint32_t txdly_clkn :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc216_TypeDef; typedef union{ /*!< rpc217 register definition*/ __IO uint32_t rpc217; struct { __IO uint32_t txdly_clkp :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc217_TypeDef; typedef union{ /*!< rpc218 register definition*/ __IO uint32_t rpc218; struct { __IO uint32_t txdly_dir_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc218_TypeDef; typedef union{ /*!< rpc219 register definition*/ __IO uint32_t rpc219; struct { __IO uint32_t txdly_dir_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc219_TypeDef; typedef union{ /*!< rpc220 register definition*/ __IO uint32_t rpc220; struct { __IO uint32_t txdly_dq :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc220_TypeDef; typedef union{ /*!< rpc221 register definition*/ __IO uint32_t rpc221; struct { __IO uint32_t txdly_dqsn :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc221_TypeDef; typedef union{ /*!< rpc222 register definition*/ __IO uint32_t rpc222; struct { __IO uint32_t txdly_dqsp :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc222_TypeDef; typedef union{ /*!< rpc223 register definition*/ __IO uint32_t rpc223; struct { __IO uint32_t txdly_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc223_TypeDef; typedef union{ /*!< rpc224 register definition*/ __IO uint32_t rpc224; struct { __IO uint32_t txdly_en_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc224_TypeDef; typedef union{ /*!< rpc225 register definition*/ __IO uint32_t rpc225; struct { __IO uint32_t txdly_offset_addcmd :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_rpc225_TypeDef; typedef union{ /*!< rpc226 register definition*/ __IO uint32_t rpc226; struct { __IO uint32_t txdly_offset_data :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_rpc226_TypeDef; typedef union{ /*!< rpc227 register definition*/ __IO uint32_t rpc227; struct { __IO uint32_t txmvdly_en_addcmd :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc227_TypeDef; typedef union{ /*!< rpc228 register definition*/ __IO uint32_t rpc228; struct { __IO uint32_t txmvdly_en_data :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rpc228_TypeDef; typedef union{ /*!< rpc229 register definition*/ __IO uint32_t rpc229; struct { __IO uint32_t tx_md_addcmd :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc229_TypeDef; typedef union{ /*!< rpc230 register definition*/ __IO uint32_t rpc230; struct { __IO uint32_t tx_md_clkn :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc230_TypeDef; typedef union{ /*!< rpc231 register definition*/ __IO uint32_t rpc231; struct { __IO uint32_t tx_md_clkp :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc231_TypeDef; typedef union{ /*!< rpc232 register definition*/ __IO uint32_t rpc232; struct { __IO uint32_t tx_md_dq :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc232_TypeDef; typedef union{ /*!< rpc233 register definition*/ __IO uint32_t rpc233; struct { __IO uint32_t tx_md_dqsn :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc233_TypeDef; typedef union{ /*!< rpc234 register definition*/ __IO uint32_t rpc234; struct { __IO uint32_t tx_md_dqsp :7; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_rpc234_TypeDef; typedef union{ /*!< rpc235 register definition*/ __IO uint32_t rpc235; struct { __IO uint32_t wpd_addcmd0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc235_TypeDef; typedef union{ /*!< rpc236 register definition*/ __IO uint32_t rpc236; struct { __IO uint32_t wpd_addcmd1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc236_TypeDef; typedef union{ /*!< rpc237 register definition*/ __IO uint32_t rpc237; struct { __IO uint32_t wpd_addcmd2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc237_TypeDef; typedef union{ /*!< rpc238 register definition*/ __IO uint32_t rpc238; struct { __IO uint32_t wpd_data0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc238_TypeDef; typedef union{ /*!< rpc239 register definition*/ __IO uint32_t rpc239; struct { __IO uint32_t wpd_data1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc239_TypeDef; typedef union{ /*!< rpc240 register definition*/ __IO uint32_t rpc240; struct { __IO uint32_t wpd_data2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc240_TypeDef; typedef union{ /*!< rpc241 register definition*/ __IO uint32_t rpc241; struct { __IO uint32_t wpd_data3 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc241_TypeDef; typedef union{ /*!< rpc242 register definition*/ __IO uint32_t rpc242; struct { __IO uint32_t wpd_ecc :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc242_TypeDef; typedef union{ /*!< rpc243 register definition*/ __IO uint32_t rpc243; struct { __IO uint32_t wpu_addcmd0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc243_TypeDef; typedef union{ /*!< rpc244 register definition*/ __IO uint32_t rpc244; struct { __IO uint32_t wpu_addcmd1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc244_TypeDef; typedef union{ /*!< rpc245 register definition*/ __IO uint32_t rpc245; struct { __IO uint32_t wpu_addcmd2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc245_TypeDef; typedef union{ /*!< rpc246 register definition*/ __IO uint32_t rpc246; struct { __IO uint32_t wpu_data0 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc246_TypeDef; typedef union{ /*!< rpc247 register definition*/ __IO uint32_t rpc247; struct { __IO uint32_t wpu_data1 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc247_TypeDef; typedef union{ /*!< rpc248 register definition*/ __IO uint32_t rpc248; struct { __IO uint32_t wpu_data2 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc248_TypeDef; typedef union{ /*!< rpc249 register definition*/ __IO uint32_t rpc249; struct { __IO uint32_t wpu_data3 :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc249_TypeDef; typedef union{ /*!< rpc250 register definition*/ __IO uint32_t rpc250; struct { __IO uint32_t wpu_ecc :12; __I uint32_t reserved_01 :20; } bitfield; } CFG_DDR_SGMII_PHY_rpc250_TypeDef; typedef union{ /*!< spio251 register definition*/ __IO uint32_t spio251; struct { __IO uint32_t sel_refclk0 :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_spio251_TypeDef; typedef union{ /*!< spio252 register definition*/ __IO uint32_t spio252; struct { __IO uint32_t sel_refclk1 :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_spio252_TypeDef; typedef union{ /*!< spio253 register definition*/ __IO uint32_t spio253; struct { __IO uint32_t sel_refclk2 :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_spio253_TypeDef; typedef union{ /*!< SOFT_RESET_TIP register definition*/ __IO uint32_t SOFT_RESET_TIP; struct { __O CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_NV_MAP_TIP_TypeDef NV_MAP_TIP :1; __O CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_V_MAP_TIP_TypeDef V_MAP_TIP :1; __I uint32_t reserved_01 :6; __O CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_PERIPH_TIP_TypeDef PERIPH_TIP :1; __I uint32_t reserved_02 :7; __I uint32_t BLOCKID_TIP :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_TypeDef; typedef union{ /*!< rank_select register definition*/ __IO uint32_t rank_select; struct { __IO uint32_t rank :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_rank_select_TypeDef; typedef union{ /*!< lane_select register definition*/ __IO uint32_t lane_select; struct { __IO uint32_t lane :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_lane_select_TypeDef; typedef union{ /*!< training_skip register definition*/ __IO uint32_t training_skip; struct { __IO uint32_t skip_bclksclk :1; __IO uint32_t skip_addcmd :1; __IO uint32_t skip_wrlvl :1; __IO uint32_t skip_rdgate :1; __IO uint32_t skip_dq_dqs_opt :1; __IO uint32_t skip_write_calibration :1; __IO uint32_t skip_vref_mr6 :1; __IO uint32_t step7 :1; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_training_skip_TypeDef; typedef union{ /*!< training_start register definition*/ __IO uint32_t training_start; struct { __IO uint32_t start :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_training_start_TypeDef; typedef union{ /*!< training_status register definition*/ __I uint32_t training_status; struct { __I uint32_t status :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_training_status_TypeDef; typedef union{ /*!< training_reset register definition*/ __IO uint32_t training_reset; struct { __IO uint32_t reset :1; __I uint32_t reserved_01 :31; } bitfield; } CFG_DDR_SGMII_PHY_training_reset_TypeDef; typedef union{ /*!< gt_err_comb register definition*/ __I uint32_t gt_err_comb; struct { __I uint32_t error_comb_lanex :6; __I uint32_t reserved_01 :26; } bitfield; } CFG_DDR_SGMII_PHY_gt_err_comb_TypeDef; typedef union{ /*!< gt_clk_sel register definition*/ __I uint32_t gt_clk_sel; struct { __I uint32_t clk_sel_lanex_rankx :3; __I uint32_t reserved_01 :29; } bitfield; } CFG_DDR_SGMII_PHY_gt_clk_sel_TypeDef; typedef union{ /*!< gt_txdly register definition*/ __I uint32_t gt_txdly; struct { __I uint32_t txdly0_lanex :8; __I uint32_t txdly1_lanex :8; __I uint32_t txdly2_lanex :8; __I uint32_t txdly3_lanex :8; } bitfield; } CFG_DDR_SGMII_PHY_gt_txdly_TypeDef; typedef union{ /*!< gt_steps_180 register definition*/ __I uint32_t gt_steps_180; struct { __I uint32_t steps_180_lanex_rankx :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_gt_steps_180_TypeDef; typedef union{ /*!< gt_state register definition*/ __I uint32_t gt_state; struct { __I uint32_t gt_state_lanex :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_gt_state_TypeDef; typedef union{ /*!< wl_delay_0 register definition*/ __I uint32_t wl_delay_0; struct { __I uint32_t wldelay_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_wl_delay_0_TypeDef; typedef union{ /*!< dq_dqs_err_done register definition*/ __I uint32_t dq_dqs_err_done; struct { __I uint32_t dq_dqs_error_done_lanex_rankx :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_dq_dqs_err_done_TypeDef; typedef union{ /*!< dqdqs_window register definition*/ __I uint32_t dqdqs_window; struct { __I uint32_t ils_lanex_rankx :8; __I uint32_t irs_lanex_rankx :8; __I uint32_t reserved_01 :16; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_window_TypeDef; typedef union{ /*!< dqdqs_state register definition*/ __I uint32_t dqdqs_state; struct { __I uint32_t state_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_state_TypeDef; typedef union{ /*!< delta0 register definition*/ __I uint32_t delta0; struct { __I uint32_t delay0_lanex :8; __I uint32_t delay1_lanex :8; __I uint32_t delay2_lanex :8; __I uint32_t delay3_lanex :8; } bitfield; } CFG_DDR_SGMII_PHY_delta0_TypeDef; typedef union{ /*!< delta1 register definition*/ __I uint32_t delta1; struct { __I uint32_t delay4_lanex :8; __I uint32_t delay5_lanex :8; __I uint32_t delay6_lanex :8; __I uint32_t delay7_lanex :8; } bitfield; } CFG_DDR_SGMII_PHY_delta1_TypeDef; typedef union{ /*!< dqdqs_status0 register definition*/ __I uint32_t dqdqs_status0; struct { __I uint32_t init_dly_lanex :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status0_TypeDef; typedef union{ /*!< dqdqs_status1 register definition*/ __I uint32_t dqdqs_status1; struct { __I uint32_t dqs_dly_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status1_TypeDef; typedef union{ /*!< dqdqs_status2 register definition*/ __I uint32_t dqdqs_status2; struct { __I uint32_t bit_width_lanex :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status2_TypeDef; typedef union{ /*!< dqdqs_status3 register definition*/ __I uint32_t dqdqs_status3; struct { __I uint32_t initldqs_2_mid_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status3_TypeDef; typedef union{ /*!< dqdqs_status4 register definition*/ __I uint32_t dqdqs_status4; struct { __I uint32_t mid_2_initldqs_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status4_TypeDef; typedef union{ /*!< dqdqs_status5 register definition*/ __I uint32_t dqdqs_status5; struct { __I uint32_t stw_2_initldqs_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status5_TypeDef; typedef union{ /*!< dqdqs_status6 register definition*/ __I uint32_t dqdqs_status6; struct { __I uint32_t initldqs_2_stw_lanex_rankx :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_status6_TypeDef; typedef union{ /*!< addcmd_status0 register definition*/ __I uint32_t addcmd_status0; struct { __I uint32_t delay_vcophs_sel0 :8; __I uint32_t delay_vcophs_sel1 :8; __I uint32_t delay_vcophs_sel2 :8; __I uint32_t delay_vcophs_sel3 :8; } bitfield; } CFG_DDR_SGMII_PHY_addcmd_status0_TypeDef; typedef union{ /*!< addcmd_status1 register definition*/ __I uint32_t addcmd_status1; struct { __I uint32_t delay_vcophs_sel4 :8; __I uint32_t delay_vcophs_sel5 :8; __I uint32_t delay_vcophs_sel6 :8; __I uint32_t delay_vcophs_sel7 :8; } bitfield; } CFG_DDR_SGMII_PHY_addcmd_status1_TypeDef; typedef union{ /*!< addcmd_answer register definition*/ __I uint32_t addcmd_answer; struct { __I uint32_t vcophs_sel_after_training :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_addcmd_answer_TypeDef; typedef union{ /*!< bclksclk_answer register definition*/ __I uint32_t bclksclk_answer; struct { __I uint32_t bclk0_vcophs_sel :4; __I uint32_t reserved_01 :28; } bitfield; } CFG_DDR_SGMII_PHY_bclksclk_answer_TypeDef; typedef union{ /*!< dqdqs_wrcalib_offset register definition*/ __I uint32_t dqdqs_wrcalib_offset; struct { __I uint32_t wrcalib_offset_lanex :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_dqdqs_wrcalib_offset_TypeDef; typedef union{ /*!< expert_mode_en register definition*/ __IO uint32_t expert_mode_en; struct { __IO uint32_t dyn_ovr_dlycnt_en :1; __IO uint32_t dyn_ovr_pllcnt_en :1; __IO uint32_t dyn_ovr_rdgate_en :1; __IO uint32_t dyn_ovr_wrcalib_en :1; __IO uint32_t dyn_ovr_calif_en :1; __IO uint32_t dyn_ovr_dfi_shim_en :1; __I uint32_t reserved_01 :26; } bitfield; } CFG_DDR_SGMII_PHY_expert_mode_en_TypeDef; typedef union{ /*!< expert_dlycnt_move_reg0 register definition*/ __IO uint32_t expert_dlycnt_move_reg0; struct { __IO uint32_t dyn_ovr_dlycnt_dq_move0 :8; __IO uint32_t dyn_ovr_dlycnt_dq_move1 :8; __IO uint32_t dyn_ovr_dlycnt_dq_move2 :8; __IO uint32_t dyn_ovr_dlycnt_dq_move3 :8; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_move_reg0_TypeDef; typedef union{ /*!< expert_dlycnt_move_reg1 register definition*/ __IO uint32_t expert_dlycnt_move_reg1; struct { __IO uint32_t dyn_ovr_dlycnt_dq_move4 :4; __IO uint32_t dyn_ovr_dlycnt_lanectrl_move0 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_move1 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_move2 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_move3 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_move4 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_move0 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_move1 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_move2 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_move3 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_move4 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_move0 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_move1 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_move2 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_move3 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_move4 :1; __IO uint32_t dyn_ovr_dlycnt_catrn_move :1; __IO uint32_t dyn_ovr_dlycnt_ca_move :1; __I uint32_t reserved_01 :11; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_move_reg1_TypeDef; typedef union{ /*!< expert_dlycnt_direction_reg0 register definition*/ __IO uint32_t expert_dlycnt_direction_reg0; struct { __IO uint32_t dyn_ovr_dlycnt_dq_direction0 :8; __IO uint32_t dyn_ovr_dlycnt_dq_direction1 :8; __IO uint32_t dyn_ovr_dlycnt_dq_direction2 :8; __IO uint32_t dyn_ovr_dlycnt_dq_direction3 :8; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_direction_reg0_TypeDef; typedef union{ /*!< expert_dlycnt_direction_reg1 register definition*/ __IO uint32_t expert_dlycnt_direction_reg1; struct { __IO uint32_t dyn_ovr_dlycnt_dq_direction4 :4; __IO uint32_t dyn_ovr_dlycnt_lanectrl_direction0 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_direction1 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_direction2 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_direction3 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_direction4 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_direction0 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_direction1 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_direction2 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_direction3 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_direction4 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_direction0 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_direction1 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_direction2 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_direction3 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_direction4 :1; __IO uint32_t dyn_ovr_dlycnt_catrn_direction :1; __IO uint32_t dyn_ovr_dlycnt_ca_direction :1; __I uint32_t reserved_01 :11; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_direction_reg1_TypeDef; typedef union{ /*!< expert_dlycnt_load_reg0 register definition*/ __IO uint32_t expert_dlycnt_load_reg0; struct { __IO uint32_t dyn_ovr_dlycnt_dq_load0 :8; __IO uint32_t dyn_ovr_dlycnt_dq_load1 :8; __IO uint32_t dyn_ovr_dlycnt_dq_load2 :8; __IO uint32_t dyn_ovr_dlycnt_dq_load3 :8; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_load_reg0_TypeDef; typedef union{ /*!< expert_dlycnt_load_reg1 register definition*/ __IO uint32_t expert_dlycnt_load_reg1; struct { __IO uint32_t dyn_ovr_dlycnt_dq_load4 :4; __IO uint32_t dyn_ovr_dlycnt_lanectrl_load0 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_load1 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_load2 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_load3 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_load4 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_load0 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_load1 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_load2 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_load3 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw270_load4 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_load0 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_load1 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_load2 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_load3 :1; __IO uint32_t dyn_ovr_dlycnt_dqsw_load4 :1; __IO uint32_t dyn_ovr_dlycnt_catrn_load :1; __IO uint32_t dyn_ovr_dlycnt_ca_load :1; __I uint32_t reserved_01 :11; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_load_reg1_TypeDef; typedef union{ /*!< expert_dlycnt_oor_reg0 register definition*/ __I uint32_t expert_dlycnt_oor_reg0; struct { __I uint32_t dyn_ovr_dlycnt_dq_oor0 :8; __I uint32_t dyn_ovr_dlycnt_dq_oor1 :8; __I uint32_t dyn_ovr_dlycnt_dq_oor2 :8; __I uint32_t dyn_ovr_dlycnt_dq_oor3 :8; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_oor_reg0_TypeDef; typedef union{ /*!< expert_dlycnt_oor_reg1 register definition*/ __I uint32_t expert_dlycnt_oor_reg1; struct { __I uint32_t dyn_ovr_dlycnt_dq_oor4 :4; __I uint32_t dyn_ovr_dlycnt_lanectrl_oor0 :1; __I uint32_t dyn_ovr_dlycnt_lanectrl_oor1 :1; __I uint32_t dyn_ovr_dlycnt_lanectrl_oor2 :1; __I uint32_t dyn_ovr_dlycnt_lanectrl_oor3 :1; __I uint32_t dyn_ovr_dlycnt_lanectrl_oor4 :1; __I uint32_t dyn_ovr_dlycnt_dqsw270_oor0 :1; __I uint32_t dyn_ovr_dlycnt_dqsw270_oor1 :1; __I uint32_t dyn_ovr_dlycnt_dqsw270_oor2 :1; __I uint32_t dyn_ovr_dlycnt_dqsw270_oor3 :1; __I uint32_t dyn_ovr_dlycnt_dqsw270_oor4 :1; __I uint32_t dyn_ovr_dlycnt_dqsw_oor0 :1; __I uint32_t dyn_ovr_dlycnt_dqsw_oor1 :1; __I uint32_t dyn_ovr_dlycnt_dqsw_oor2 :1; __I uint32_t dyn_ovr_dlycnt_dqsw_oor3 :1; __I uint32_t dyn_ovr_dlycnt_dqsw_oor4 :1; __I uint32_t dyn_ovr_dlycnt_catrn_oor :1; __I uint32_t dyn_ovr_dlycnt_ca_oor :1; __I uint32_t reserved_01 :11; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_oor_reg1_TypeDef; typedef union{ /*!< expert_dlycnt_mv_rd_dly_reg register definition*/ __IO uint32_t expert_dlycnt_mv_rd_dly_reg; struct { __IO uint32_t dyn_ovr_dlycnt_lanectrl_mv_rd_dly0 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_mv_rd_dly1 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_mv_rd_dly2 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_mv_rd_dly3 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_mv_rd_dly4 :1; __I uint32_t reserved_01 :27; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_mv_rd_dly_reg_TypeDef; typedef union{ /*!< expert_dlycnt_pause register definition*/ __IO uint32_t expert_dlycnt_pause; struct { __IO uint32_t dyn_ovr_dlycnt_lanectrl_pause_addcmd :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_pause_data0 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_pause_data1 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_pause_data2 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_pause_data3 :1; __IO uint32_t dyn_ovr_dlycnt_lanectrl_pause_data4 :1; __I uint32_t reserved_01 :26; } bitfield; } CFG_DDR_SGMII_PHY_expert_dlycnt_pause_TypeDef; typedef union{ /*!< expert_pllcnt register definition*/ __IO uint32_t expert_pllcnt; struct { __IO uint32_t dyn_ovr_dlycnt_rotate :1; __IO uint32_t dyn_ovr_dlycnt_direction :1; __IO uint32_t dyn_ovr_dlycnt_loadphs_b :1; __IO uint32_t dyn_ovr_dlycnt_phsel :4; __I uint32_t reserved_01 :25; } bitfield; } CFG_DDR_SGMII_PHY_expert_pllcnt_TypeDef; typedef union{ /*!< expert_dqlane_readback register definition*/ __I uint32_t expert_dqlane_readback; struct { __I uint32_t dq_or :5; __I uint32_t dq_and :5; __I uint32_t burst_valid :5; __I uint32_t reserved_01 :17; } bitfield; } CFG_DDR_SGMII_PHY_expert_dqlane_readback_TypeDef; typedef union{ /*!< expert_addcmd_ln_readback register definition*/ __I uint32_t expert_addcmd_ln_readback; struct { __I uint32_t rx_refclk :8; __I uint32_t rx_addcmd :4; __I uint32_t rx_bclksclk :2; __I uint32_t reserved_01 :18; } bitfield; } CFG_DDR_SGMII_PHY_expert_addcmd_ln_readback_TypeDef; typedef union{ /*!< expert_read_gate_controls register definition*/ __IO uint32_t expert_read_gate_controls; struct { __IO uint32_t dyn_ovr_rdgate_clksel :10; __IO uint32_t dyn_ovr_rdgate_steps180 :20; __I uint32_t reserved_01 :2; } bitfield; } CFG_DDR_SGMII_PHY_expert_read_gate_controls_TypeDef; typedef union{ /*!< expert_dq_dqs_optimization0 register definition*/ __I uint32_t expert_dq_dqs_optimization0; struct { __I uint32_t dyn_ovr_dqdqs_data_match_lane0 :8; __I uint32_t dyn_ovr_dqdqs_data_match_lane1 :8; __I uint32_t dyn_ovr_dqdqs_data_match_lane2 :8; __I uint32_t dyn_ovr_dqdqs_data_match_lane3 :8; } bitfield; } CFG_DDR_SGMII_PHY_expert_dq_dqs_optimization0_TypeDef; typedef union{ /*!< expert_dq_dqs_optimization1 register definition*/ __I uint32_t expert_dq_dqs_optimization1; struct { __I uint32_t dyn_ovr_dqdqs_data_match_lane4 :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_expert_dq_dqs_optimization1_TypeDef; typedef union{ /*!< expert_wrcalib register definition*/ __IO uint32_t expert_wrcalib; struct { __IO uint32_t dyn_ovr_wrcalib_offset_lane0 :4; __IO uint32_t dyn_ovr_wrcalib_offset_lane1 :4; __IO uint32_t dyn_ovr_wrcalib_offset_lane2 :4; __IO uint32_t dyn_ovr_wrcalib_offset_lane3 :4; __IO uint32_t dyn_ovr_wrcalib_offset_lane4 :4; __I uint32_t reserved_01 :12; } bitfield; } CFG_DDR_SGMII_PHY_expert_wrcalib_TypeDef; typedef union{ /*!< expert_calif register definition*/ __IO uint32_t expert_calif; struct { __IO uint32_t dyn_ovr_calif_read :1; __IO uint32_t dyn_ovr_calif_write :1; __IO uint32_t dyn_ovr_pattern_sel :4; __I uint32_t reserved_01 :26; } bitfield; } CFG_DDR_SGMII_PHY_expert_calif_TypeDef; typedef union{ /*!< expert_calif_readback register definition*/ __I uint32_t expert_calif_readback; struct { __I uint32_t wrcalib_pattern_match_lane0 :8; __I uint32_t wrcalib_pattern_match_lane1 :8; __I uint32_t wrcalib_pattern_match_lane2 :8; __I uint32_t wrcalib_pattern_match_lane3 :8; } bitfield; } CFG_DDR_SGMII_PHY_expert_calif_readback_TypeDef; typedef union{ /*!< expert_calif_readback1 register definition*/ __I uint32_t expert_calif_readback1; struct { __I uint32_t wrcalib_pattern_match_lane4 :8; __I uint32_t reserved_01 :24; } bitfield; } CFG_DDR_SGMII_PHY_expert_calif_readback1_TypeDef; typedef union{ /*!< expert_dfi_status_override_to_shim register definition*/ __IO uint32_t expert_dfi_status_override_to_shim; struct { __IO uint32_t dfi_init_complete_shim :1; __IO uint32_t dfi_training_complete_shim :1; __IO uint32_t dfi_wrlvl_en_shim :1; __IO uint32_t dfi_rdlvl_en_shim :1; __IO uint32_t dfi_rdlvl_gate_en_shim :1; __I uint32_t reserved_01 :27; } bitfield; } CFG_DDR_SGMII_PHY_expert_dfi_status_override_to_shim_TypeDef; typedef union{ /*!< tip_cfg_params register definition*/ __IO uint32_t tip_cfg_params; struct { __IO uint32_t addcmd_offset :3; __IO uint32_t bcklsclk_offset :3; __IO uint32_t wrcalib_write_count :7; __IO uint32_t read_gate_min_reads :9; __IO uint32_t addrcmd_wait_count :9; __I uint32_t reserved_01 :1; } bitfield; } CFG_DDR_SGMII_PHY_tip_cfg_params_TypeDef; typedef union{ /*!< tip_vref_param register definition*/ __IO uint32_t tip_vref_param; struct { __IO uint32_t vref_override :1; __IO uint32_t data_vref :8; __IO uint32_t ca_vref :8; __I uint32_t reserved_01 :15; } bitfield; } CFG_DDR_SGMII_PHY_tip_vref_param_TypeDef; typedef union{ /*!< lane_alignment_fifo_control register definition*/ __IO uint32_t lane_alignment_fifo_control; struct { __IO uint32_t block_fifo :1; __IO uint32_t fifo_reset_n :1; __I uint32_t reserved_01 :30; } bitfield; } CFG_DDR_SGMII_PHY_lane_alignment_fifo_control_TypeDef; typedef union{ /*!< SOFT_RESET_SGMII register definition*/ __IO uint32_t SOFT_RESET_SGMII; struct { __O uint32_t nv_map_SGMII :1; __O uint32_t v_map_SGMII :1; __I uint32_t reserved_01 :6; __O uint32_t periph_SGMII :1; __I uint32_t reserved_02 :7; __I uint32_t blockid_SGMII :16; } bitfield; } CFG_DDR_SGMII_PHY_SOFT_RESET_SGMII_TypeDef; typedef union{ /*!< SGMII_MODE register definition*/ __IO uint32_t SGMII_MODE; struct { __IO uint32_t reg_pll_en :1; __IO uint32_t reg_dll_en :1; __IO uint32_t reg_pvt_en :1; __IO uint32_t reg_bc_vrgen_en :1; __IO uint32_t reg_tx0_en :1; __IO uint32_t reg_rx0_en :1; __IO uint32_t reg_tx1_en :1; __IO uint32_t reg_rx1_en :1; __IO uint32_t reg_dll_lock_flt :2; __IO uint32_t reg_dll_adj_code :4; __IO uint32_t reg_rx0_cdr_reset_b :1; __IO uint32_t reg_rx1_cdr_reset_b :1; __IO uint32_t reg_bc_vrgen :6; __IO uint32_t reg_cdr_move_step :1; __IO uint32_t reg_refclk_en_rdiff :1; __IO uint32_t reg_bc_vs :4; __IO uint32_t reg_refclk_en_udrive_p :1; __IO uint32_t reg_refclk_en_ins_hyst_p :1; __IO uint32_t reg_refclk_en_udrive_n :1; __IO uint32_t reg_refclk_en_ins_hyst_n :1; } bitfield; } CFG_DDR_SGMII_PHY_SGMII_MODE_TypeDef; typedef union{ /*!< PLL_CNTL register definition*/ __IO uint32_t PLL_CNTL; struct { __IO uint32_t reg_pll_postdiv :7; __I uint32_t aro_pll0_lock :1; __IO uint32_t reg_pll_rfdiv :6; __IO uint32_t reg_pll_reg_rfclk_sel :1; __IO uint32_t reg_pll_lp_requires_lock :1; __IO uint32_t reg_pll_intin :12; __IO uint32_t reg_pll_bwi :2; __IO uint32_t reg_pll_bwp :2; } bitfield; } CFG_DDR_SGMII_PHY_PLL_CNTL_TypeDef; typedef union{ /*!< CH0_CNTL register definition*/ __IO uint32_t CH0_CNTL; struct { __IO uint32_t reg_tx0_wpu_p :1; __IO uint32_t reg_tx0_wpd_p :1; __IO uint32_t reg_tx0_slew_p :2; __IO uint32_t reg_tx0_drv_p :4; __IO uint32_t reg_tx0_odt_p :4; __IO uint32_t reg_tx0_odt_static_p :3; __IO uint32_t reg_rx0_tim_long :1; __IO uint32_t reg_rx0_wpu_p :1; __IO uint32_t reg_rx0_wpd_p :1; __IO uint32_t reg_rx0_ibufmd_p :3; __IO uint32_t reg_rx0_eyewidth_p :3; __IO uint32_t reg_rx0_odt_p :4; __IO uint32_t reg_rx0_odt_static_p :3; __I uint32_t reserved_01 :1; } bitfield; } CFG_DDR_SGMII_PHY_CH0_CNTL_TypeDef; typedef union{ /*!< CH1_CNTL register definition*/ __IO uint32_t CH1_CNTL; struct { __IO uint32_t reg_tx1_wpu_p :1; __IO uint32_t reg_tx1_wpd_p :1; __IO uint32_t reg_tx1_slew_p :2; __IO uint32_t reg_tx1_drv_p :4; __IO uint32_t reg_tx1_odt_p :4; __IO uint32_t reg_tx1_odt_static_p :3; __IO uint32_t reg_rx1_tim_long :1; __IO uint32_t reg_rx1_wpu_p :1; __IO uint32_t reg_rx1_wpd_p :1; __IO uint32_t reg_rx1_ibufmd_p :3; __IO uint32_t reg_rx1_eyewidth_p :3; __IO uint32_t reg_rx1_odt_p :4; __IO uint32_t reg_rx1_odt_static_p :3; __I uint32_t reserved_01 :1; } bitfield; } CFG_DDR_SGMII_PHY_CH1_CNTL_TypeDef; typedef union{ /*!< RECAL_CNTL register definition*/ __IO uint32_t RECAL_CNTL; struct { __IO uint32_t reg_recal_diff_range :5; __IO uint32_t reg_recal_start_en :1; __IO uint32_t reg_pvt_calib_start :1; __IO uint32_t reg_pvt_calib_lock :1; __IO uint32_t reg_recal_upd :1; __IO uint32_t bc_vrgen_direction :1; __IO uint32_t bc_vrgen_load :1; __IO uint32_t bc_vrgen_move :1; __IO uint32_t reg_pvt_reg_calib_clkdiv :2; __IO uint32_t reg_pvt_reg_calib_diffr_vsel :2; __I uint32_t sro_dll_90_code :7; __I uint32_t sro_dll_lock :1; __I uint32_t sro_dll_st_code :7; __I uint32_t sro_recal_start :1; } bitfield; } CFG_DDR_SGMII_PHY_RECAL_CNTL_TypeDef; typedef union{ /*!< CLK_CNTL register definition*/ __IO uint32_t CLK_CNTL; struct { __IO uint32_t reg_refclk_en_term_p :2; __IO uint32_t reg_refclk_en_rxmode_p :2; __IO uint32_t reg_refclk_en_term_n :2; __IO uint32_t reg_refclk_en_rxmode_n :2; __IO uint32_t reg_refclk_clkbuf_en_pullup :1; __IO uint32_t reg_clkmux_fclk_sel :3; __IO uint32_t reg_clkmux_pll0_rfclk0_sel :2; __IO uint32_t reg_clkmux_pll0_rfclk1_sel :2; __IO uint32_t reg_clkmux_spare0 :16; } bitfield; } CFG_DDR_SGMII_PHY_CLK_CNTL_TypeDef; typedef union{ /*!< DYN_CNTL register definition*/ __IO uint32_t DYN_CNTL; struct { __IO uint32_t reg_pll_dynen :1; __IO uint32_t reg_dll_dynen :1; __IO uint32_t reg_pvt_dynen :1; __IO uint32_t reg_bc_dynen :1; __IO uint32_t reg_clkmux_dynen :1; __IO uint32_t reg_lane0_dynen :1; __IO uint32_t reg_lane1_dynen :1; __I uint32_t bc_vrgen_oor :1; __IO uint32_t reg_pll_soft_reset_periph :1; __IO uint32_t reg_dll_soft_reset_periph :1; __IO uint32_t reg_pvt_soft_reset_periph :1; __IO uint32_t reg_bc_soft_reset_periph :1; __IO uint32_t reg_clkmux_soft_reset_periph :1; __IO uint32_t reg_lane0_soft_reset_periph :1; __IO uint32_t reg_lane1_soft_reset_periph :1; __I uint32_t pvt_calib_status :1; __I uint32_t aro_pll0_vco0ph_sel :3; __I uint32_t aro_pll0_vco1ph_sel :3; __I uint32_t aro_pll0_vco2ph_sel :3; __I uint32_t aro_pll0_vco3ph_sel :3; __I uint32_t aro_ref_diffr :4; } bitfield; } CFG_DDR_SGMII_PHY_DYN_CNTL_TypeDef; typedef union{ /*!< PVT_STAT register definition*/ __IO uint32_t PVT_STAT; struct { __I uint32_t aro_ref_pcode :6; __I uint32_t aro_ioen_bnk :1; __I uint32_t aro_ioen_bnk_b :1; __I uint32_t aro_ref_ncode :6; __I uint32_t aro_calib_status :1; __I uint32_t aro_calib_status_b :1; __I uint32_t aro_pcode :6; __I uint32_t aro_calib_intrpt :1; __I uint32_t pvt_calib_intrpt :1; __I uint32_t aro_ncode :6; __IO uint32_t pvt_calib_lock :1; __IO uint32_t pvt_calib_start :1; } bitfield; } CFG_DDR_SGMII_PHY_PVT_STAT_TypeDef; typedef union{ /*!< SPARE_CNTL register definition*/ __IO uint32_t SPARE_CNTL; struct { __IO uint32_t reg_spare :32; } bitfield; } CFG_DDR_SGMII_PHY_SPARE_CNTL_TypeDef; typedef union{ /*!< SPARE_STAT register definition*/ __I uint32_t SPARE_STAT; struct { __I uint32_t sro_spare :32; } bitfield; } CFG_DDR_SGMII_PHY_SPARE_STAT_TypeDef; /*------------ CFG_DDR_SGMII_PHY definition -----------*/ typedef struct { __IO CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_TypeDef SOFT_RESET_DDR_PHY; /*!< Offset: 0x0 */ __IO CFG_DDR_SGMII_PHY_DDRPHY_MODE_TypeDef DDRPHY_MODE; /*!< Offset: 0x4 */ __IO CFG_DDR_SGMII_PHY_DDRPHY_STARTUP_TypeDef DDRPHY_STARTUP; /*!< Offset: 0x8 */ __IO uint32_t UNUSED_SPACE0[29]; /*!< Offset: 0xc */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_TypeDef SOFT_RESET_MAIN_PLL; /*!< Offset: 0x80 */ __IO CFG_DDR_SGMII_PHY_PLL_CTRL_MAIN_TypeDef PLL_CTRL_MAIN; /*!< Offset: 0x84 */ __IO CFG_DDR_SGMII_PHY_PLL_REF_FB_MAIN_TypeDef PLL_REF_FB_MAIN; /*!< Offset: 0x88 */ __I CFG_DDR_SGMII_PHY_PLL_FRACN_MAIN_TypeDef PLL_FRACN_MAIN; /*!< Offset: 0x8c */ __IO CFG_DDR_SGMII_PHY_PLL_DIV_0_1_MAIN_TypeDef PLL_DIV_0_1_MAIN; /*!< Offset: 0x90 */ __IO CFG_DDR_SGMII_PHY_PLL_DIV_2_3_MAIN_TypeDef PLL_DIV_2_3_MAIN; /*!< Offset: 0x94 */ __IO CFG_DDR_SGMII_PHY_PLL_CTRL2_MAIN_TypeDef PLL_CTRL2_MAIN; /*!< Offset: 0x98 */ __I CFG_DDR_SGMII_PHY_PLL_CAL_MAIN_TypeDef PLL_CAL_MAIN; /*!< Offset: 0x9c */ __IO CFG_DDR_SGMII_PHY_PLL_PHADJ_MAIN_TypeDef PLL_PHADJ_MAIN; /*!< Offset: 0xa0 */ __I CFG_DDR_SGMII_PHY_SSCG_REG_0_MAIN_TypeDef SSCG_REG_0_MAIN; /*!< Offset: 0xa4 */ __I CFG_DDR_SGMII_PHY_SSCG_REG_1_MAIN_TypeDef SSCG_REG_1_MAIN; /*!< Offset: 0xa8 */ __IO CFG_DDR_SGMII_PHY_SSCG_REG_2_MAIN_TypeDef SSCG_REG_2_MAIN; /*!< Offset: 0xac */ __I CFG_DDR_SGMII_PHY_SSCG_REG_3_MAIN_TypeDef SSCG_REG_3_MAIN; /*!< Offset: 0xb0 */ __IO CFG_DDR_SGMII_PHY_RPC_RESET_MAIN_PLL_TypeDef RPC_RESET_MAIN_PLL; /*!< Offset: 0xb4 */ __I uint32_t UNUSED_SPACE1[18]; /*!< Offset: 0xb8 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_IOSCB_PLL_TypeDef SOFT_RESET_IOSCB_PLL; /*!< Offset: 0x100 */ __IO CFG_DDR_SGMII_PHY_PLL_CTRL_IOSCB_TypeDef PLL_CTRL_IOSCB; /*!< Offset: 0x104 */ __IO CFG_DDR_SGMII_PHY_PLL_REF_FB_IOSCB_TypeDef PLL_REF_FB_IOSCB; /*!< Offset: 0x108 */ __I CFG_DDR_SGMII_PHY_PLL_FRACN_IOSCB_TypeDef PLL_FRACN_IOSCB; /*!< Offset: 0x10c */ __IO CFG_DDR_SGMII_PHY_PLL_DIV_0_1_IOSCB_TypeDef PLL_DIV_0_1_IOSCB; /*!< Offset: 0x110 */ __IO CFG_DDR_SGMII_PHY_PLL_DIV_2_3_IOSCB_TypeDef PLL_DIV_2_3_IOSCB; /*!< Offset: 0x114 */ __IO CFG_DDR_SGMII_PHY_PLL_CTRL2_IOSCB_TypeDef PLL_CTRL2_IOSCB; /*!< Offset: 0x118 */ __I CFG_DDR_SGMII_PHY_PLL_CAL_IOSCB_TypeDef PLL_CAL_IOSCB; /*!< Offset: 0x11c */ __IO CFG_DDR_SGMII_PHY_PLL_PHADJ_IOSCB_TypeDef PLL_PHADJ_IOSCB; /*!< Offset: 0x120 */ __I CFG_DDR_SGMII_PHY_SSCG_REG_0_IOSCB_TypeDef SSCG_REG_0_IOSCB; /*!< Offset: 0x124 */ __I CFG_DDR_SGMII_PHY_SSCG_REG_1_IOSCB_TypeDef SSCG_REG_1_IOSCB; /*!< Offset: 0x128 */ __IO CFG_DDR_SGMII_PHY_SSCG_REG_2_IOSCB_TypeDef SSCG_REG_2_IOSCB; /*!< Offset: 0x12c */ __I CFG_DDR_SGMII_PHY_SSCG_REG_3_IOSCB_TypeDef SSCG_REG_3_IOSCB; /*!< Offset: 0x130 */ __IO CFG_DDR_SGMII_PHY_RPC_RESET_IOSCB_TypeDef RPC_RESET_IOSCB; /*!< Offset: 0x134 */ __I uint32_t UNUSED_SPACE2[18]; /*!< Offset: 0x138 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_BANK_CTRL_TypeDef SOFT_RESET_BANK_CTRL; /*!< Offset: 0x180 */ __IO CFG_DDR_SGMII_PHY_DPC_BITS_TypeDef DPC_BITS; /*!< Offset: 0x184 */ __I CFG_DDR_SGMII_PHY_BANK_STATUS_TypeDef BANK_STATUS; /*!< Offset: 0x188 */ __IO CFG_DDR_SGMII_PHY_RPC_RESET_BANK_CTRL_TypeDef RPC_RESET_BANK_CTRL; /*!< Offset: 0x18c */ __I uint32_t UNUSED_SPACE3[28]; /*!< Offset: 0x190 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_IOCALIB_TypeDef SOFT_RESET_IOCALIB; /*!< Offset: 0x200 */ __IO CFG_DDR_SGMII_PHY_IOC_REG0_TypeDef IOC_REG0; /*!< Offset: 0x204 */ __I CFG_DDR_SGMII_PHY_IOC_REG1_TypeDef IOC_REG1; /*!< Offset: 0x208 */ __I CFG_DDR_SGMII_PHY_IOC_REG2_TypeDef IOC_REG2; /*!< Offset: 0x20c */ __I CFG_DDR_SGMII_PHY_IOC_REG3_TypeDef IOC_REG3; /*!< Offset: 0x210 */ __I CFG_DDR_SGMII_PHY_IOC_REG4_TypeDef IOC_REG4; /*!< Offset: 0x214 */ __I CFG_DDR_SGMII_PHY_IOC_REG5_TypeDef IOC_REG5; /*!< Offset: 0x218 */ __IO CFG_DDR_SGMII_PHY_IOC_REG6_TypeDef IOC_REG6; /*!< Offset: 0x21c */ __IO CFG_DDR_SGMII_PHY_RPC_RESET_IOCALIB_TypeDef RPC_RESET_IOCALIB; /*!< Offset: 0x220 */ __IO CFG_DDR_SGMII_PHY_rpc_calib_TypeDef rpc_calib; /*!< Offset: 0x224 */ __I uint32_t UNUSED_SPACE4[22]; /*!< Offset: 0x228 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_CFM_TypeDef SOFT_RESET_CFM; /*!< Offset: 0x280 */ __IO CFG_DDR_SGMII_PHY_BCLKMUX_TypeDef BCLKMUX; /*!< Offset: 0x284 */ __IO CFG_DDR_SGMII_PHY_PLL_CKMUX_TypeDef PLL_CKMUX; /*!< Offset: 0x288 */ __IO CFG_DDR_SGMII_PHY_MSSCLKMUX_TypeDef MSSCLKMUX; /*!< Offset: 0x28c */ __IO CFG_DDR_SGMII_PHY_SPARE0_TypeDef SPARE0; /*!< Offset: 0x290 */ __I CFG_DDR_SGMII_PHY_FMETER_ADDR_TypeDef FMETER_ADDR; /*!< Offset: 0x294 */ __I CFG_DDR_SGMII_PHY_FMETER_DATAW_TypeDef FMETER_DATAW; /*!< Offset: 0x298 */ __I CFG_DDR_SGMII_PHY_FMETER_DATAR_TypeDef FMETER_DATAR; /*!< Offset: 0x29c */ __I CFG_DDR_SGMII_PHY_TEST_CTRL_TypeDef TEST_CTRL; /*!< Offset: 0x2a0 */ __IO CFG_DDR_SGMII_PHY_RPC_RESET_CFM_TypeDef RPC_RESET_CFM; /*!< Offset: 0x2a4 */ __I uint32_t UNUSED_SPACE5[22]; /*!< Offset: 0x2a8 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_TypeDef SOFT_RESET_DECODER_DRIVER; /*!< Offset: 0x300 */ __IO CFG_DDR_SGMII_PHY_rpc1_DRV_TypeDef rpc1_DRV; /*!< Offset: 0x304 */ __IO CFG_DDR_SGMII_PHY_rpc2_DRV_TypeDef rpc2_DRV; /*!< Offset: 0x308 */ __IO CFG_DDR_SGMII_PHY_rpc3_DRV_TypeDef rpc3_DRV; /*!< Offset: 0x30c */ __IO CFG_DDR_SGMII_PHY_rpc4_DRV_TypeDef rpc4_DRV; /*!< Offset: 0x310 */ __I uint32_t UNUSED_SPACE6[27]; /*!< Offset: 0x314 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_TypeDef SOFT_RESET_DECODER_ODT; /*!< Offset: 0x380 */ __IO CFG_DDR_SGMII_PHY_rpc1_ODT_TypeDef rpc1_ODT; /*!< Offset: 0x384 */ __IO CFG_DDR_SGMII_PHY_rpc2_ODT_TypeDef rpc2_ODT; /*!< Offset: 0x388 */ __IO CFG_DDR_SGMII_PHY_rpc3_ODT_TypeDef rpc3_ODT; /*!< Offset: 0x38c */ __IO CFG_DDR_SGMII_PHY_rpc4_ODT_TypeDef rpc4_ODT; /*!< Offset: 0x390 */ __IO CFG_DDR_SGMII_PHY_rpc5_ODT_TypeDef rpc5_ODT; /*!< Offset: 0x394 */ __IO CFG_DDR_SGMII_PHY_rpc6_ODT_TypeDef rpc6_ODT; /*!< Offset: 0x398 */ __IO CFG_DDR_SGMII_PHY_rpc7_ODT_TypeDef rpc7_ODT; /*!< Offset: 0x39c */ __IO CFG_DDR_SGMII_PHY_rpc8_ODT_TypeDef rpc8_ODT; /*!< Offset: 0x3a0 */ __IO CFG_DDR_SGMII_PHY_rpc9_ODT_TypeDef rpc9_ODT; /*!< Offset: 0x3a4 */ __IO CFG_DDR_SGMII_PHY_rpc10_ODT_TypeDef rpc10_ODT; /*!< Offset: 0x3a8 */ __IO CFG_DDR_SGMII_PHY_rpc11_ODT_TypeDef rpc11_ODT; /*!< Offset: 0x3ac */ __I uint32_t UNUSED_SPACE7[20]; /*!< Offset: 0x3b0 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_TypeDef SOFT_RESET_DECODER_IO; /*!< Offset: 0x400 */ __IO CFG_DDR_SGMII_PHY_ovrt1_TypeDef ovrt1; /*!< Offset: 0x404 */ __IO CFG_DDR_SGMII_PHY_ovrt2_TypeDef ovrt2; /*!< Offset: 0x408 */ __IO CFG_DDR_SGMII_PHY_ovrt3_TypeDef ovrt3; /*!< Offset: 0x40c */ __IO CFG_DDR_SGMII_PHY_ovrt4_TypeDef ovrt4; /*!< Offset: 0x410 */ __IO CFG_DDR_SGMII_PHY_ovrt5_TypeDef ovrt5; /*!< Offset: 0x414 */ __IO CFG_DDR_SGMII_PHY_ovrt6_TypeDef ovrt6; /*!< Offset: 0x418 */ __IO CFG_DDR_SGMII_PHY_ovrt7_TypeDef ovrt7; /*!< Offset: 0x41c */ __IO CFG_DDR_SGMII_PHY_ovrt8_TypeDef ovrt8; /*!< Offset: 0x420 */ __IO CFG_DDR_SGMII_PHY_ovrt9_TypeDef ovrt9; /*!< Offset: 0x424 */ __IO CFG_DDR_SGMII_PHY_ovrt10_TypeDef ovrt10; /*!< Offset: 0x428 */ __IO CFG_DDR_SGMII_PHY_ovrt11_TypeDef ovrt11; /*!< Offset: 0x42c */ __IO CFG_DDR_SGMII_PHY_ovrt12_TypeDef ovrt12; /*!< Offset: 0x430 */ __IO CFG_DDR_SGMII_PHY_ovrt13_TypeDef ovrt13; /*!< Offset: 0x434 */ __IO CFG_DDR_SGMII_PHY_ovrt14_TypeDef ovrt14; /*!< Offset: 0x438 */ __IO CFG_DDR_SGMII_PHY_ovrt15_TypeDef ovrt15; /*!< Offset: 0x43c */ __IO CFG_DDR_SGMII_PHY_ovrt16_TypeDef ovrt16; /*!< Offset: 0x440 */ __IO CFG_DDR_SGMII_PHY_rpc17_TypeDef rpc17; /*!< Offset: 0x444 */ __IO CFG_DDR_SGMII_PHY_rpc18_TypeDef rpc18; /*!< Offset: 0x448 */ __IO CFG_DDR_SGMII_PHY_rpc19_TypeDef rpc19; /*!< Offset: 0x44c */ __IO CFG_DDR_SGMII_PHY_rpc20_TypeDef rpc20; /*!< Offset: 0x450 */ __IO CFG_DDR_SGMII_PHY_rpc21_TypeDef rpc21; /*!< Offset: 0x454 */ __IO CFG_DDR_SGMII_PHY_rpc22_TypeDef rpc22; /*!< Offset: 0x458 */ __IO CFG_DDR_SGMII_PHY_rpc23_TypeDef rpc23; /*!< Offset: 0x45c */ __IO CFG_DDR_SGMII_PHY_rpc24_TypeDef rpc24; /*!< Offset: 0x460 */ __IO CFG_DDR_SGMII_PHY_rpc25_TypeDef rpc25; /*!< Offset: 0x464 */ __IO CFG_DDR_SGMII_PHY_rpc26_TypeDef rpc26; /*!< Offset: 0x468 */ __IO CFG_DDR_SGMII_PHY_rpc27_TypeDef rpc27; /*!< Offset: 0x46c */ __IO CFG_DDR_SGMII_PHY_rpc28_TypeDef rpc28; /*!< Offset: 0x470 */ __IO CFG_DDR_SGMII_PHY_rpc29_TypeDef rpc29; /*!< Offset: 0x474 */ __IO CFG_DDR_SGMII_PHY_rpc30_TypeDef rpc30; /*!< Offset: 0x478 */ __IO CFG_DDR_SGMII_PHY_rpc31_TypeDef rpc31; /*!< Offset: 0x47c */ __IO CFG_DDR_SGMII_PHY_rpc32_TypeDef rpc32; /*!< Offset: 0x480 */ __IO CFG_DDR_SGMII_PHY_rpc33_TypeDef rpc33; /*!< Offset: 0x484 */ __IO CFG_DDR_SGMII_PHY_rpc34_TypeDef rpc34; /*!< Offset: 0x488 */ __IO CFG_DDR_SGMII_PHY_rpc35_TypeDef rpc35; /*!< Offset: 0x48c */ __IO CFG_DDR_SGMII_PHY_rpc36_TypeDef rpc36; /*!< Offset: 0x490 */ __IO CFG_DDR_SGMII_PHY_rpc37_TypeDef rpc37; /*!< Offset: 0x494 */ __IO CFG_DDR_SGMII_PHY_rpc38_TypeDef rpc38; /*!< Offset: 0x498 */ __IO CFG_DDR_SGMII_PHY_rpc39_TypeDef rpc39; /*!< Offset: 0x49c */ __IO CFG_DDR_SGMII_PHY_rpc40_TypeDef rpc40; /*!< Offset: 0x4a0 */ __IO CFG_DDR_SGMII_PHY_rpc41_TypeDef rpc41; /*!< Offset: 0x4a4 */ __IO CFG_DDR_SGMII_PHY_rpc42_TypeDef rpc42; /*!< Offset: 0x4a8 */ __IO CFG_DDR_SGMII_PHY_rpc43_TypeDef rpc43; /*!< Offset: 0x4ac */ __IO CFG_DDR_SGMII_PHY_rpc44_TypeDef rpc44; /*!< Offset: 0x4b0 */ __IO CFG_DDR_SGMII_PHY_rpc45_TypeDef rpc45; /*!< Offset: 0x4b4 */ __IO CFG_DDR_SGMII_PHY_rpc46_TypeDef rpc46; /*!< Offset: 0x4b8 */ __IO CFG_DDR_SGMII_PHY_rpc47_TypeDef rpc47; /*!< Offset: 0x4bc */ __IO CFG_DDR_SGMII_PHY_rpc48_TypeDef rpc48; /*!< Offset: 0x4c0 */ __IO CFG_DDR_SGMII_PHY_rpc49_TypeDef rpc49; /*!< Offset: 0x4c4 */ __IO CFG_DDR_SGMII_PHY_rpc50_TypeDef rpc50; /*!< Offset: 0x4c8 */ __IO CFG_DDR_SGMII_PHY_rpc51_TypeDef rpc51; /*!< Offset: 0x4cc */ __IO CFG_DDR_SGMII_PHY_rpc52_TypeDef rpc52; /*!< Offset: 0x4d0 */ __IO CFG_DDR_SGMII_PHY_rpc53_TypeDef rpc53; /*!< Offset: 0x4d4 */ __IO CFG_DDR_SGMII_PHY_rpc54_TypeDef rpc54; /*!< Offset: 0x4d8 */ __IO CFG_DDR_SGMII_PHY_rpc55_TypeDef rpc55; /*!< Offset: 0x4dc */ __IO CFG_DDR_SGMII_PHY_rpc56_TypeDef rpc56; /*!< Offset: 0x4e0 */ __IO CFG_DDR_SGMII_PHY_rpc57_TypeDef rpc57; /*!< Offset: 0x4e4 */ __IO CFG_DDR_SGMII_PHY_rpc58_TypeDef rpc58; /*!< Offset: 0x4e8 */ __IO CFG_DDR_SGMII_PHY_rpc59_TypeDef rpc59; /*!< Offset: 0x4ec */ __IO CFG_DDR_SGMII_PHY_rpc60_TypeDef rpc60; /*!< Offset: 0x4f0 */ __IO CFG_DDR_SGMII_PHY_rpc61_TypeDef rpc61; /*!< Offset: 0x4f4 */ __IO CFG_DDR_SGMII_PHY_rpc62_TypeDef rpc62; /*!< Offset: 0x4f8 */ __IO CFG_DDR_SGMII_PHY_rpc63_TypeDef rpc63; /*!< Offset: 0x4fc */ __IO CFG_DDR_SGMII_PHY_rpc64_TypeDef rpc64; /*!< Offset: 0x500 */ __IO CFG_DDR_SGMII_PHY_rpc65_TypeDef rpc65; /*!< Offset: 0x504 */ __IO CFG_DDR_SGMII_PHY_rpc66_TypeDef rpc66; /*!< Offset: 0x508 */ __IO CFG_DDR_SGMII_PHY_rpc67_TypeDef rpc67; /*!< Offset: 0x50c */ __IO CFG_DDR_SGMII_PHY_rpc68_TypeDef rpc68; /*!< Offset: 0x510 */ __IO CFG_DDR_SGMII_PHY_rpc69_TypeDef rpc69; /*!< Offset: 0x514 */ __IO CFG_DDR_SGMII_PHY_rpc70_TypeDef rpc70; /*!< Offset: 0x518 */ __IO CFG_DDR_SGMII_PHY_rpc71_TypeDef rpc71; /*!< Offset: 0x51c */ __IO CFG_DDR_SGMII_PHY_rpc72_TypeDef rpc72; /*!< Offset: 0x520 */ __IO CFG_DDR_SGMII_PHY_rpc73_TypeDef rpc73; /*!< Offset: 0x524 */ __IO CFG_DDR_SGMII_PHY_rpc74_TypeDef rpc74; /*!< Offset: 0x528 */ __IO CFG_DDR_SGMII_PHY_rpc75_TypeDef rpc75; /*!< Offset: 0x52c */ __IO CFG_DDR_SGMII_PHY_rpc76_TypeDef rpc76; /*!< Offset: 0x530 */ __IO CFG_DDR_SGMII_PHY_rpc77_TypeDef rpc77; /*!< Offset: 0x534 */ __IO CFG_DDR_SGMII_PHY_rpc78_TypeDef rpc78; /*!< Offset: 0x538 */ __IO CFG_DDR_SGMII_PHY_rpc79_TypeDef rpc79; /*!< Offset: 0x53c */ __IO CFG_DDR_SGMII_PHY_rpc80_TypeDef rpc80; /*!< Offset: 0x540 */ __IO CFG_DDR_SGMII_PHY_rpc81_TypeDef rpc81; /*!< Offset: 0x544 */ __IO CFG_DDR_SGMII_PHY_rpc82_TypeDef rpc82; /*!< Offset: 0x548 */ __IO CFG_DDR_SGMII_PHY_rpc83_TypeDef rpc83; /*!< Offset: 0x54c */ __IO CFG_DDR_SGMII_PHY_rpc84_TypeDef rpc84; /*!< Offset: 0x550 */ __IO CFG_DDR_SGMII_PHY_rpc85_TypeDef rpc85; /*!< Offset: 0x554 */ __IO CFG_DDR_SGMII_PHY_rpc86_TypeDef rpc86; /*!< Offset: 0x558 */ __IO CFG_DDR_SGMII_PHY_rpc87_TypeDef rpc87; /*!< Offset: 0x55c */ __IO CFG_DDR_SGMII_PHY_rpc88_TypeDef rpc88; /*!< Offset: 0x560 */ __IO CFG_DDR_SGMII_PHY_rpc89_TypeDef rpc89; /*!< Offset: 0x564 */ __IO CFG_DDR_SGMII_PHY_rpc90_TypeDef rpc90; /*!< Offset: 0x568 */ __IO CFG_DDR_SGMII_PHY_rpc91_TypeDef rpc91; /*!< Offset: 0x56c */ __IO CFG_DDR_SGMII_PHY_rpc92_TypeDef rpc92; /*!< Offset: 0x570 */ __IO CFG_DDR_SGMII_PHY_rpc93_TypeDef rpc93; /*!< Offset: 0x574 */ __IO CFG_DDR_SGMII_PHY_rpc94_TypeDef rpc94; /*!< Offset: 0x578 */ __IO CFG_DDR_SGMII_PHY_rpc95_TypeDef rpc95; /*!< Offset: 0x57c */ __IO CFG_DDR_SGMII_PHY_rpc96_TypeDef rpc96; /*!< Offset: 0x580 */ __IO CFG_DDR_SGMII_PHY_rpc97_TypeDef rpc97; /*!< Offset: 0x584 */ __IO CFG_DDR_SGMII_PHY_rpc98_TypeDef rpc98; /*!< Offset: 0x588 */ __IO CFG_DDR_SGMII_PHY_rpc99_TypeDef rpc99; /*!< Offset: 0x58c */ __IO CFG_DDR_SGMII_PHY_rpc100_TypeDef rpc100; /*!< Offset: 0x590 */ __IO CFG_DDR_SGMII_PHY_rpc101_TypeDef rpc101; /*!< Offset: 0x594 */ __IO CFG_DDR_SGMII_PHY_rpc102_TypeDef rpc102; /*!< Offset: 0x598 */ __IO CFG_DDR_SGMII_PHY_rpc103_TypeDef rpc103; /*!< Offset: 0x59c */ __IO CFG_DDR_SGMII_PHY_rpc104_TypeDef rpc104; /*!< Offset: 0x5a0 */ __IO CFG_DDR_SGMII_PHY_rpc105_TypeDef rpc105; /*!< Offset: 0x5a4 */ __IO CFG_DDR_SGMII_PHY_rpc106_TypeDef rpc106; /*!< Offset: 0x5a8 */ __IO CFG_DDR_SGMII_PHY_rpc107_TypeDef rpc107; /*!< Offset: 0x5ac */ __IO CFG_DDR_SGMII_PHY_rpc108_TypeDef rpc108; /*!< Offset: 0x5b0 */ __IO CFG_DDR_SGMII_PHY_rpc109_TypeDef rpc109; /*!< Offset: 0x5b4 */ __IO CFG_DDR_SGMII_PHY_rpc110_TypeDef rpc110; /*!< Offset: 0x5b8 */ __IO CFG_DDR_SGMII_PHY_rpc111_TypeDef rpc111; /*!< Offset: 0x5bc */ __IO CFG_DDR_SGMII_PHY_rpc112_TypeDef rpc112; /*!< Offset: 0x5c0 */ __IO CFG_DDR_SGMII_PHY_rpc113_TypeDef rpc113; /*!< Offset: 0x5c4 */ __IO CFG_DDR_SGMII_PHY_rpc114_TypeDef rpc114; /*!< Offset: 0x5c8 */ __IO CFG_DDR_SGMII_PHY_rpc115_TypeDef rpc115; /*!< Offset: 0x5cc */ __IO CFG_DDR_SGMII_PHY_rpc116_TypeDef rpc116; /*!< Offset: 0x5d0 */ __IO CFG_DDR_SGMII_PHY_rpc117_TypeDef rpc117; /*!< Offset: 0x5d4 */ __IO CFG_DDR_SGMII_PHY_rpc118_TypeDef rpc118; /*!< Offset: 0x5d8 */ __IO CFG_DDR_SGMII_PHY_rpc119_TypeDef rpc119; /*!< Offset: 0x5dc */ __IO CFG_DDR_SGMII_PHY_rpc120_TypeDef rpc120; /*!< Offset: 0x5e0 */ __IO CFG_DDR_SGMII_PHY_rpc121_TypeDef rpc121; /*!< Offset: 0x5e4 */ __IO CFG_DDR_SGMII_PHY_rpc122_TypeDef rpc122; /*!< Offset: 0x5e8 */ __IO CFG_DDR_SGMII_PHY_rpc123_TypeDef rpc123; /*!< Offset: 0x5ec */ __IO CFG_DDR_SGMII_PHY_rpc124_TypeDef rpc124; /*!< Offset: 0x5f0 */ __IO CFG_DDR_SGMII_PHY_rpc125_TypeDef rpc125; /*!< Offset: 0x5f4 */ __IO CFG_DDR_SGMII_PHY_rpc126_TypeDef rpc126; /*!< Offset: 0x5f8 */ __IO CFG_DDR_SGMII_PHY_rpc127_TypeDef rpc127; /*!< Offset: 0x5fc */ __IO CFG_DDR_SGMII_PHY_rpc128_TypeDef rpc128; /*!< Offset: 0x600 */ __IO CFG_DDR_SGMII_PHY_rpc129_TypeDef rpc129; /*!< Offset: 0x604 */ __IO CFG_DDR_SGMII_PHY_rpc130_TypeDef rpc130; /*!< Offset: 0x608 */ __IO CFG_DDR_SGMII_PHY_rpc131_TypeDef rpc131; /*!< Offset: 0x60c */ __IO CFG_DDR_SGMII_PHY_rpc132_TypeDef rpc132; /*!< Offset: 0x610 */ __IO CFG_DDR_SGMII_PHY_rpc133_TypeDef rpc133; /*!< Offset: 0x614 */ __IO CFG_DDR_SGMII_PHY_rpc134_TypeDef rpc134; /*!< Offset: 0x618 */ __IO CFG_DDR_SGMII_PHY_rpc135_TypeDef rpc135; /*!< Offset: 0x61c */ __IO CFG_DDR_SGMII_PHY_rpc136_TypeDef rpc136; /*!< Offset: 0x620 */ __IO CFG_DDR_SGMII_PHY_rpc137_TypeDef rpc137; /*!< Offset: 0x624 */ __IO CFG_DDR_SGMII_PHY_rpc138_TypeDef rpc138; /*!< Offset: 0x628 */ __IO CFG_DDR_SGMII_PHY_rpc139_TypeDef rpc139; /*!< Offset: 0x62c */ __IO CFG_DDR_SGMII_PHY_rpc140_TypeDef rpc140; /*!< Offset: 0x630 */ __IO CFG_DDR_SGMII_PHY_rpc141_TypeDef rpc141; /*!< Offset: 0x634 */ __IO CFG_DDR_SGMII_PHY_rpc142_TypeDef rpc142; /*!< Offset: 0x638 */ __IO CFG_DDR_SGMII_PHY_rpc143_TypeDef rpc143; /*!< Offset: 0x63c */ __IO CFG_DDR_SGMII_PHY_rpc144_TypeDef rpc144; /*!< Offset: 0x640 */ __IO CFG_DDR_SGMII_PHY_rpc145_TypeDef rpc145; /*!< Offset: 0x644 */ __IO CFG_DDR_SGMII_PHY_rpc146_TypeDef rpc146; /*!< Offset: 0x648 */ __IO CFG_DDR_SGMII_PHY_rpc147_TypeDef rpc147; /*!< Offset: 0x64c */ __IO CFG_DDR_SGMII_PHY_rpc148_TypeDef rpc148; /*!< Offset: 0x650 */ __IO CFG_DDR_SGMII_PHY_rpc149_TypeDef rpc149; /*!< Offset: 0x654 */ __IO CFG_DDR_SGMII_PHY_rpc150_TypeDef rpc150; /*!< Offset: 0x658 */ __IO CFG_DDR_SGMII_PHY_rpc151_TypeDef rpc151; /*!< Offset: 0x65c */ __IO CFG_DDR_SGMII_PHY_rpc152_TypeDef rpc152; /*!< Offset: 0x660 */ __IO CFG_DDR_SGMII_PHY_rpc153_TypeDef rpc153; /*!< Offset: 0x664 */ __IO CFG_DDR_SGMII_PHY_rpc154_TypeDef rpc154; /*!< Offset: 0x668 */ __IO CFG_DDR_SGMII_PHY_rpc155_TypeDef rpc155; /*!< Offset: 0x66c */ __IO CFG_DDR_SGMII_PHY_rpc156_TypeDef rpc156; /*!< Offset: 0x670 */ __IO CFG_DDR_SGMII_PHY_rpc157_TypeDef rpc157; /*!< Offset: 0x674 */ __IO CFG_DDR_SGMII_PHY_rpc158_TypeDef rpc158; /*!< Offset: 0x678 */ __IO CFG_DDR_SGMII_PHY_rpc159_TypeDef rpc159; /*!< Offset: 0x67c */ __IO CFG_DDR_SGMII_PHY_rpc160_TypeDef rpc160; /*!< Offset: 0x680 */ __IO CFG_DDR_SGMII_PHY_rpc161_TypeDef rpc161; /*!< Offset: 0x684 */ __IO CFG_DDR_SGMII_PHY_rpc162_TypeDef rpc162; /*!< Offset: 0x688 */ __IO CFG_DDR_SGMII_PHY_rpc163_TypeDef rpc163; /*!< Offset: 0x68c */ __IO CFG_DDR_SGMII_PHY_rpc164_TypeDef rpc164; /*!< Offset: 0x690 */ __IO CFG_DDR_SGMII_PHY_rpc165_TypeDef rpc165; /*!< Offset: 0x694 */ __IO CFG_DDR_SGMII_PHY_rpc166_TypeDef rpc166; /*!< Offset: 0x698 */ __IO CFG_DDR_SGMII_PHY_rpc167_TypeDef rpc167; /*!< Offset: 0x69c */ __IO CFG_DDR_SGMII_PHY_rpc168_TypeDef rpc168; /*!< Offset: 0x6a0 */ __IO CFG_DDR_SGMII_PHY_rpc169_TypeDef rpc169; /*!< Offset: 0x6a4 */ __IO CFG_DDR_SGMII_PHY_rpc170_TypeDef rpc170; /*!< Offset: 0x6a8 */ __IO CFG_DDR_SGMII_PHY_rpc171_TypeDef rpc171; /*!< Offset: 0x6ac */ __IO CFG_DDR_SGMII_PHY_rpc172_TypeDef rpc172; /*!< Offset: 0x6b0 */ __IO CFG_DDR_SGMII_PHY_rpc173_TypeDef rpc173; /*!< Offset: 0x6b4 */ __IO CFG_DDR_SGMII_PHY_rpc174_TypeDef rpc174; /*!< Offset: 0x6b8 */ __IO CFG_DDR_SGMII_PHY_rpc175_TypeDef rpc175; /*!< Offset: 0x6bc */ __IO CFG_DDR_SGMII_PHY_rpc176_TypeDef rpc176; /*!< Offset: 0x6c0 */ __IO CFG_DDR_SGMII_PHY_rpc177_TypeDef rpc177; /*!< Offset: 0x6c4 */ __IO CFG_DDR_SGMII_PHY_rpc178_TypeDef rpc178; /*!< Offset: 0x6c8 */ __IO CFG_DDR_SGMII_PHY_rpc179_TypeDef rpc179; /*!< Offset: 0x6cc */ __IO CFG_DDR_SGMII_PHY_rpc180_TypeDef rpc180; /*!< Offset: 0x6d0 */ __IO CFG_DDR_SGMII_PHY_rpc181_TypeDef rpc181; /*!< Offset: 0x6d4 */ __IO CFG_DDR_SGMII_PHY_rpc182_TypeDef rpc182; /*!< Offset: 0x6d8 */ __IO CFG_DDR_SGMII_PHY_rpc183_TypeDef rpc183; /*!< Offset: 0x6dc */ __IO CFG_DDR_SGMII_PHY_rpc184_TypeDef rpc184; /*!< Offset: 0x6e0 */ __IO CFG_DDR_SGMII_PHY_rpc185_TypeDef rpc185; /*!< Offset: 0x6e4 */ __IO CFG_DDR_SGMII_PHY_rpc186_TypeDef rpc186; /*!< Offset: 0x6e8 */ __IO CFG_DDR_SGMII_PHY_rpc187_TypeDef rpc187; /*!< Offset: 0x6ec */ __IO CFG_DDR_SGMII_PHY_rpc188_TypeDef rpc188; /*!< Offset: 0x6f0 */ __IO CFG_DDR_SGMII_PHY_rpc189_TypeDef rpc189; /*!< Offset: 0x6f4 */ __IO CFG_DDR_SGMII_PHY_rpc190_TypeDef rpc190; /*!< Offset: 0x6f8 */ __IO CFG_DDR_SGMII_PHY_rpc191_TypeDef rpc191; /*!< Offset: 0x6fc */ __IO CFG_DDR_SGMII_PHY_rpc192_TypeDef rpc192; /*!< Offset: 0x700 */ __IO CFG_DDR_SGMII_PHY_rpc193_TypeDef rpc193; /*!< Offset: 0x704 */ __IO CFG_DDR_SGMII_PHY_rpc194_TypeDef rpc194; /*!< Offset: 0x708 */ __IO CFG_DDR_SGMII_PHY_rpc195_TypeDef rpc195; /*!< Offset: 0x70c */ __IO CFG_DDR_SGMII_PHY_rpc196_TypeDef rpc196; /*!< Offset: 0x710 */ __IO CFG_DDR_SGMII_PHY_rpc197_TypeDef rpc197; /*!< Offset: 0x714 */ __IO CFG_DDR_SGMII_PHY_rpc198_TypeDef rpc198; /*!< Offset: 0x718 */ __IO CFG_DDR_SGMII_PHY_rpc199_TypeDef rpc199; /*!< Offset: 0x71c */ __IO CFG_DDR_SGMII_PHY_rpc200_TypeDef rpc200; /*!< Offset: 0x720 */ __IO CFG_DDR_SGMII_PHY_rpc201_TypeDef rpc201; /*!< Offset: 0x724 */ __IO CFG_DDR_SGMII_PHY_rpc202_TypeDef rpc202; /*!< Offset: 0x728 */ __IO CFG_DDR_SGMII_PHY_rpc203_TypeDef rpc203; /*!< Offset: 0x72c */ __IO CFG_DDR_SGMII_PHY_rpc204_TypeDef rpc204; /*!< Offset: 0x730 */ __IO CFG_DDR_SGMII_PHY_rpc205_TypeDef rpc205; /*!< Offset: 0x734 */ __IO CFG_DDR_SGMII_PHY_rpc206_TypeDef rpc206; /*!< Offset: 0x738 */ __IO CFG_DDR_SGMII_PHY_rpc207_TypeDef rpc207; /*!< Offset: 0x73c */ __IO CFG_DDR_SGMII_PHY_rpc208_TypeDef rpc208; /*!< Offset: 0x740 */ __IO CFG_DDR_SGMII_PHY_rpc209_TypeDef rpc209; /*!< Offset: 0x744 */ __IO CFG_DDR_SGMII_PHY_rpc210_TypeDef rpc210; /*!< Offset: 0x748 */ __IO CFG_DDR_SGMII_PHY_rpc211_TypeDef rpc211; /*!< Offset: 0x74c */ __IO CFG_DDR_SGMII_PHY_rpc212_TypeDef rpc212; /*!< Offset: 0x750 */ __IO CFG_DDR_SGMII_PHY_rpc213_TypeDef rpc213; /*!< Offset: 0x754 */ __IO CFG_DDR_SGMII_PHY_rpc214_TypeDef rpc214; /*!< Offset: 0x758 */ __IO CFG_DDR_SGMII_PHY_rpc215_TypeDef rpc215; /*!< Offset: 0x75c */ __IO CFG_DDR_SGMII_PHY_rpc216_TypeDef rpc216; /*!< Offset: 0x760 */ __IO CFG_DDR_SGMII_PHY_rpc217_TypeDef rpc217; /*!< Offset: 0x764 */ __IO CFG_DDR_SGMII_PHY_rpc218_TypeDef rpc218; /*!< Offset: 0x768 */ __IO CFG_DDR_SGMII_PHY_rpc219_TypeDef rpc219; /*!< Offset: 0x76c */ __IO CFG_DDR_SGMII_PHY_rpc220_TypeDef rpc220; /*!< Offset: 0x770 */ __IO CFG_DDR_SGMII_PHY_rpc221_TypeDef rpc221; /*!< Offset: 0x774 */ __IO CFG_DDR_SGMII_PHY_rpc222_TypeDef rpc222; /*!< Offset: 0x778 */ __IO CFG_DDR_SGMII_PHY_rpc223_TypeDef rpc223; /*!< Offset: 0x77c */ __IO CFG_DDR_SGMII_PHY_rpc224_TypeDef rpc224; /*!< Offset: 0x780 */ __IO CFG_DDR_SGMII_PHY_rpc225_TypeDef rpc225; /*!< Offset: 0x784 */ __IO CFG_DDR_SGMII_PHY_rpc226_TypeDef rpc226; /*!< Offset: 0x788 */ __IO CFG_DDR_SGMII_PHY_rpc227_TypeDef rpc227; /*!< Offset: 0x78c */ __IO CFG_DDR_SGMII_PHY_rpc228_TypeDef rpc228; /*!< Offset: 0x790 */ __IO CFG_DDR_SGMII_PHY_rpc229_TypeDef rpc229; /*!< Offset: 0x794 */ __IO CFG_DDR_SGMII_PHY_rpc230_TypeDef rpc230; /*!< Offset: 0x798 */ __IO CFG_DDR_SGMII_PHY_rpc231_TypeDef rpc231; /*!< Offset: 0x79c */ __IO CFG_DDR_SGMII_PHY_rpc232_TypeDef rpc232; /*!< Offset: 0x7a0 */ __IO CFG_DDR_SGMII_PHY_rpc233_TypeDef rpc233; /*!< Offset: 0x7a4 */ __IO CFG_DDR_SGMII_PHY_rpc234_TypeDef rpc234; /*!< Offset: 0x7a8 */ __IO CFG_DDR_SGMII_PHY_rpc235_TypeDef rpc235; /*!< Offset: 0x7ac */ __IO CFG_DDR_SGMII_PHY_rpc236_TypeDef rpc236; /*!< Offset: 0x7b0 */ __IO CFG_DDR_SGMII_PHY_rpc237_TypeDef rpc237; /*!< Offset: 0x7b4 */ __IO CFG_DDR_SGMII_PHY_rpc238_TypeDef rpc238; /*!< Offset: 0x7b8 */ __IO CFG_DDR_SGMII_PHY_rpc239_TypeDef rpc239; /*!< Offset: 0x7bc */ __IO CFG_DDR_SGMII_PHY_rpc240_TypeDef rpc240; /*!< Offset: 0x7c0 */ __IO CFG_DDR_SGMII_PHY_rpc241_TypeDef rpc241; /*!< Offset: 0x7c4 */ __IO CFG_DDR_SGMII_PHY_rpc242_TypeDef rpc242; /*!< Offset: 0x7c8 */ __IO CFG_DDR_SGMII_PHY_rpc243_TypeDef rpc243; /*!< Offset: 0x7cc */ __IO CFG_DDR_SGMII_PHY_rpc244_TypeDef rpc244; /*!< Offset: 0x7d0 */ __IO CFG_DDR_SGMII_PHY_rpc245_TypeDef rpc245; /*!< Offset: 0x7d4 */ __IO CFG_DDR_SGMII_PHY_rpc246_TypeDef rpc246; /*!< Offset: 0x7d8 */ __IO CFG_DDR_SGMII_PHY_rpc247_TypeDef rpc247; /*!< Offset: 0x7dc */ __IO CFG_DDR_SGMII_PHY_rpc248_TypeDef rpc248; /*!< Offset: 0x7e0 */ __IO CFG_DDR_SGMII_PHY_rpc249_TypeDef rpc249; /*!< Offset: 0x7e4 */ __IO CFG_DDR_SGMII_PHY_rpc250_TypeDef rpc250; /*!< Offset: 0x7e8 */ __IO CFG_DDR_SGMII_PHY_spio251_TypeDef spio251; /*!< Offset: 0x7ec */ __IO CFG_DDR_SGMII_PHY_spio252_TypeDef spio252; /*!< Offset: 0x7f0 */ __IO CFG_DDR_SGMII_PHY_spio253_TypeDef spio253; /*!< Offset: 0x7f4 */ __I uint32_t UNUSED_SPACE8[2]; /*!< Offset: 0x7f8 */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_TIP_TypeDef SOFT_RESET_TIP; /*!< Offset: 0x800 */ __IO CFG_DDR_SGMII_PHY_rank_select_TypeDef rank_select; /*!< Offset: 0x804 */ __IO CFG_DDR_SGMII_PHY_lane_select_TypeDef lane_select; /*!< Offset: 0x808 */ __IO CFG_DDR_SGMII_PHY_training_skip_TypeDef training_skip; /*!< Offset: 0x80c */ __IO CFG_DDR_SGMII_PHY_training_start_TypeDef training_start; /*!< Offset: 0x810 */ __I CFG_DDR_SGMII_PHY_training_status_TypeDef training_status; /*!< Offset: 0x814 */ __IO CFG_DDR_SGMII_PHY_training_reset_TypeDef training_reset; /*!< Offset: 0x818 */ __I CFG_DDR_SGMII_PHY_gt_err_comb_TypeDef gt_err_comb; /*!< Offset: 0x81c */ __I CFG_DDR_SGMII_PHY_gt_clk_sel_TypeDef gt_clk_sel; /*!< Offset: 0x820 */ __I CFG_DDR_SGMII_PHY_gt_txdly_TypeDef gt_txdly; /*!< Offset: 0x824 */ __I CFG_DDR_SGMII_PHY_gt_steps_180_TypeDef gt_steps_180; /*!< Offset: 0x828 */ __I CFG_DDR_SGMII_PHY_gt_state_TypeDef gt_state; /*!< Offset: 0x82c */ __I CFG_DDR_SGMII_PHY_wl_delay_0_TypeDef wl_delay_0; /*!< Offset: 0x830 */ __I CFG_DDR_SGMII_PHY_dq_dqs_err_done_TypeDef dq_dqs_err_done; /*!< Offset: 0x834 */ __I CFG_DDR_SGMII_PHY_dqdqs_window_TypeDef dqdqs_window; /*!< Offset: 0x838 */ __I CFG_DDR_SGMII_PHY_dqdqs_state_TypeDef dqdqs_state; /*!< Offset: 0x83c */ __I CFG_DDR_SGMII_PHY_delta0_TypeDef delta0; /*!< Offset: 0x840 */ __I CFG_DDR_SGMII_PHY_delta1_TypeDef delta1; /*!< Offset: 0x844 */ __I CFG_DDR_SGMII_PHY_dqdqs_status0_TypeDef dqdqs_status0; /*!< Offset: 0x848 */ __I CFG_DDR_SGMII_PHY_dqdqs_status1_TypeDef dqdqs_status1; /*!< Offset: 0x84c */ __I CFG_DDR_SGMII_PHY_dqdqs_status2_TypeDef dqdqs_status2; /*!< Offset: 0x850 */ __I CFG_DDR_SGMII_PHY_dqdqs_status3_TypeDef dqdqs_status3; /*!< Offset: 0x854 */ __I CFG_DDR_SGMII_PHY_dqdqs_status4_TypeDef dqdqs_status4; /*!< Offset: 0x858 */ __I CFG_DDR_SGMII_PHY_dqdqs_status5_TypeDef dqdqs_status5; /*!< Offset: 0x85c */ __I CFG_DDR_SGMII_PHY_dqdqs_status6_TypeDef dqdqs_status6; /*!< Offset: 0x860 */ __I CFG_DDR_SGMII_PHY_addcmd_status0_TypeDef addcmd_status0; /*!< Offset: 0x864 */ __I CFG_DDR_SGMII_PHY_addcmd_status1_TypeDef addcmd_status1; /*!< Offset: 0x868 */ __I CFG_DDR_SGMII_PHY_addcmd_answer_TypeDef addcmd_answer; /*!< Offset: 0x86c */ __I CFG_DDR_SGMII_PHY_bclksclk_answer_TypeDef bclksclk_answer; /*!< Offset: 0x870 */ __I CFG_DDR_SGMII_PHY_dqdqs_wrcalib_offset_TypeDef dqdqs_wrcalib_offset; /*!< Offset: 0x874 */ __IO CFG_DDR_SGMII_PHY_expert_mode_en_TypeDef expert_mode_en; /*!< Offset: 0x878 */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_move_reg0_TypeDef expert_dlycnt_move_reg0; /*!< Offset: 0x87c */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_move_reg1_TypeDef expert_dlycnt_move_reg1; /*!< Offset: 0x880 */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_direction_reg0_TypeDef expert_dlycnt_direction_reg0; /*!< Offset: 0x884 */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_direction_reg1_TypeDef expert_dlycnt_direction_reg1; /*!< Offset: 0x888 */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_load_reg0_TypeDef expert_dlycnt_load_reg0; /*!< Offset: 0x88c */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_load_reg1_TypeDef expert_dlycnt_load_reg1; /*!< Offset: 0x890 */ __I CFG_DDR_SGMII_PHY_expert_dlycnt_oor_reg0_TypeDef expert_dlycnt_oor_reg0; /*!< Offset: 0x894 */ __I CFG_DDR_SGMII_PHY_expert_dlycnt_oor_reg1_TypeDef expert_dlycnt_oor_reg1; /*!< Offset: 0x898 */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_mv_rd_dly_reg_TypeDef expert_dlycnt_mv_rd_dly_reg; /*!< Offset: 0x89c */ __IO CFG_DDR_SGMII_PHY_expert_dlycnt_pause_TypeDef expert_dlycnt_pause; /*!< Offset: 0x8a0 */ __IO CFG_DDR_SGMII_PHY_expert_pllcnt_TypeDef expert_pllcnt; /*!< Offset: 0x8a4 */ __I CFG_DDR_SGMII_PHY_expert_dqlane_readback_TypeDef expert_dqlane_readback; /*!< Offset: 0x8a8 */ __I CFG_DDR_SGMII_PHY_expert_addcmd_ln_readback_TypeDef expert_addcmd_ln_readback; /*!< Offset: 0x8ac */ __IO CFG_DDR_SGMII_PHY_expert_read_gate_controls_TypeDef expert_read_gate_controls; /*!< Offset: 0x8b0 */ __I CFG_DDR_SGMII_PHY_expert_dq_dqs_optimization0_TypeDef expert_dq_dqs_optimization0; /*!< Offset: 0x8b4 */ __I CFG_DDR_SGMII_PHY_expert_dq_dqs_optimization1_TypeDef expert_dq_dqs_optimization1; /*!< Offset: 0x8b8 */ __IO CFG_DDR_SGMII_PHY_expert_wrcalib_TypeDef expert_wrcalib; /*!< Offset: 0x8bc */ __IO CFG_DDR_SGMII_PHY_expert_calif_TypeDef expert_calif; /*!< Offset: 0x8c0 */ __I CFG_DDR_SGMII_PHY_expert_calif_readback_TypeDef expert_calif_readback; /*!< Offset: 0x8c4 */ __I CFG_DDR_SGMII_PHY_expert_calif_readback1_TypeDef expert_calif_readback1; /*!< Offset: 0x8c8 */ __IO CFG_DDR_SGMII_PHY_expert_dfi_status_override_to_shim_TypeDef expert_dfi_status_override_to_shim; /*!< Offset: 0x8cc */ __IO CFG_DDR_SGMII_PHY_tip_cfg_params_TypeDef tip_cfg_params; /*!< Offset: 0x8d0 */ __IO CFG_DDR_SGMII_PHY_tip_vref_param_TypeDef tip_vref_param; /*!< Offset: 0x8d4 */ __IO CFG_DDR_SGMII_PHY_lane_alignment_fifo_control_TypeDef lane_alignment_fifo_control; /*!< Offset: 0x8d8 */ __I uint32_t UNUSED_SPACE9[201]; /*!< Offset: 0x8dc */ __IO CFG_DDR_SGMII_PHY_SOFT_RESET_SGMII_TypeDef SOFT_RESET_SGMII; /*!< Offset: 0xc00 */ __IO CFG_DDR_SGMII_PHY_SGMII_MODE_TypeDef SGMII_MODE; /*!< Offset: 0xc04 */ __IO CFG_DDR_SGMII_PHY_PLL_CNTL_TypeDef PLL_CNTL; /*!< Offset: 0xc08 */ __IO CFG_DDR_SGMII_PHY_CH0_CNTL_TypeDef CH0_CNTL; /*!< Offset: 0xc0c */ __IO CFG_DDR_SGMII_PHY_CH1_CNTL_TypeDef CH1_CNTL; /*!< Offset: 0xc10 */ __IO CFG_DDR_SGMII_PHY_RECAL_CNTL_TypeDef RECAL_CNTL; /*!< Offset: 0xc14 */ __IO CFG_DDR_SGMII_PHY_CLK_CNTL_TypeDef CLK_CNTL; /*!< Offset: 0xc18 */ __IO CFG_DDR_SGMII_PHY_DYN_CNTL_TypeDef DYN_CNTL; /*!< Offset: 0xc1c */ __IO CFG_DDR_SGMII_PHY_PVT_STAT_TypeDef PVT_STAT; /*!< Offset: 0xc20 */ __IO CFG_DDR_SGMII_PHY_SPARE_CNTL_TypeDef SPARE_CNTL; /*!< Offset: 0xc24 */ __I CFG_DDR_SGMII_PHY_SPARE_STAT_TypeDef SPARE_STAT; /*!< Offset: 0xc28 */ } CFG_DDR_SGMII_PHY_TypeDef; /******************************************************************************/ /* finish of CFG_DDR_SGMII_PHY definitions */ /******************************************************************************/ #ifdef __cplusplus } #endif #endif /* MSS_DDR_SGMII_PHY_DEFS_H_ */ mss_ddr_sgmii_regs.h000066400000000000000000010504251432224323300406660ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_hal.h * @author Microchip-FPGA Embedded Systems Solutions * @brief Register bit offsets and masks definitions for MPFS MSS DDR * This was generated directly from the RTL * */ #ifndef MSS_DDR_REGS_H_ #define MSS_DDR_REGS_H_ #include "../mss_sysreg.h" #include "mss_ddr_sgmii_phy_defs.h" #ifdef __cplusplus extern "C" { #endif /*----------------------------------------------------------------------------*/ /*----------------------------------- DDR -----------------------------------*/ /*----------------------------------------------------------------------------*/ /*============================== CFG_DDR_SGMII_PHY definitions ===========================*/ /* see mss_ddr_sgmii_phy_defs.h */ /******************************************************************************/ /* finish of CFG_DDR_SGMII_PHY definitions */ /******************************************************************************/ /*============================== DDR_CSR_APB definitions ===========================*/ typedef union{ /*!< CFG_MANUAL_ADDRESS_MAP register definition*/ __IO uint32_t CFG_MANUAL_ADDRESS_MAP; struct { __IO uint32_t cfg_manual_address_map :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_MANUAL_ADDRESS_MAP_TypeDef; typedef union{ /*!< CFG_CHIPADDR_MAP register definition*/ __IO uint32_t CFG_CHIPADDR_MAP; struct { __IO uint32_t cfg_chipaddr_map :24; __I uint32_t reserved :8; } bitfield; } DDR_CSR_APB_CFG_CHIPADDR_MAP_TypeDef; typedef union{ /*!< CFG_CIDADDR_MAP register definition*/ __IO uint32_t CFG_CIDADDR_MAP; struct { __IO uint32_t cfg_cidaddr_map :18; __I uint32_t reserved :14; } bitfield; } DDR_CSR_APB_CFG_CIDADDR_MAP_TypeDef; typedef union{ /*!< CFG_MB_AUTOPCH_COL_BIT_POS_LOW register definition*/ __IO uint32_t CFG_MB_AUTOPCH_COL_BIT_POS_LOW; struct { __IO uint32_t cfg_mb_autopch_col_bit_pos_low :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_MB_AUTOPCH_COL_BIT_POS_LOW_TypeDef; typedef union{ /*!< CFG_MB_AUTOPCH_COL_BIT_POS_HIGH register definition*/ __IO uint32_t CFG_MB_AUTOPCH_COL_BIT_POS_HIGH; struct { __IO uint32_t cfg_mb_autopch_col_bit_pos_high :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_MB_AUTOPCH_COL_BIT_POS_HIGH_TypeDef; typedef union{ /*!< CFG_BANKADDR_MAP_0 register definition*/ __IO uint32_t CFG_BANKADDR_MAP_0; struct { __IO uint32_t cfg_bankaddr_map_0 :32; } bitfield; } DDR_CSR_APB_CFG_BANKADDR_MAP_0_TypeDef; typedef union{ /*!< CFG_BANKADDR_MAP_1 register definition*/ __IO uint32_t CFG_BANKADDR_MAP_1; struct { __IO uint32_t cfg_bankaddr_map_1 :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_BANKADDR_MAP_1_TypeDef; typedef union{ /*!< CFG_ROWADDR_MAP_0 register definition*/ __IO uint32_t CFG_ROWADDR_MAP_0; struct { __IO uint32_t cfg_rowaddr_map_0 :32; } bitfield; } DDR_CSR_APB_CFG_ROWADDR_MAP_0_TypeDef; typedef union{ /*!< CFG_ROWADDR_MAP_1 register definition*/ __IO uint32_t CFG_ROWADDR_MAP_1; struct { __IO uint32_t cfg_rowaddr_map_1 :32; } bitfield; } DDR_CSR_APB_CFG_ROWADDR_MAP_1_TypeDef; typedef union{ /*!< CFG_ROWADDR_MAP_2 register definition*/ __IO uint32_t CFG_ROWADDR_MAP_2; struct { __IO uint32_t cfg_rowaddr_map_2 :32; } bitfield; } DDR_CSR_APB_CFG_ROWADDR_MAP_2_TypeDef; typedef union{ /*!< CFG_ROWADDR_MAP_3 register definition*/ __IO uint32_t CFG_ROWADDR_MAP_3; struct { __IO uint32_t cfg_rowaddr_map_3 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_ROWADDR_MAP_3_TypeDef; typedef union{ /*!< CFG_COLADDR_MAP_0 register definition*/ __IO uint32_t CFG_COLADDR_MAP_0; struct { __IO uint32_t cfg_coladdr_map_0 :32; } bitfield; } DDR_CSR_APB_CFG_COLADDR_MAP_0_TypeDef; typedef union{ /*!< CFG_COLADDR_MAP_1 register definition*/ __IO uint32_t CFG_COLADDR_MAP_1; struct { __IO uint32_t cfg_coladdr_map_1 :32; } bitfield; } DDR_CSR_APB_CFG_COLADDR_MAP_1_TypeDef; typedef union{ /*!< CFG_COLADDR_MAP_2 register definition*/ __IO uint32_t CFG_COLADDR_MAP_2; struct { __IO uint32_t cfg_coladdr_map_2 :32; } bitfield; } DDR_CSR_APB_CFG_COLADDR_MAP_2_TypeDef; typedef union{ /*!< CFG_VRCG_ENABLE register definition*/ __IO uint32_t CFG_VRCG_ENABLE; struct { __IO uint32_t cfg_vrcg_enable :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_VRCG_ENABLE_TypeDef; typedef union{ /*!< CFG_VRCG_DISABLE register definition*/ __IO uint32_t CFG_VRCG_DISABLE; struct { __IO uint32_t cfg_vrcg_disable :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_VRCG_DISABLE_TypeDef; typedef union{ /*!< CFG_WRITE_LATENCY_SET register definition*/ __IO uint32_t CFG_WRITE_LATENCY_SET; struct { __IO uint32_t cfg_write_latency_set :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_WRITE_LATENCY_SET_TypeDef; typedef union{ /*!< CFG_THERMAL_OFFSET register definition*/ __IO uint32_t CFG_THERMAL_OFFSET; struct { __IO uint32_t cfg_thermal_offset :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_THERMAL_OFFSET_TypeDef; typedef union{ /*!< CFG_SOC_ODT register definition*/ __IO uint32_t CFG_SOC_ODT; struct { __IO uint32_t cfg_soc_odt :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_SOC_ODT_TypeDef; typedef union{ /*!< CFG_ODTE_CK register definition*/ __IO uint32_t CFG_ODTE_CK; struct { __IO uint32_t cfg_odte_ck :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ODTE_CK_TypeDef; typedef union{ /*!< CFG_ODTE_CS register definition*/ __IO uint32_t CFG_ODTE_CS; struct { __IO uint32_t cfg_odte_cs :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ODTE_CS_TypeDef; typedef union{ /*!< CFG_ODTD_CA register definition*/ __IO uint32_t CFG_ODTD_CA; struct { __IO uint32_t cfg_odtd_ca :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ODTD_CA_TypeDef; typedef union{ /*!< CFG_LPDDR4_FSP_OP register definition*/ __IO uint32_t CFG_LPDDR4_FSP_OP; struct { __IO uint32_t cfg_lpddr4_fsp_op :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_LPDDR4_FSP_OP_TypeDef; typedef union{ /*!< CFG_GENERATE_REFRESH_ON_SRX register definition*/ __IO uint32_t CFG_GENERATE_REFRESH_ON_SRX; struct { __IO uint32_t cfg_generate_refresh_on_srx :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_GENERATE_REFRESH_ON_SRX_TypeDef; typedef union{ /*!< CFG_DBI_CL register definition*/ __IO uint32_t CFG_DBI_CL; struct { __IO uint32_t cfg_dbi_cl :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_DBI_CL_TypeDef; typedef union{ /*!< CFG_NON_DBI_CL register definition*/ __IO uint32_t CFG_NON_DBI_CL; struct { __IO uint32_t cfg_non_dbi_cl :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_NON_DBI_CL_TypeDef; typedef union{ /*!< INIT_FORCE_WRITE_DATA_0 register definition*/ __IO uint32_t INIT_FORCE_WRITE_DATA_0; struct { __IO uint32_t init_force_write_data_0 :9; __I uint32_t reserved :23; } bitfield; } DDR_CSR_APB_INIT_FORCE_WRITE_DATA_0_TypeDef; typedef union{ /*!< CFG_WRITE_CRC register definition*/ __IO uint32_t CFG_WRITE_CRC; struct { __IO uint32_t cfg_write_crc :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_WRITE_CRC_TypeDef; typedef union{ /*!< CFG_MPR_READ_FORMAT register definition*/ __IO uint32_t CFG_MPR_READ_FORMAT; struct { __IO uint32_t cfg_mpr_read_format :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_MPR_READ_FORMAT_TypeDef; typedef union{ /*!< CFG_WR_CMD_LAT_CRC_DM register definition*/ __IO uint32_t CFG_WR_CMD_LAT_CRC_DM; struct { __IO uint32_t cfg_wr_cmd_lat_crc_dm :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_WR_CMD_LAT_CRC_DM_TypeDef; typedef union{ /*!< CFG_FINE_GRAN_REF_MODE register definition*/ __IO uint32_t CFG_FINE_GRAN_REF_MODE; struct { __IO uint32_t cfg_fine_gran_ref_mode :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_FINE_GRAN_REF_MODE_TypeDef; typedef union{ /*!< CFG_TEMP_SENSOR_READOUT register definition*/ __IO uint32_t CFG_TEMP_SENSOR_READOUT; struct { __IO uint32_t cfg_temp_sensor_readout :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TEMP_SENSOR_READOUT_TypeDef; typedef union{ /*!< CFG_PER_DRAM_ADDR_EN register definition*/ __IO uint32_t CFG_PER_DRAM_ADDR_EN; struct { __IO uint32_t cfg_per_dram_addr_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_PER_DRAM_ADDR_EN_TypeDef; typedef union{ /*!< CFG_GEARDOWN_MODE register definition*/ __IO uint32_t CFG_GEARDOWN_MODE; struct { __IO uint32_t cfg_geardown_mode :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_GEARDOWN_MODE_TypeDef; typedef union{ /*!< CFG_WR_PREAMBLE register definition*/ __IO uint32_t CFG_WR_PREAMBLE; struct { __IO uint32_t cfg_wr_preamble :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_WR_PREAMBLE_TypeDef; typedef union{ /*!< CFG_RD_PREAMBLE register definition*/ __IO uint32_t CFG_RD_PREAMBLE; struct { __IO uint32_t cfg_rd_preamble :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RD_PREAMBLE_TypeDef; typedef union{ /*!< CFG_RD_PREAMB_TRN_MODE register definition*/ __IO uint32_t CFG_RD_PREAMB_TRN_MODE; struct { __IO uint32_t cfg_rd_preamb_trn_mode :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RD_PREAMB_TRN_MODE_TypeDef; typedef union{ /*!< CFG_SR_ABORT register definition*/ __IO uint32_t CFG_SR_ABORT; struct { __IO uint32_t cfg_sr_abort :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_SR_ABORT_TypeDef; typedef union{ /*!< CFG_CS_TO_CMDADDR_LATENCY register definition*/ __IO uint32_t CFG_CS_TO_CMDADDR_LATENCY; struct { __IO uint32_t cfg_cs_to_cmdaddr_latency :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_CS_TO_CMDADDR_LATENCY_TypeDef; typedef union{ /*!< CFG_INT_VREF_MON register definition*/ __IO uint32_t CFG_INT_VREF_MON; struct { __IO uint32_t cfg_int_vref_mon :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_INT_VREF_MON_TypeDef; typedef union{ /*!< CFG_TEMP_CTRL_REF_MODE register definition*/ __IO uint32_t CFG_TEMP_CTRL_REF_MODE; struct { __IO uint32_t cfg_temp_ctrl_ref_mode :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TEMP_CTRL_REF_MODE_TypeDef; typedef union{ /*!< CFG_TEMP_CTRL_REF_RANGE register definition*/ __IO uint32_t CFG_TEMP_CTRL_REF_RANGE; struct { __IO uint32_t cfg_temp_ctrl_ref_range :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TEMP_CTRL_REF_RANGE_TypeDef; typedef union{ /*!< CFG_MAX_PWR_DOWN_MODE register definition*/ __IO uint32_t CFG_MAX_PWR_DOWN_MODE; struct { __IO uint32_t cfg_max_pwr_down_mode :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_MAX_PWR_DOWN_MODE_TypeDef; typedef union{ /*!< CFG_READ_DBI register definition*/ __IO uint32_t CFG_READ_DBI; struct { __IO uint32_t cfg_read_dbi :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_READ_DBI_TypeDef; typedef union{ /*!< CFG_WRITE_DBI register definition*/ __IO uint32_t CFG_WRITE_DBI; struct { __IO uint32_t cfg_write_dbi :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_WRITE_DBI_TypeDef; typedef union{ /*!< CFG_DATA_MASK register definition*/ __IO uint32_t CFG_DATA_MASK; struct { __IO uint32_t cfg_data_mask :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DATA_MASK_TypeDef; typedef union{ /*!< CFG_CA_PARITY_PERSIST_ERR register definition*/ __IO uint32_t CFG_CA_PARITY_PERSIST_ERR; struct { __IO uint32_t cfg_ca_parity_persist_err :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CA_PARITY_PERSIST_ERR_TypeDef; typedef union{ /*!< CFG_RTT_PARK register definition*/ __IO uint32_t CFG_RTT_PARK; struct { __IO uint32_t cfg_rtt_park :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_RTT_PARK_TypeDef; typedef union{ /*!< CFG_ODT_INBUF_4_PD register definition*/ __IO uint32_t CFG_ODT_INBUF_4_PD; struct { __IO uint32_t cfg_odt_inbuf_4_pd :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ODT_INBUF_4_PD_TypeDef; typedef union{ /*!< CFG_CA_PARITY_ERR_STATUS register definition*/ __IO uint32_t CFG_CA_PARITY_ERR_STATUS; struct { __IO uint32_t cfg_ca_parity_err_status :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CA_PARITY_ERR_STATUS_TypeDef; typedef union{ /*!< CFG_CRC_ERROR_CLEAR register definition*/ __IO uint32_t CFG_CRC_ERROR_CLEAR; struct { __IO uint32_t cfg_crc_error_clear :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CRC_ERROR_CLEAR_TypeDef; typedef union{ /*!< CFG_CA_PARITY_LATENCY register definition*/ __IO uint32_t CFG_CA_PARITY_LATENCY; struct { __IO uint32_t cfg_ca_parity_latency :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_CA_PARITY_LATENCY_TypeDef; typedef union{ /*!< CFG_CCD_S register definition*/ __IO uint32_t CFG_CCD_S; struct { __IO uint32_t cfg_ccd_s :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_CCD_S_TypeDef; typedef union{ /*!< CFG_CCD_L register definition*/ __IO uint32_t CFG_CCD_L; struct { __IO uint32_t cfg_ccd_l :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_CCD_L_TypeDef; typedef union{ /*!< CFG_VREFDQ_TRN_ENABLE register definition*/ __IO uint32_t CFG_VREFDQ_TRN_ENABLE; struct { __IO uint32_t cfg_vrefdq_trn_enable :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_VREFDQ_TRN_ENABLE_TypeDef; typedef union{ /*!< CFG_VREFDQ_TRN_RANGE register definition*/ __IO uint32_t CFG_VREFDQ_TRN_RANGE; struct { __IO uint32_t cfg_vrefdq_trn_range :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_VREFDQ_TRN_RANGE_TypeDef; typedef union{ /*!< CFG_VREFDQ_TRN_VALUE register definition*/ __IO uint32_t CFG_VREFDQ_TRN_VALUE; struct { __IO uint32_t cfg_vrefdq_trn_value :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_VREFDQ_TRN_VALUE_TypeDef; typedef union{ /*!< CFG_RRD_S register definition*/ __IO uint32_t CFG_RRD_S; struct { __IO uint32_t cfg_rrd_s :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_RRD_S_TypeDef; typedef union{ /*!< CFG_RRD_L register definition*/ __IO uint32_t CFG_RRD_L; struct { __IO uint32_t cfg_rrd_l :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_RRD_L_TypeDef; typedef union{ /*!< CFG_WTR_S register definition*/ __IO uint32_t CFG_WTR_S; struct { __IO uint32_t cfg_wtr_s :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_WTR_S_TypeDef; typedef union{ /*!< CFG_WTR_L register definition*/ __IO uint32_t CFG_WTR_L; struct { __IO uint32_t cfg_wtr_l :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_WTR_L_TypeDef; typedef union{ /*!< CFG_WTR_S_CRC_DM register definition*/ __IO uint32_t CFG_WTR_S_CRC_DM; struct { __IO uint32_t cfg_wtr_s_crc_dm :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_WTR_S_CRC_DM_TypeDef; typedef union{ /*!< CFG_WTR_L_CRC_DM register definition*/ __IO uint32_t CFG_WTR_L_CRC_DM; struct { __IO uint32_t cfg_wtr_l_crc_dm :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_WTR_L_CRC_DM_TypeDef; typedef union{ /*!< CFG_WR_CRC_DM register definition*/ __IO uint32_t CFG_WR_CRC_DM; struct { __IO uint32_t cfg_wr_crc_dm :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_WR_CRC_DM_TypeDef; typedef union{ /*!< CFG_RFC1 register definition*/ __IO uint32_t CFG_RFC1; struct { __IO uint32_t cfg_rfc1 :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC1_TypeDef; typedef union{ /*!< CFG_RFC2 register definition*/ __IO uint32_t CFG_RFC2; struct { __IO uint32_t cfg_rfc2 :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC2_TypeDef; typedef union{ /*!< CFG_RFC4 register definition*/ __IO uint32_t CFG_RFC4; struct { __IO uint32_t cfg_rfc4 :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC4_TypeDef; typedef union{ /*!< CFG_NIBBLE_DEVICES register definition*/ __IO uint32_t CFG_NIBBLE_DEVICES; struct { __IO uint32_t cfg_nibble_devices :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_NIBBLE_DEVICES_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS0_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS0_0; struct { __IO uint32_t cfg_bit_map_index_cs0_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS0_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS0_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS0_1; struct { __IO uint32_t cfg_bit_map_index_cs0_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS0_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS1_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS1_0; struct { __IO uint32_t cfg_bit_map_index_cs1_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS1_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS1_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS1_1; struct { __IO uint32_t cfg_bit_map_index_cs1_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS1_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS2_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS2_0; struct { __IO uint32_t cfg_bit_map_index_cs2_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS2_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS2_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS2_1; struct { __IO uint32_t cfg_bit_map_index_cs2_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS2_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS3_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS3_0; struct { __IO uint32_t cfg_bit_map_index_cs3_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS3_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS3_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS3_1; struct { __IO uint32_t cfg_bit_map_index_cs3_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS3_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS4_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS4_0; struct { __IO uint32_t cfg_bit_map_index_cs4_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS4_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS4_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS4_1; struct { __IO uint32_t cfg_bit_map_index_cs4_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS4_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS5_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS5_0; struct { __IO uint32_t cfg_bit_map_index_cs5_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS5_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS5_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS5_1; struct { __IO uint32_t cfg_bit_map_index_cs5_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS5_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS6_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS6_0; struct { __IO uint32_t cfg_bit_map_index_cs6_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS6_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS6_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS6_1; struct { __IO uint32_t cfg_bit_map_index_cs6_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS6_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS7_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS7_0; struct { __IO uint32_t cfg_bit_map_index_cs7_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS7_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS7_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS7_1; struct { __IO uint32_t cfg_bit_map_index_cs7_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS7_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS8_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS8_0; struct { __IO uint32_t cfg_bit_map_index_cs8_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS8_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS8_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS8_1; struct { __IO uint32_t cfg_bit_map_index_cs8_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS8_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS9_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS9_0; struct { __IO uint32_t cfg_bit_map_index_cs9_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS9_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS9_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS9_1; struct { __IO uint32_t cfg_bit_map_index_cs9_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS9_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS10_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS10_0; struct { __IO uint32_t cfg_bit_map_index_cs10_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS10_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS10_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS10_1; struct { __IO uint32_t cfg_bit_map_index_cs10_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS10_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS11_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS11_0; struct { __IO uint32_t cfg_bit_map_index_cs11_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS11_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS11_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS11_1; struct { __IO uint32_t cfg_bit_map_index_cs11_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS11_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS12_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS12_0; struct { __IO uint32_t cfg_bit_map_index_cs12_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS12_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS12_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS12_1; struct { __IO uint32_t cfg_bit_map_index_cs12_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS12_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS13_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS13_0; struct { __IO uint32_t cfg_bit_map_index_cs13_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS13_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS13_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS13_1; struct { __IO uint32_t cfg_bit_map_index_cs13_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS13_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS14_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS14_0; struct { __IO uint32_t cfg_bit_map_index_cs14_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS14_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS14_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS14_1; struct { __IO uint32_t cfg_bit_map_index_cs14_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS14_1_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS15_0 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS15_0; struct { __IO uint32_t cfg_bit_map_index_cs15_0 :32; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS15_0_TypeDef; typedef union{ /*!< CFG_BIT_MAP_INDEX_CS15_1 register definition*/ __IO uint32_t CFG_BIT_MAP_INDEX_CS15_1; struct { __IO uint32_t cfg_bit_map_index_cs15_1 :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS15_1_TypeDef; typedef union{ /*!< CFG_NUM_LOGICAL_RANKS_PER_3DS register definition*/ __IO uint32_t CFG_NUM_LOGICAL_RANKS_PER_3DS; struct { __IO uint32_t cfg_num_logical_ranks_per_3ds :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_NUM_LOGICAL_RANKS_PER_3DS_TypeDef; typedef union{ /*!< CFG_RFC_DLR1 register definition*/ __IO uint32_t CFG_RFC_DLR1; struct { __IO uint32_t cfg_rfc_dlr1 :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC_DLR1_TypeDef; typedef union{ /*!< CFG_RFC_DLR2 register definition*/ __IO uint32_t CFG_RFC_DLR2; struct { __IO uint32_t cfg_rfc_dlr2 :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC_DLR2_TypeDef; typedef union{ /*!< CFG_RFC_DLR4 register definition*/ __IO uint32_t CFG_RFC_DLR4; struct { __IO uint32_t cfg_rfc_dlr4 :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC_DLR4_TypeDef; typedef union{ /*!< CFG_RRD_DLR register definition*/ __IO uint32_t CFG_RRD_DLR; struct { __IO uint32_t cfg_rrd_dlr :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_RRD_DLR_TypeDef; typedef union{ /*!< CFG_FAW_DLR register definition*/ __IO uint32_t CFG_FAW_DLR; struct { __IO uint32_t cfg_faw_dlr :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_FAW_DLR_TypeDef; typedef union{ /*!< CFG_ADVANCE_ACTIVATE_READY register definition*/ __IO uint32_t CFG_ADVANCE_ACTIVATE_READY; struct { __IO uint32_t cfg_advance_activate_ready :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_ADVANCE_ACTIVATE_READY_TypeDef; typedef union{ /*!< CTRLR_SOFT_RESET_N register definition*/ __IO uint32_t CTRLR_SOFT_RESET_N; struct { __IO uint32_t ctrlr_soft_reset_n :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CTRLR_SOFT_RESET_N_TypeDef; typedef union{ /*!< CFG_LOOKAHEAD_PCH register definition*/ __IO uint32_t CFG_LOOKAHEAD_PCH; struct { __IO uint32_t cfg_lookahead_pch :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_LOOKAHEAD_PCH_TypeDef; typedef union{ /*!< CFG_LOOKAHEAD_ACT register definition*/ __IO uint32_t CFG_LOOKAHEAD_ACT; struct { __IO uint32_t cfg_lookahead_act :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_LOOKAHEAD_ACT_TypeDef; typedef union{ /*!< INIT_AUTOINIT_DISABLE register definition*/ __IO uint32_t INIT_AUTOINIT_DISABLE; struct { __IO uint32_t init_autoinit_disable :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_AUTOINIT_DISABLE_TypeDef; typedef union{ /*!< INIT_FORCE_RESET register definition*/ __IO uint32_t INIT_FORCE_RESET; struct { __IO uint32_t init_force_reset :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_FORCE_RESET_TypeDef; typedef union{ /*!< INIT_GEARDOWN_EN register definition*/ __IO uint32_t INIT_GEARDOWN_EN; struct { __IO uint32_t init_geardown_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_GEARDOWN_EN_TypeDef; typedef union{ /*!< INIT_DISABLE_CKE register definition*/ __IO uint32_t INIT_DISABLE_CKE; struct { __IO uint32_t init_disable_cke :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_DISABLE_CKE_TypeDef; typedef union{ /*!< INIT_CS register definition*/ __IO uint32_t INIT_CS; struct { __IO uint32_t init_cs :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_CS_TypeDef; typedef union{ /*!< INIT_PRECHARGE_ALL register definition*/ __IO uint32_t INIT_PRECHARGE_ALL; struct { __IO uint32_t init_precharge_all :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_PRECHARGE_ALL_TypeDef; typedef union{ /*!< INIT_REFRESH register definition*/ __IO uint32_t INIT_REFRESH; struct { __IO uint32_t init_refresh :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_REFRESH_TypeDef; typedef union{ /*!< INIT_ZQ_CAL_REQ register definition*/ __IO uint32_t INIT_ZQ_CAL_REQ; struct { __IO uint32_t init_zq_cal_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_ZQ_CAL_REQ_TypeDef; typedef union{ /*!< INIT_ACK register definition*/ __I uint32_t INIT_ACK; struct { __I uint32_t init_ack :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_ACK_TypeDef; typedef union{ /*!< CFG_BL register definition*/ __IO uint32_t CFG_BL; struct { __IO uint32_t cfg_bl :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_BL_TypeDef; typedef union{ /*!< CTRLR_INIT register definition*/ __IO uint32_t CTRLR_INIT; struct { __IO uint32_t ctrlr_init :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CTRLR_INIT_TypeDef; typedef union{ /*!< CTRLR_INIT_DONE register definition*/ __I uint32_t CTRLR_INIT_DONE; struct { __I uint32_t ctrlr_init_done :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CTRLR_INIT_DONE_TypeDef; typedef union{ /*!< CFG_AUTO_REF_EN register definition*/ __IO uint32_t CFG_AUTO_REF_EN; struct { __IO uint32_t cfg_auto_ref_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_AUTO_REF_EN_TypeDef; typedef union{ /*!< CFG_RAS register definition*/ __IO uint32_t CFG_RAS; struct { __IO uint32_t cfg_ras :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_RAS_TypeDef; typedef union{ /*!< CFG_RCD register definition*/ __IO uint32_t CFG_RCD; struct { __IO uint32_t cfg_rcd :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_RCD_TypeDef; typedef union{ /*!< CFG_RRD register definition*/ __IO uint32_t CFG_RRD; struct { __IO uint32_t cfg_rrd :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_RRD_TypeDef; typedef union{ /*!< CFG_RP register definition*/ __IO uint32_t CFG_RP; struct { __IO uint32_t cfg_rp :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_RP_TypeDef; typedef union{ /*!< CFG_RC register definition*/ __IO uint32_t CFG_RC; struct { __IO uint32_t cfg_rc :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_RC_TypeDef; typedef union{ /*!< CFG_FAW register definition*/ __IO uint32_t CFG_FAW; struct { __IO uint32_t cfg_faw :9; __I uint32_t reserved :23; } bitfield; } DDR_CSR_APB_CFG_FAW_TypeDef; typedef union{ /*!< CFG_RFC register definition*/ __IO uint32_t CFG_RFC; struct { __IO uint32_t cfg_rfc :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_RFC_TypeDef; typedef union{ /*!< CFG_RTP register definition*/ __IO uint32_t CFG_RTP; struct { __IO uint32_t cfg_rtp :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_RTP_TypeDef; typedef union{ /*!< CFG_WR register definition*/ __IO uint32_t CFG_WR; struct { __IO uint32_t cfg_wr :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_WR_TypeDef; typedef union{ /*!< CFG_WTR register definition*/ __IO uint32_t CFG_WTR; struct { __IO uint32_t cfg_wtr :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_WTR_TypeDef; typedef union{ /*!< CFG_PASR register definition*/ __IO uint32_t CFG_PASR; struct { __IO uint32_t cfg_pasr :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_PASR_TypeDef; typedef union{ /*!< CFG_XP register definition*/ __IO uint32_t CFG_XP; struct { __IO uint32_t cfg_xp :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_XP_TypeDef; typedef union{ /*!< CFG_XSR register definition*/ __IO uint32_t CFG_XSR; struct { __IO uint32_t cfg_xsr :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_XSR_TypeDef; typedef union{ /*!< CFG_CL register definition*/ __IO uint32_t CFG_CL; struct { __IO uint32_t cfg_cl :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_CL_TypeDef; typedef union{ /*!< CFG_READ_TO_WRITE register definition*/ __IO uint32_t CFG_READ_TO_WRITE; struct { __IO uint32_t cfg_read_to_write :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_READ_TO_WRITE_TypeDef; typedef union{ /*!< CFG_WRITE_TO_WRITE register definition*/ __IO uint32_t CFG_WRITE_TO_WRITE; struct { __IO uint32_t cfg_write_to_write :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_WRITE_TO_WRITE_TypeDef; typedef union{ /*!< CFG_READ_TO_READ register definition*/ __IO uint32_t CFG_READ_TO_READ; struct { __IO uint32_t cfg_read_to_read :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_READ_TO_READ_TypeDef; typedef union{ /*!< CFG_WRITE_TO_READ register definition*/ __IO uint32_t CFG_WRITE_TO_READ; struct { __IO uint32_t cfg_write_to_read :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_WRITE_TO_READ_TypeDef; typedef union{ /*!< CFG_READ_TO_WRITE_ODT register definition*/ __IO uint32_t CFG_READ_TO_WRITE_ODT; struct { __IO uint32_t cfg_read_to_write_odt :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_READ_TO_WRITE_ODT_TypeDef; typedef union{ /*!< CFG_WRITE_TO_WRITE_ODT register definition*/ __IO uint32_t CFG_WRITE_TO_WRITE_ODT; struct { __IO uint32_t cfg_write_to_write_odt :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_WRITE_TO_WRITE_ODT_TypeDef; typedef union{ /*!< CFG_READ_TO_READ_ODT register definition*/ __IO uint32_t CFG_READ_TO_READ_ODT; struct { __IO uint32_t cfg_read_to_read_odt :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_READ_TO_READ_ODT_TypeDef; typedef union{ /*!< CFG_WRITE_TO_READ_ODT register definition*/ __IO uint32_t CFG_WRITE_TO_READ_ODT; struct { __IO uint32_t cfg_write_to_read_odt :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_WRITE_TO_READ_ODT_TypeDef; typedef union{ /*!< CFG_MIN_READ_IDLE register definition*/ __IO uint32_t CFG_MIN_READ_IDLE; struct { __IO uint32_t cfg_min_read_idle :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_MIN_READ_IDLE_TypeDef; typedef union{ /*!< CFG_MRD register definition*/ __IO uint32_t CFG_MRD; struct { __IO uint32_t cfg_mrd :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_MRD_TypeDef; typedef union{ /*!< CFG_BT register definition*/ __IO uint32_t CFG_BT; struct { __IO uint32_t cfg_bt :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_BT_TypeDef; typedef union{ /*!< CFG_DS register definition*/ __IO uint32_t CFG_DS; struct { __IO uint32_t cfg_ds :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_DS_TypeDef; typedef union{ /*!< CFG_QOFF register definition*/ __IO uint32_t CFG_QOFF; struct { __IO uint32_t cfg_qoff :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_QOFF_TypeDef; typedef union{ /*!< CFG_RTT register definition*/ __IO uint32_t CFG_RTT; struct { __IO uint32_t cfg_rtt :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_RTT_TypeDef; typedef union{ /*!< CFG_DLL_DISABLE register definition*/ __IO uint32_t CFG_DLL_DISABLE; struct { __IO uint32_t cfg_dll_disable :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DLL_DISABLE_TypeDef; typedef union{ /*!< CFG_REF_PER register definition*/ __IO uint32_t CFG_REF_PER; struct { __IO uint32_t cfg_ref_per :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_CFG_REF_PER_TypeDef; typedef union{ /*!< CFG_STARTUP_DELAY register definition*/ __IO uint32_t CFG_STARTUP_DELAY; struct { __IO uint32_t cfg_startup_delay :19; __I uint32_t reserved :13; } bitfield; } DDR_CSR_APB_CFG_STARTUP_DELAY_TypeDef; typedef union{ /*!< CFG_MEM_COLBITS register definition*/ __IO uint32_t CFG_MEM_COLBITS; struct { __IO uint32_t cfg_mem_colbits :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_MEM_COLBITS_TypeDef; typedef union{ /*!< CFG_MEM_ROWBITS register definition*/ __IO uint32_t CFG_MEM_ROWBITS; struct { __IO uint32_t cfg_mem_rowbits :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_MEM_ROWBITS_TypeDef; typedef union{ /*!< CFG_MEM_BANKBITS register definition*/ __IO uint32_t CFG_MEM_BANKBITS; struct { __IO uint32_t cfg_mem_bankbits :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_MEM_BANKBITS_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS0 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS0; struct { __IO uint32_t cfg_odt_rd_map_cs0 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS0_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS1 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS1; struct { __IO uint32_t cfg_odt_rd_map_cs1 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS1_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS2 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS2; struct { __IO uint32_t cfg_odt_rd_map_cs2 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS2_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS3 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS3; struct { __IO uint32_t cfg_odt_rd_map_cs3 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS3_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS4 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS4; struct { __IO uint32_t cfg_odt_rd_map_cs4 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS4_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS5 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS5; struct { __IO uint32_t cfg_odt_rd_map_cs5 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS5_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS6 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS6; struct { __IO uint32_t cfg_odt_rd_map_cs6 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS6_TypeDef; typedef union{ /*!< CFG_ODT_RD_MAP_CS7 register definition*/ __IO uint32_t CFG_ODT_RD_MAP_CS7; struct { __IO uint32_t cfg_odt_rd_map_cs7 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_MAP_CS7_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS0 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS0; struct { __IO uint32_t cfg_odt_wr_map_cs0 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS0_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS1 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS1; struct { __IO uint32_t cfg_odt_wr_map_cs1 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS1_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS2 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS2; struct { __IO uint32_t cfg_odt_wr_map_cs2 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS2_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS3 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS3; struct { __IO uint32_t cfg_odt_wr_map_cs3 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS3_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS4 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS4; struct { __IO uint32_t cfg_odt_wr_map_cs4 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS4_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS5 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS5; struct { __IO uint32_t cfg_odt_wr_map_cs5 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS5_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS6 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS6; struct { __IO uint32_t cfg_odt_wr_map_cs6 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS6_TypeDef; typedef union{ /*!< CFG_ODT_WR_MAP_CS7 register definition*/ __IO uint32_t CFG_ODT_WR_MAP_CS7; struct { __IO uint32_t cfg_odt_wr_map_cs7 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_MAP_CS7_TypeDef; typedef union{ /*!< CFG_ODT_RD_TURN_ON register definition*/ __IO uint32_t CFG_ODT_RD_TURN_ON; struct { __IO uint32_t cfg_odt_rd_turn_on :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_TURN_ON_TypeDef; typedef union{ /*!< CFG_ODT_WR_TURN_ON register definition*/ __IO uint32_t CFG_ODT_WR_TURN_ON; struct { __IO uint32_t cfg_odt_wr_turn_on :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_TURN_ON_TypeDef; typedef union{ /*!< CFG_ODT_RD_TURN_OFF register definition*/ __IO uint32_t CFG_ODT_RD_TURN_OFF; struct { __IO uint32_t cfg_odt_rd_turn_off :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_ODT_RD_TURN_OFF_TypeDef; typedef union{ /*!< CFG_ODT_WR_TURN_OFF register definition*/ __IO uint32_t CFG_ODT_WR_TURN_OFF; struct { __IO uint32_t cfg_odt_wr_turn_off :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_ODT_WR_TURN_OFF_TypeDef; typedef union{ /*!< CFG_EMR3 register definition*/ __IO uint32_t CFG_EMR3; struct { __IO uint32_t cfg_emr3 :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_CFG_EMR3_TypeDef; typedef union{ /*!< CFG_TWO_T register definition*/ __IO uint32_t CFG_TWO_T; struct { __IO uint32_t cfg_two_t :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TWO_T_TypeDef; typedef union{ /*!< CFG_TWO_T_SEL_CYCLE register definition*/ __IO uint32_t CFG_TWO_T_SEL_CYCLE; struct { __IO uint32_t cfg_two_t_sel_cycle :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TWO_T_SEL_CYCLE_TypeDef; typedef union{ /*!< CFG_REGDIMM register definition*/ __IO uint32_t CFG_REGDIMM; struct { __IO uint32_t cfg_regdimm :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_REGDIMM_TypeDef; typedef union{ /*!< CFG_MOD register definition*/ __IO uint32_t CFG_MOD; struct { __IO uint32_t cfg_mod :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_MOD_TypeDef; typedef union{ /*!< CFG_XS register definition*/ __IO uint32_t CFG_XS; struct { __IO uint32_t cfg_xs :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_XS_TypeDef; typedef union{ /*!< CFG_XSDLL register definition*/ __IO uint32_t CFG_XSDLL; struct { __IO uint32_t cfg_xsdll :11; __I uint32_t reserved :21; } bitfield; } DDR_CSR_APB_CFG_XSDLL_TypeDef; typedef union{ /*!< CFG_XPR register definition*/ __IO uint32_t CFG_XPR; struct { __IO uint32_t cfg_xpr :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_XPR_TypeDef; typedef union{ /*!< CFG_AL_MODE register definition*/ __IO uint32_t CFG_AL_MODE; struct { __IO uint32_t cfg_al_mode :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_AL_MODE_TypeDef; typedef union{ /*!< CFG_CWL register definition*/ __IO uint32_t CFG_CWL; struct { __IO uint32_t cfg_cwl :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_CWL_TypeDef; typedef union{ /*!< CFG_BL_MODE register definition*/ __IO uint32_t CFG_BL_MODE; struct { __IO uint32_t cfg_bl_mode :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_BL_MODE_TypeDef; typedef union{ /*!< CFG_TDQS register definition*/ __IO uint32_t CFG_TDQS; struct { __IO uint32_t cfg_tdqs :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TDQS_TypeDef; typedef union{ /*!< CFG_RTT_WR register definition*/ __IO uint32_t CFG_RTT_WR; struct { __IO uint32_t cfg_rtt_wr :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_RTT_WR_TypeDef; typedef union{ /*!< CFG_LP_ASR register definition*/ __IO uint32_t CFG_LP_ASR; struct { __IO uint32_t cfg_lp_asr :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_LP_ASR_TypeDef; typedef union{ /*!< CFG_AUTO_SR register definition*/ __IO uint32_t CFG_AUTO_SR; struct { __IO uint32_t cfg_auto_sr :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_AUTO_SR_TypeDef; typedef union{ /*!< CFG_SRT register definition*/ __IO uint32_t CFG_SRT; struct { __IO uint32_t cfg_srt :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_SRT_TypeDef; typedef union{ /*!< CFG_ADDR_MIRROR register definition*/ __IO uint32_t CFG_ADDR_MIRROR; struct { __IO uint32_t cfg_addr_mirror :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ADDR_MIRROR_TypeDef; typedef union{ /*!< CFG_ZQ_CAL_TYPE register definition*/ __IO uint32_t CFG_ZQ_CAL_TYPE; struct { __IO uint32_t cfg_zq_cal_type :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_ZQ_CAL_TYPE_TypeDef; typedef union{ /*!< CFG_ZQ_CAL_PER register definition*/ __IO uint32_t CFG_ZQ_CAL_PER; struct { __IO uint32_t cfg_zq_cal_per :32; } bitfield; } DDR_CSR_APB_CFG_ZQ_CAL_PER_TypeDef; typedef union{ /*!< CFG_AUTO_ZQ_CAL_EN register definition*/ __IO uint32_t CFG_AUTO_ZQ_CAL_EN; struct { __IO uint32_t cfg_auto_zq_cal_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_AUTO_ZQ_CAL_EN_TypeDef; typedef union{ /*!< CFG_MEMORY_TYPE register definition*/ __IO uint32_t CFG_MEMORY_TYPE; struct { __IO uint32_t cfg_memory_type :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_CFG_MEMORY_TYPE_TypeDef; typedef union{ /*!< CFG_ONLY_SRANK_CMDS register definition*/ __IO uint32_t CFG_ONLY_SRANK_CMDS; struct { __IO uint32_t cfg_only_srank_cmds :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ONLY_SRANK_CMDS_TypeDef; typedef union{ /*!< CFG_NUM_RANKS register definition*/ __IO uint32_t CFG_NUM_RANKS; struct { __IO uint32_t cfg_num_ranks :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_NUM_RANKS_TypeDef; typedef union{ /*!< CFG_QUAD_RANK register definition*/ __IO uint32_t CFG_QUAD_RANK; struct { __IO uint32_t cfg_quad_rank :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_QUAD_RANK_TypeDef; typedef union{ /*!< CFG_EARLY_RANK_TO_WR_START register definition*/ __IO uint32_t CFG_EARLY_RANK_TO_WR_START; struct { __IO uint32_t cfg_early_rank_to_wr_start :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_EARLY_RANK_TO_WR_START_TypeDef; typedef union{ /*!< CFG_EARLY_RANK_TO_RD_START register definition*/ __IO uint32_t CFG_EARLY_RANK_TO_RD_START; struct { __IO uint32_t cfg_early_rank_to_rd_start :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_EARLY_RANK_TO_RD_START_TypeDef; typedef union{ /*!< CFG_PASR_BANK register definition*/ __IO uint32_t CFG_PASR_BANK; struct { __IO uint32_t cfg_pasr_bank :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_PASR_BANK_TypeDef; typedef union{ /*!< CFG_PASR_SEG register definition*/ __IO uint32_t CFG_PASR_SEG; struct { __IO uint32_t cfg_pasr_seg :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_PASR_SEG_TypeDef; typedef union{ /*!< INIT_MRR_MODE register definition*/ __IO uint32_t INIT_MRR_MODE; struct { __IO uint32_t init_mrr_mode :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_MRR_MODE_TypeDef; typedef union{ /*!< INIT_MR_W_REQ register definition*/ __IO uint32_t INIT_MR_W_REQ; struct { __IO uint32_t init_mr_w_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_MR_W_REQ_TypeDef; typedef union{ /*!< INIT_MR_ADDR register definition*/ __IO uint32_t INIT_MR_ADDR; struct { __IO uint32_t init_mr_addr :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_MR_ADDR_TypeDef; typedef union{ /*!< INIT_MR_WR_DATA register definition*/ __IO uint32_t INIT_MR_WR_DATA; struct { __IO uint32_t init_mr_wr_data :18; __I uint32_t reserved :14; } bitfield; } DDR_CSR_APB_INIT_MR_WR_DATA_TypeDef; typedef union{ /*!< INIT_MR_WR_MASK register definition*/ __IO uint32_t INIT_MR_WR_MASK; struct { __IO uint32_t init_mr_wr_mask :18; __I uint32_t reserved :14; } bitfield; } DDR_CSR_APB_INIT_MR_WR_MASK_TypeDef; typedef union{ /*!< INIT_NOP register definition*/ __IO uint32_t INIT_NOP; struct { __IO uint32_t init_nop :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_NOP_TypeDef; typedef union{ /*!< CFG_INIT_DURATION register definition*/ __IO uint32_t CFG_INIT_DURATION; struct { __IO uint32_t cfg_init_duration :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_CFG_INIT_DURATION_TypeDef; typedef union{ /*!< CFG_ZQINIT_CAL_DURATION register definition*/ __IO uint32_t CFG_ZQINIT_CAL_DURATION; struct { __IO uint32_t cfg_zqinit_cal_duration :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_ZQINIT_CAL_DURATION_TypeDef; typedef union{ /*!< CFG_ZQ_CAL_L_DURATION register definition*/ __IO uint32_t CFG_ZQ_CAL_L_DURATION; struct { __IO uint32_t cfg_zq_cal_l_duration :11; __I uint32_t reserved :21; } bitfield; } DDR_CSR_APB_CFG_ZQ_CAL_L_DURATION_TypeDef; typedef union{ /*!< CFG_ZQ_CAL_S_DURATION register definition*/ __IO uint32_t CFG_ZQ_CAL_S_DURATION; struct { __IO uint32_t cfg_zq_cal_s_duration :11; __I uint32_t reserved :21; } bitfield; } DDR_CSR_APB_CFG_ZQ_CAL_S_DURATION_TypeDef; typedef union{ /*!< CFG_ZQ_CAL_R_DURATION register definition*/ __IO uint32_t CFG_ZQ_CAL_R_DURATION; struct { __IO uint32_t cfg_zq_cal_r_duration :11; __I uint32_t reserved :21; } bitfield; } DDR_CSR_APB_CFG_ZQ_CAL_R_DURATION_TypeDef; typedef union{ /*!< CFG_MRR register definition*/ __IO uint32_t CFG_MRR; struct { __IO uint32_t cfg_mrr :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_MRR_TypeDef; typedef union{ /*!< CFG_MRW register definition*/ __IO uint32_t CFG_MRW; struct { __IO uint32_t cfg_mrw :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_MRW_TypeDef; typedef union{ /*!< CFG_ODT_POWERDOWN register definition*/ __IO uint32_t CFG_ODT_POWERDOWN; struct { __IO uint32_t cfg_odt_powerdown :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ODT_POWERDOWN_TypeDef; typedef union{ /*!< CFG_WL register definition*/ __IO uint32_t CFG_WL; struct { __IO uint32_t cfg_wl :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_WL_TypeDef; typedef union{ /*!< CFG_RL register definition*/ __IO uint32_t CFG_RL; struct { __IO uint32_t cfg_rl :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_RL_TypeDef; typedef union{ /*!< CFG_CAL_READ_PERIOD register definition*/ __IO uint32_t CFG_CAL_READ_PERIOD; struct { __IO uint32_t cfg_cal_read_period :22; __I uint32_t reserved :10; } bitfield; } DDR_CSR_APB_CFG_CAL_READ_PERIOD_TypeDef; typedef union{ /*!< CFG_NUM_CAL_READS register definition*/ __IO uint32_t CFG_NUM_CAL_READS; struct { __IO uint32_t cfg_num_cal_reads :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_NUM_CAL_READS_TypeDef; typedef union{ /*!< INIT_SELF_REFRESH register definition*/ __IO uint32_t INIT_SELF_REFRESH; struct { __IO uint32_t init_self_refresh :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_SELF_REFRESH_TypeDef; typedef union{ /*!< INIT_SELF_REFRESH_STATUS register definition*/ __I uint32_t INIT_SELF_REFRESH_STATUS; struct { __I uint32_t init_self_refresh_status :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_SELF_REFRESH_STATUS_TypeDef; typedef union{ /*!< INIT_POWER_DOWN register definition*/ __IO uint32_t INIT_POWER_DOWN; struct { __IO uint32_t init_power_down :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_POWER_DOWN_TypeDef; typedef union{ /*!< INIT_POWER_DOWN_STATUS register definition*/ __I uint32_t INIT_POWER_DOWN_STATUS; struct { __I uint32_t init_power_down_status :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_POWER_DOWN_STATUS_TypeDef; typedef union{ /*!< INIT_FORCE_WRITE register definition*/ __IO uint32_t INIT_FORCE_WRITE; struct { __IO uint32_t init_force_write :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_FORCE_WRITE_TypeDef; typedef union{ /*!< INIT_FORCE_WRITE_CS register definition*/ __IO uint32_t INIT_FORCE_WRITE_CS; struct { __IO uint32_t init_force_write_cs :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_INIT_FORCE_WRITE_CS_TypeDef; typedef union{ /*!< CFG_CTRLR_INIT_DISABLE register definition*/ __IO uint32_t CFG_CTRLR_INIT_DISABLE; struct { __IO uint32_t cfg_ctrlr_init_disable :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CTRLR_INIT_DISABLE_TypeDef; typedef union{ /*!< CTRLR_READY register definition*/ __I uint32_t CTRLR_READY; struct { __I uint32_t ctrlr_ready :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CTRLR_READY_TypeDef; typedef union{ /*!< INIT_RDIMM_READY register definition*/ __I uint32_t INIT_RDIMM_READY; struct { __I uint32_t init_rdimm_ready :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_RDIMM_READY_TypeDef; typedef union{ /*!< INIT_RDIMM_COMPLETE register definition*/ __IO uint32_t INIT_RDIMM_COMPLETE; struct { __IO uint32_t init_rdimm_complete :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_RDIMM_COMPLETE_TypeDef; typedef union{ /*!< CFG_RDIMM_LAT register definition*/ __IO uint32_t CFG_RDIMM_LAT; struct { __IO uint32_t cfg_rdimm_lat :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_RDIMM_LAT_TypeDef; typedef union{ /*!< CFG_RDIMM_BSIDE_INVERT register definition*/ __IO uint32_t CFG_RDIMM_BSIDE_INVERT; struct { __IO uint32_t cfg_rdimm_bside_invert :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RDIMM_BSIDE_INVERT_TypeDef; typedef union{ /*!< CFG_LRDIMM register definition*/ __IO uint32_t CFG_LRDIMM; struct { __IO uint32_t cfg_lrdimm :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_LRDIMM_TypeDef; typedef union{ /*!< INIT_MEMORY_RESET_MASK register definition*/ __IO uint32_t INIT_MEMORY_RESET_MASK; struct { __IO uint32_t init_memory_reset_mask :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_MEMORY_RESET_MASK_TypeDef; typedef union{ /*!< CFG_RD_PREAMB_TOGGLE register definition*/ __IO uint32_t CFG_RD_PREAMB_TOGGLE; struct { __IO uint32_t cfg_rd_preamb_toggle :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RD_PREAMB_TOGGLE_TypeDef; typedef union{ /*!< CFG_RD_POSTAMBLE register definition*/ __IO uint32_t CFG_RD_POSTAMBLE; struct { __IO uint32_t cfg_rd_postamble :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RD_POSTAMBLE_TypeDef; typedef union{ /*!< CFG_PU_CAL register definition*/ __IO uint32_t CFG_PU_CAL; struct { __IO uint32_t cfg_pu_cal :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_PU_CAL_TypeDef; typedef union{ /*!< CFG_DQ_ODT register definition*/ __IO uint32_t CFG_DQ_ODT; struct { __IO uint32_t cfg_dq_odt :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_DQ_ODT_TypeDef; typedef union{ /*!< CFG_CA_ODT register definition*/ __IO uint32_t CFG_CA_ODT; struct { __IO uint32_t cfg_ca_odt :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_CA_ODT_TypeDef; typedef union{ /*!< CFG_ZQLATCH_DURATION register definition*/ __IO uint32_t CFG_ZQLATCH_DURATION; struct { __IO uint32_t cfg_zqlatch_duration :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ZQLATCH_DURATION_TypeDef; typedef union{ /*!< INIT_CAL_SELECT register definition*/ __IO uint32_t INIT_CAL_SELECT; struct { __IO uint32_t init_cal_select :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_CAL_SELECT_TypeDef; typedef union{ /*!< INIT_CAL_L_R_REQ register definition*/ __IO uint32_t INIT_CAL_L_R_REQ; struct { __IO uint32_t init_cal_l_r_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_CAL_L_R_REQ_TypeDef; typedef union{ /*!< INIT_CAL_L_B_SIZE register definition*/ __IO uint32_t INIT_CAL_L_B_SIZE; struct { __IO uint32_t init_cal_l_b_size :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_INIT_CAL_L_B_SIZE_TypeDef; typedef union{ /*!< INIT_CAL_L_R_ACK register definition*/ __I uint32_t INIT_CAL_L_R_ACK; struct { __I uint32_t init_cal_l_r_ack :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_CAL_L_R_ACK_TypeDef; typedef union{ /*!< INIT_CAL_L_READ_COMPLETE register definition*/ __I uint32_t INIT_CAL_L_READ_COMPLETE; struct { __I uint32_t init_cal_l_read_complete :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_CAL_L_READ_COMPLETE_TypeDef; typedef union{ /*!< INIT_RWFIFO register definition*/ __IO uint32_t INIT_RWFIFO; struct { __IO uint32_t init_rwfifo :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_RWFIFO_TypeDef; typedef union{ /*!< INIT_RD_DQCAL register definition*/ __IO uint32_t INIT_RD_DQCAL; struct { __IO uint32_t init_rd_dqcal :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_RD_DQCAL_TypeDef; typedef union{ /*!< INIT_START_DQSOSC register definition*/ __IO uint32_t INIT_START_DQSOSC; struct { __IO uint32_t init_start_dqsosc :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_START_DQSOSC_TypeDef; typedef union{ /*!< INIT_STOP_DQSOSC register definition*/ __IO uint32_t INIT_STOP_DQSOSC; struct { __IO uint32_t init_stop_dqsosc :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_STOP_DQSOSC_TypeDef; typedef union{ /*!< INIT_ZQ_CAL_START register definition*/ __IO uint32_t INIT_ZQ_CAL_START; struct { __IO uint32_t init_zq_cal_start :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_ZQ_CAL_START_TypeDef; typedef union{ /*!< CFG_WR_POSTAMBLE register definition*/ __IO uint32_t CFG_WR_POSTAMBLE; struct { __IO uint32_t cfg_wr_postamble :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_WR_POSTAMBLE_TypeDef; typedef union{ /*!< INIT_CAL_L_ADDR_0 register definition*/ __IO uint32_t INIT_CAL_L_ADDR_0; struct { __IO uint32_t init_cal_l_addr_0 :32; } bitfield; } DDR_CSR_APB_INIT_CAL_L_ADDR_0_TypeDef; typedef union{ /*!< INIT_CAL_L_ADDR_1 register definition*/ __IO uint32_t INIT_CAL_L_ADDR_1; struct { __IO uint32_t init_cal_l_addr_1 :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_INIT_CAL_L_ADDR_1_TypeDef; typedef union{ /*!< CFG_CTRLUPD_TRIG register definition*/ __IO uint32_t CFG_CTRLUPD_TRIG; struct { __IO uint32_t cfg_ctrlupd_trig :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_CTRLUPD_TRIG_TypeDef; typedef union{ /*!< CFG_CTRLUPD_START_DELAY register definition*/ __IO uint32_t CFG_CTRLUPD_START_DELAY; struct { __IO uint32_t cfg_ctrlupd_start_delay :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_CTRLUPD_START_DELAY_TypeDef; typedef union{ /*!< CFG_DFI_T_CTRLUPD_MAX register definition*/ __IO uint32_t CFG_DFI_T_CTRLUPD_MAX; struct { __IO uint32_t cfg_dfi_t_ctrlupd_max :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_DFI_T_CTRLUPD_MAX_TypeDef; typedef union{ /*!< CFG_CTRLR_BUSY_SEL register definition*/ __IO uint32_t CFG_CTRLR_BUSY_SEL; struct { __IO uint32_t cfg_ctrlr_busy_sel :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CTRLR_BUSY_SEL_TypeDef; typedef union{ /*!< CFG_CTRLR_BUSY_VALUE register definition*/ __IO uint32_t CFG_CTRLR_BUSY_VALUE; struct { __IO uint32_t cfg_ctrlr_busy_value :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CTRLR_BUSY_VALUE_TypeDef; typedef union{ /*!< CFG_CTRLR_BUSY_TURN_OFF_DELAY register definition*/ __IO uint32_t CFG_CTRLR_BUSY_TURN_OFF_DELAY; struct { __IO uint32_t cfg_ctrlr_busy_turn_off_delay :9; __I uint32_t reserved :23; } bitfield; } DDR_CSR_APB_CFG_CTRLR_BUSY_TURN_OFF_DELAY_TypeDef; typedef union{ /*!< CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW register definition*/ __IO uint32_t CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW; struct { __IO uint32_t cfg_ctrlr_busy_slow_restart_window :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW_TypeDef; typedef union{ /*!< CFG_CTRLR_BUSY_RESTART_HOLDOFF register definition*/ __IO uint32_t CFG_CTRLR_BUSY_RESTART_HOLDOFF; struct { __IO uint32_t cfg_ctrlr_busy_restart_holdoff :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_CTRLR_BUSY_RESTART_HOLDOFF_TypeDef; typedef union{ /*!< CFG_PARITY_RDIMM_DELAY register definition*/ __IO uint32_t CFG_PARITY_RDIMM_DELAY; struct { __IO uint32_t cfg_parity_rdimm_delay :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_PARITY_RDIMM_DELAY_TypeDef; typedef union{ /*!< CFG_CTRLR_BUSY_ENABLE register definition*/ __IO uint32_t CFG_CTRLR_BUSY_ENABLE; struct { __IO uint32_t cfg_ctrlr_busy_enable :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_CTRLR_BUSY_ENABLE_TypeDef; typedef union{ /*!< CFG_ASYNC_ODT register definition*/ __IO uint32_t CFG_ASYNC_ODT; struct { __IO uint32_t cfg_async_odt :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ASYNC_ODT_TypeDef; typedef union{ /*!< CFG_ZQ_CAL_DURATION register definition*/ __IO uint32_t CFG_ZQ_CAL_DURATION; struct { __IO uint32_t cfg_zq_cal_duration :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_ZQ_CAL_DURATION_TypeDef; typedef union{ /*!< CFG_MRRI register definition*/ __IO uint32_t CFG_MRRI; struct { __IO uint32_t cfg_mrri :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_MRRI_TypeDef; typedef union{ /*!< INIT_ODT_FORCE_EN register definition*/ __IO uint32_t INIT_ODT_FORCE_EN; struct { __IO uint32_t init_odt_force_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_ODT_FORCE_EN_TypeDef; typedef union{ /*!< INIT_ODT_FORCE_RANK register definition*/ __IO uint32_t INIT_ODT_FORCE_RANK; struct { __IO uint32_t init_odt_force_rank :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_INIT_ODT_FORCE_RANK_TypeDef; typedef union{ /*!< CFG_PHYUPD_ACK_DELAY register definition*/ __IO uint32_t CFG_PHYUPD_ACK_DELAY; struct { __IO uint32_t cfg_phyupd_ack_delay :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_CFG_PHYUPD_ACK_DELAY_TypeDef; typedef union{ /*!< CFG_MIRROR_X16_BG0_BG1 register definition*/ __IO uint32_t CFG_MIRROR_X16_BG0_BG1; struct { __IO uint32_t cfg_mirror_x16_bg0_bg1 :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_MIRROR_X16_BG0_BG1_TypeDef; typedef union{ /*!< INIT_PDA_MR_W_REQ register definition*/ __IO uint32_t INIT_PDA_MR_W_REQ; struct { __IO uint32_t init_pda_mr_w_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_PDA_MR_W_REQ_TypeDef; typedef union{ /*!< INIT_PDA_NIBBLE_SELECT register definition*/ __IO uint32_t INIT_PDA_NIBBLE_SELECT; struct { __IO uint32_t init_pda_nibble_select :18; __I uint32_t reserved :14; } bitfield; } DDR_CSR_APB_INIT_PDA_NIBBLE_SELECT_TypeDef; typedef union{ /*!< CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH register definition*/ __IO uint32_t CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH; struct { __IO uint32_t cfg_dram_clk_disable_in_self_refresh :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH_TypeDef; typedef union{ /*!< CFG_CKSRE register definition*/ __IO uint32_t CFG_CKSRE; struct { __IO uint32_t cfg_cksre :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_CKSRE_TypeDef; typedef union{ /*!< CFG_CKSRX register definition*/ __IO uint32_t CFG_CKSRX; struct { __IO uint32_t cfg_cksrx :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_CKSRX_TypeDef; typedef union{ /*!< CFG_RCD_STAB register definition*/ __IO uint32_t CFG_RCD_STAB; struct { __IO uint32_t cfg_rcd_stab :14; __I uint32_t reserved :18; } bitfield; } DDR_CSR_APB_CFG_RCD_STAB_TypeDef; typedef union{ /*!< CFG_DFI_T_CTRL_DELAY register definition*/ __IO uint32_t CFG_DFI_T_CTRL_DELAY; struct { __IO uint32_t cfg_dfi_t_ctrl_delay :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_DFI_T_CTRL_DELAY_TypeDef; typedef union{ /*!< CFG_DFI_T_DRAM_CLK_ENABLE register definition*/ __IO uint32_t CFG_DFI_T_DRAM_CLK_ENABLE; struct { __IO uint32_t cfg_dfi_t_dram_clk_enable :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_DFI_T_DRAM_CLK_ENABLE_TypeDef; typedef union{ /*!< CFG_IDLE_TIME_TO_SELF_REFRESH register definition*/ __IO uint32_t CFG_IDLE_TIME_TO_SELF_REFRESH; struct { __IO uint32_t cfg_idle_time_to_self_refresh :32; } bitfield; } DDR_CSR_APB_CFG_IDLE_TIME_TO_SELF_REFRESH_TypeDef; typedef union{ /*!< CFG_IDLE_TIME_TO_POWER_DOWN register definition*/ __IO uint32_t CFG_IDLE_TIME_TO_POWER_DOWN; struct { __IO uint32_t cfg_idle_time_to_power_down :32; } bitfield; } DDR_CSR_APB_CFG_IDLE_TIME_TO_POWER_DOWN_TypeDef; typedef union{ /*!< CFG_BURST_RW_REFRESH_HOLDOFF register definition*/ __IO uint32_t CFG_BURST_RW_REFRESH_HOLDOFF; struct { __IO uint32_t cfg_burst_rw_refresh_holdoff :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_BURST_RW_REFRESH_HOLDOFF_TypeDef; typedef union{ /*!< INIT_REFRESH_COUNT register definition*/ __I uint32_t INIT_REFRESH_COUNT; struct { __I uint32_t init_refresh_count :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_INIT_REFRESH_COUNT_TypeDef; typedef union{ /*!< CFG_BG_INTERLEAVE register definition*/ __IO uint32_t CFG_BG_INTERLEAVE; struct { __IO uint32_t cfg_bg_interleave :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_BG_INTERLEAVE_TypeDef; typedef union{ /*!< CFG_REFRESH_DURING_PHY_TRAINING register definition*/ __IO uint32_t CFG_REFRESH_DURING_PHY_TRAINING; struct { __IO uint32_t cfg_refresh_during_phy_training :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_REFRESH_DURING_PHY_TRAINING_TypeDef; typedef union{ /*!< MT_EN register definition*/ __IO uint32_t MT_EN; struct { __IO uint32_t mt_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_EN_TypeDef; typedef union{ /*!< MT_EN_SINGLE register definition*/ __IO uint32_t MT_EN_SINGLE; struct { __IO uint32_t mt_en_single :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_EN_SINGLE_TypeDef; typedef union{ /*!< MT_STOP_ON_ERROR register definition*/ __IO uint32_t MT_STOP_ON_ERROR; struct { __IO uint32_t mt_stop_on_error :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_STOP_ON_ERROR_TypeDef; typedef union{ /*!< MT_RD_ONLY register definition*/ __IO uint32_t MT_RD_ONLY; struct { __IO uint32_t mt_rd_only :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_RD_ONLY_TypeDef; typedef union{ /*!< MT_WR_ONLY register definition*/ __IO uint32_t MT_WR_ONLY; struct { __IO uint32_t mt_wr_only :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_WR_ONLY_TypeDef; typedef union{ /*!< MT_DATA_PATTERN register definition*/ __IO uint32_t MT_DATA_PATTERN; struct { __IO uint32_t mt_data_pattern :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_MT_DATA_PATTERN_TypeDef; typedef union{ /*!< MT_ADDR_PATTERN register definition*/ __IO uint32_t MT_ADDR_PATTERN; struct { __IO uint32_t mt_addr_pattern :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_MT_ADDR_PATTERN_TypeDef; typedef union{ /*!< MT_DATA_INVERT register definition*/ __IO uint32_t MT_DATA_INVERT; struct { __IO uint32_t mt_data_invert :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_DATA_INVERT_TypeDef; typedef union{ /*!< MT_ADDR_BITS register definition*/ __IO uint32_t MT_ADDR_BITS; struct { __IO uint32_t mt_addr_bits :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_MT_ADDR_BITS_TypeDef; typedef union{ /*!< MT_ERROR_STS register definition*/ __I uint32_t MT_ERROR_STS; struct { __I uint32_t mt_error_sts :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_ERROR_STS_TypeDef; typedef union{ /*!< MT_DONE_ACK register definition*/ __I uint32_t MT_DONE_ACK; struct { __I uint32_t mt_done_ack :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_DONE_ACK_TypeDef; typedef union{ /*!< MT_START_ADDR_0 register definition*/ __IO uint32_t MT_START_ADDR_0; struct { __IO uint32_t mt_start_addr_0 :32; } bitfield; } DDR_CSR_APB_MT_START_ADDR_0_TypeDef; typedef union{ /*!< MT_START_ADDR_1 register definition*/ __IO uint32_t MT_START_ADDR_1; struct { __IO uint32_t mt_start_addr_1 :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_MT_START_ADDR_1_TypeDef; typedef union{ /*!< MT_ERROR_MASK_0 register definition*/ __IO uint32_t MT_ERROR_MASK_0; struct { __IO uint32_t mt_error_mask_0 :32; } bitfield; } DDR_CSR_APB_MT_ERROR_MASK_0_TypeDef; typedef union{ /*!< MT_ERROR_MASK_1 register definition*/ __IO uint32_t MT_ERROR_MASK_1; struct { __IO uint32_t mt_error_mask_1 :32; } bitfield; } DDR_CSR_APB_MT_ERROR_MASK_1_TypeDef; typedef union{ /*!< MT_ERROR_MASK_2 register definition*/ __IO uint32_t MT_ERROR_MASK_2; struct { __IO uint32_t mt_error_mask_2 :32; } bitfield; } DDR_CSR_APB_MT_ERROR_MASK_2_TypeDef; typedef union{ /*!< MT_ERROR_MASK_3 register definition*/ __IO uint32_t MT_ERROR_MASK_3; struct { __IO uint32_t mt_error_mask_3 :32; } bitfield; } DDR_CSR_APB_MT_ERROR_MASK_3_TypeDef; typedef union{ /*!< MT_ERROR_MASK_4 register definition*/ __IO uint32_t MT_ERROR_MASK_4; struct { __IO uint32_t mt_error_mask_4 :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_MT_ERROR_MASK_4_TypeDef; typedef union{ /*!< MT_USER_DATA_PATTERN register definition*/ __IO uint32_t MT_USER_DATA_PATTERN; struct { __IO uint32_t mt_user_data_pattern :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_MT_USER_DATA_PATTERN_TypeDef; typedef union{ /*!< MT_ALG_AUTO_PCH register definition*/ __IO uint32_t MT_ALG_AUTO_PCH; struct { __IO uint32_t mt_alg_auto_pch :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MT_ALG_AUTO_PCH_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P0 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P0; struct { __IO uint32_t cfg_starve_timeout_p0 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P0_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P1 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P1; struct { __IO uint32_t cfg_starve_timeout_p1 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P1_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P2 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P2; struct { __IO uint32_t cfg_starve_timeout_p2 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P2_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P3 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P3; struct { __IO uint32_t cfg_starve_timeout_p3 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P3_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P4 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P4; struct { __IO uint32_t cfg_starve_timeout_p4 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P4_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P5 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P5; struct { __IO uint32_t cfg_starve_timeout_p5 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P5_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P6 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P6; struct { __IO uint32_t cfg_starve_timeout_p6 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P6_TypeDef; typedef union{ /*!< CFG_STARVE_TIMEOUT_P7 register definition*/ __IO uint32_t CFG_STARVE_TIMEOUT_P7; struct { __IO uint32_t cfg_starve_timeout_p7 :12; __I uint32_t reserved :20; } bitfield; } DDR_CSR_APB_CFG_STARVE_TIMEOUT_P7_TypeDef; typedef union{ /*!< CFG_REORDER_EN register definition*/ __IO uint32_t CFG_REORDER_EN; struct { __IO uint32_t cfg_reorder_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_REORDER_EN_TypeDef; typedef union{ /*!< CFG_REORDER_QUEUE_EN register definition*/ __IO uint32_t CFG_REORDER_QUEUE_EN; struct { __IO uint32_t cfg_reorder_queue_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_REORDER_QUEUE_EN_TypeDef; typedef union{ /*!< CFG_INTRAPORT_REORDER_EN register definition*/ __IO uint32_t CFG_INTRAPORT_REORDER_EN; struct { __IO uint32_t cfg_intraport_reorder_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_INTRAPORT_REORDER_EN_TypeDef; typedef union{ /*!< CFG_MAINTAIN_COHERENCY register definition*/ __IO uint32_t CFG_MAINTAIN_COHERENCY; struct { __IO uint32_t cfg_maintain_coherency :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_MAINTAIN_COHERENCY_TypeDef; typedef union{ /*!< CFG_Q_AGE_LIMIT register definition*/ __IO uint32_t CFG_Q_AGE_LIMIT; struct { __IO uint32_t cfg_q_age_limit :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_Q_AGE_LIMIT_TypeDef; typedef union{ /*!< CFG_RO_CLOSED_PAGE_POLICY register definition*/ __IO uint32_t CFG_RO_CLOSED_PAGE_POLICY; struct { __IO uint32_t cfg_ro_closed_page_policy :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RO_CLOSED_PAGE_POLICY_TypeDef; typedef union{ /*!< CFG_REORDER_RW_ONLY register definition*/ __IO uint32_t CFG_REORDER_RW_ONLY; struct { __IO uint32_t cfg_reorder_rw_only :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_REORDER_RW_ONLY_TypeDef; typedef union{ /*!< CFG_RO_PRIORITY_EN register definition*/ __IO uint32_t CFG_RO_PRIORITY_EN; struct { __IO uint32_t cfg_ro_priority_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RO_PRIORITY_EN_TypeDef; typedef union{ /*!< CFG_DM_EN register definition*/ __IO uint32_t CFG_DM_EN; struct { __IO uint32_t cfg_dm_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DM_EN_TypeDef; typedef union{ /*!< CFG_RMW_EN register definition*/ __IO uint32_t CFG_RMW_EN; struct { __IO uint32_t cfg_rmw_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_RMW_EN_TypeDef; typedef union{ /*!< CFG_ECC_CORRECTION_EN register definition*/ __IO uint32_t CFG_ECC_CORRECTION_EN; struct { __IO uint32_t cfg_ecc_correction_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ECC_CORRECTION_EN_TypeDef; typedef union{ /*!< CFG_ECC_BYPASS register definition*/ __IO uint32_t CFG_ECC_BYPASS; struct { __IO uint32_t cfg_ecc_bypass :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ECC_BYPASS_TypeDef; typedef union{ /*!< INIT_WRITE_DATA_1B_ECC_ERROR_GEN register definition*/ __IO uint32_t INIT_WRITE_DATA_1B_ECC_ERROR_GEN; struct { __IO uint32_t init_write_data_1b_ecc_error_gen :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_INIT_WRITE_DATA_1B_ECC_ERROR_GEN_TypeDef; typedef union{ /*!< INIT_WRITE_DATA_2B_ECC_ERROR_GEN register definition*/ __IO uint32_t INIT_WRITE_DATA_2B_ECC_ERROR_GEN; struct { __IO uint32_t init_write_data_2b_ecc_error_gen :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_INIT_WRITE_DATA_2B_ECC_ERROR_GEN_TypeDef; typedef union{ /*!< CFG_ECC_1BIT_INT_THRESH register definition*/ __IO uint32_t CFG_ECC_1BIT_INT_THRESH; struct { __IO uint32_t cfg_ecc_1bit_int_thresh :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_CFG_ECC_1BIT_INT_THRESH_TypeDef; typedef union{ /*!< STAT_INT_ECC_1BIT_THRESH register definition*/ __I uint32_t STAT_INT_ECC_1BIT_THRESH; struct { __I uint32_t stat_int_ecc_1bit_thresh :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_INT_ECC_1BIT_THRESH_TypeDef; typedef union{ /*!< INIT_READ_CAPTURE_ADDR register definition*/ __IO uint32_t INIT_READ_CAPTURE_ADDR; struct { __IO uint32_t init_read_capture_addr :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_INIT_READ_CAPTURE_ADDR_TypeDef; typedef union{ /*!< INIT_READ_CAPTURE_DATA_0 register definition*/ __I uint32_t INIT_READ_CAPTURE_DATA_0; struct { __I uint32_t init_read_capture_data_0 :32; } bitfield; } DDR_CSR_APB_INIT_READ_CAPTURE_DATA_0_TypeDef; typedef union{ /*!< INIT_READ_CAPTURE_DATA_1 register definition*/ __I uint32_t INIT_READ_CAPTURE_DATA_1; struct { __I uint32_t init_read_capture_data_1 :32; } bitfield; } DDR_CSR_APB_INIT_READ_CAPTURE_DATA_1_TypeDef; typedef union{ /*!< INIT_READ_CAPTURE_DATA_2 register definition*/ __I uint32_t INIT_READ_CAPTURE_DATA_2; struct { __I uint32_t init_read_capture_data_2 :32; } bitfield; } DDR_CSR_APB_INIT_READ_CAPTURE_DATA_2_TypeDef; typedef union{ /*!< INIT_READ_CAPTURE_DATA_3 register definition*/ __I uint32_t INIT_READ_CAPTURE_DATA_3; struct { __I uint32_t init_read_capture_data_3 :32; } bitfield; } DDR_CSR_APB_INIT_READ_CAPTURE_DATA_3_TypeDef; typedef union{ /*!< INIT_READ_CAPTURE_DATA_4 register definition*/ __I uint32_t INIT_READ_CAPTURE_DATA_4; struct { __I uint32_t init_read_capture_data_4 :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_INIT_READ_CAPTURE_DATA_4_TypeDef; typedef union{ /*!< CFG_ERROR_GROUP_SEL register definition*/ __IO uint32_t CFG_ERROR_GROUP_SEL; struct { __IO uint32_t cfg_error_group_sel :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ERROR_GROUP_SEL_TypeDef; typedef union{ /*!< CFG_DATA_SEL register definition*/ __IO uint32_t CFG_DATA_SEL; struct { __IO uint32_t cfg_data_sel :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_DATA_SEL_TypeDef; typedef union{ /*!< CFG_TRIG_MODE register definition*/ __IO uint32_t CFG_TRIG_MODE; struct { __IO uint32_t cfg_trig_mode :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_TRIG_MODE_TypeDef; typedef union{ /*!< CFG_POST_TRIG_CYCS register definition*/ __IO uint32_t CFG_POST_TRIG_CYCS; struct { __IO uint32_t cfg_post_trig_cycs :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_POST_TRIG_CYCS_TypeDef; typedef union{ /*!< CFG_TRIG_MASK register definition*/ __IO uint32_t CFG_TRIG_MASK; struct { __IO uint32_t cfg_trig_mask :3; __I uint32_t reserved :29; } bitfield; } DDR_CSR_APB_CFG_TRIG_MASK_TypeDef; typedef union{ /*!< CFG_EN_MASK register definition*/ __IO uint32_t CFG_EN_MASK; struct { __IO uint32_t cfg_en_mask :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_EN_MASK_TypeDef; typedef union{ /*!< MTC_ACQ_ADDR register definition*/ __IO uint32_t MTC_ACQ_ADDR; struct { __IO uint32_t mtc_acq_addr :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_MTC_ACQ_ADDR_TypeDef; typedef union{ /*!< MTC_ACQ_CYCS_STORED register definition*/ __I uint32_t MTC_ACQ_CYCS_STORED; struct { __I uint32_t mtc_acq_cycs_stored :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_MTC_ACQ_CYCS_STORED_TypeDef; typedef union{ /*!< MTC_ACQ_TRIG_DETECT register definition*/ __I uint32_t MTC_ACQ_TRIG_DETECT; struct { __I uint32_t mtc_acq_trig_detect :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MTC_ACQ_TRIG_DETECT_TypeDef; typedef union{ /*!< MTC_ACQ_MEM_TRIG_ADDR register definition*/ __I uint32_t MTC_ACQ_MEM_TRIG_ADDR; struct { __I uint32_t mtc_acq_mem_trig_addr :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_MTC_ACQ_MEM_TRIG_ADDR_TypeDef; typedef union{ /*!< MTC_ACQ_MEM_LAST_ADDR register definition*/ __I uint32_t MTC_ACQ_MEM_LAST_ADDR; struct { __I uint32_t mtc_acq_mem_last_addr :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_MTC_ACQ_MEM_LAST_ADDR_TypeDef; typedef union{ /*!< MTC_ACK register definition*/ __I uint32_t MTC_ACK; struct { __I uint32_t mtc_ack :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MTC_ACK_TypeDef; typedef union{ /*!< CFG_TRIG_MT_ADDR_0 register definition*/ __IO uint32_t CFG_TRIG_MT_ADDR_0; struct { __IO uint32_t cfg_trig_mt_addr_0 :32; } bitfield; } DDR_CSR_APB_CFG_TRIG_MT_ADDR_0_TypeDef; typedef union{ /*!< CFG_TRIG_MT_ADDR_1 register definition*/ __IO uint32_t CFG_TRIG_MT_ADDR_1; struct { __IO uint32_t cfg_trig_mt_addr_1 :7; __I uint32_t reserved :25; } bitfield; } DDR_CSR_APB_CFG_TRIG_MT_ADDR_1_TypeDef; typedef union{ /*!< CFG_TRIG_ERR_MASK_0 register definition*/ __IO uint32_t CFG_TRIG_ERR_MASK_0; struct { __IO uint32_t cfg_trig_err_mask_0 :32; } bitfield; } DDR_CSR_APB_CFG_TRIG_ERR_MASK_0_TypeDef; typedef union{ /*!< CFG_TRIG_ERR_MASK_1 register definition*/ __IO uint32_t CFG_TRIG_ERR_MASK_1; struct { __IO uint32_t cfg_trig_err_mask_1 :32; } bitfield; } DDR_CSR_APB_CFG_TRIG_ERR_MASK_1_TypeDef; typedef union{ /*!< CFG_TRIG_ERR_MASK_2 register definition*/ __IO uint32_t CFG_TRIG_ERR_MASK_2; struct { __IO uint32_t cfg_trig_err_mask_2 :32; } bitfield; } DDR_CSR_APB_CFG_TRIG_ERR_MASK_2_TypeDef; typedef union{ /*!< CFG_TRIG_ERR_MASK_3 register definition*/ __IO uint32_t CFG_TRIG_ERR_MASK_3; struct { __IO uint32_t cfg_trig_err_mask_3 :32; } bitfield; } DDR_CSR_APB_CFG_TRIG_ERR_MASK_3_TypeDef; typedef union{ /*!< CFG_TRIG_ERR_MASK_4 register definition*/ __IO uint32_t CFG_TRIG_ERR_MASK_4; struct { __IO uint32_t cfg_trig_err_mask_4 :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_CFG_TRIG_ERR_MASK_4_TypeDef; typedef union{ /*!< MTC_ACQ_WR_DATA_0 register definition*/ __IO uint32_t MTC_ACQ_WR_DATA_0; struct { __IO uint32_t mtc_acq_wr_data_0 :32; } bitfield; } DDR_CSR_APB_MTC_ACQ_WR_DATA_0_TypeDef; typedef union{ /*!< MTC_ACQ_WR_DATA_1 register definition*/ __IO uint32_t MTC_ACQ_WR_DATA_1; struct { __IO uint32_t mtc_acq_wr_data_1 :32; } bitfield; } DDR_CSR_APB_MTC_ACQ_WR_DATA_1_TypeDef; typedef union{ /*!< MTC_ACQ_WR_DATA_2 register definition*/ __IO uint32_t MTC_ACQ_WR_DATA_2; struct { __IO uint32_t mtc_acq_wr_data_2 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_MTC_ACQ_WR_DATA_2_TypeDef; typedef union{ /*!< MTC_ACQ_RD_DATA_0 register definition*/ __I uint32_t MTC_ACQ_RD_DATA_0; struct { __I uint32_t mtc_acq_rd_data_0 :32; } bitfield; } DDR_CSR_APB_MTC_ACQ_RD_DATA_0_TypeDef; typedef union{ /*!< MTC_ACQ_RD_DATA_1 register definition*/ __I uint32_t MTC_ACQ_RD_DATA_1; struct { __I uint32_t mtc_acq_rd_data_1 :32; } bitfield; } DDR_CSR_APB_MTC_ACQ_RD_DATA_1_TypeDef; typedef union{ /*!< MTC_ACQ_RD_DATA_2 register definition*/ __I uint32_t MTC_ACQ_RD_DATA_2; struct { __I uint32_t mtc_acq_rd_data_2 :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_MTC_ACQ_RD_DATA_2_TypeDef; typedef union{ /*!< CFG_PRE_TRIG_CYCS register definition*/ __IO uint32_t CFG_PRE_TRIG_CYCS; struct { __IO uint32_t cfg_pre_trig_cycs :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_CFG_PRE_TRIG_CYCS_TypeDef; typedef union{ /*!< MTC_ACQ_ERROR_CNT register definition*/ __I uint32_t MTC_ACQ_ERROR_CNT; struct { __I uint32_t mtc_acq_error_cnt :10; __I uint32_t reserved :22; } bitfield; } DDR_CSR_APB_MTC_ACQ_ERROR_CNT_TypeDef; typedef union{ /*!< MTC_ACQ_ERROR_CNT_OVFL register definition*/ __I uint32_t MTC_ACQ_ERROR_CNT_OVFL; struct { __I uint32_t mtc_acq_error_cnt_ovfl :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_MTC_ACQ_ERROR_CNT_OVFL_TypeDef; typedef union{ /*!< CFG_DATA_SEL_FIRST_ERROR register definition*/ __IO uint32_t CFG_DATA_SEL_FIRST_ERROR; struct { __IO uint32_t cfg_data_sel_first_error :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DATA_SEL_FIRST_ERROR_TypeDef; typedef union{ /*!< CFG_DQ_WIDTH register definition*/ __IO uint32_t CFG_DQ_WIDTH; struct { __IO uint32_t cfg_dq_width :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_DQ_WIDTH_TypeDef; typedef union{ /*!< CFG_ACTIVE_DQ_SEL register definition*/ __IO uint32_t CFG_ACTIVE_DQ_SEL; struct { __IO uint32_t cfg_active_dq_sel :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_ACTIVE_DQ_SEL_TypeDef; typedef union{ /*!< STAT_CA_PARITY_ERROR register definition*/ __I uint32_t STAT_CA_PARITY_ERROR; struct { __I uint32_t stat_ca_parity_error :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_CA_PARITY_ERROR_TypeDef; typedef union{ /*!< INIT_CA_PARITY_ERROR_GEN_REQ register definition*/ __IO uint32_t INIT_CA_PARITY_ERROR_GEN_REQ; struct { __IO uint32_t init_ca_parity_error_gen_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_CA_PARITY_ERROR_GEN_REQ_TypeDef; typedef union{ /*!< INIT_CA_PARITY_ERROR_GEN_CMD register definition*/ __IO uint32_t INIT_CA_PARITY_ERROR_GEN_CMD; struct { __IO uint32_t init_ca_parity_error_gen_cmd :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_INIT_CA_PARITY_ERROR_GEN_CMD_TypeDef; typedef union{ /*!< INIT_CA_PARITY_ERROR_GEN_ACK register definition*/ __I uint32_t INIT_CA_PARITY_ERROR_GEN_ACK; struct { __I uint32_t init_ca_parity_error_gen_ack :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_CA_PARITY_ERROR_GEN_ACK_TypeDef; typedef union{ /*!< CFG_DFI_T_RDDATA_EN register definition*/ __IO uint32_t CFG_DFI_T_RDDATA_EN; struct { __IO uint32_t cfg_dfi_t_rddata_en :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_DFI_T_RDDATA_EN_TypeDef; typedef union{ /*!< CFG_DFI_T_PHY_RDLAT register definition*/ __IO uint32_t CFG_DFI_T_PHY_RDLAT; struct { __IO uint32_t cfg_dfi_t_phy_rdlat :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_DFI_T_PHY_RDLAT_TypeDef; typedef union{ /*!< CFG_DFI_T_PHY_WRLAT register definition*/ __IO uint32_t CFG_DFI_T_PHY_WRLAT; struct { __IO uint32_t cfg_dfi_t_phy_wrlat :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_CFG_DFI_T_PHY_WRLAT_TypeDef; typedef union{ /*!< CFG_DFI_PHYUPD_EN register definition*/ __IO uint32_t CFG_DFI_PHYUPD_EN; struct { __IO uint32_t cfg_dfi_phyupd_en :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DFI_PHYUPD_EN_TypeDef; typedef union{ /*!< INIT_DFI_LP_DATA_REQ register definition*/ __IO uint32_t INIT_DFI_LP_DATA_REQ; struct { __IO uint32_t init_dfi_lp_data_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_DFI_LP_DATA_REQ_TypeDef; typedef union{ /*!< INIT_DFI_LP_CTRL_REQ register definition*/ __IO uint32_t INIT_DFI_LP_CTRL_REQ; struct { __IO uint32_t init_dfi_lp_ctrl_req :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_INIT_DFI_LP_CTRL_REQ_TypeDef; typedef union{ /*!< STAT_DFI_LP_ACK register definition*/ __I uint32_t STAT_DFI_LP_ACK; struct { __I uint32_t stat_dfi_lp_ack :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_DFI_LP_ACK_TypeDef; typedef union{ /*!< INIT_DFI_LP_WAKEUP register definition*/ __IO uint32_t INIT_DFI_LP_WAKEUP; struct { __IO uint32_t init_dfi_lp_wakeup :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_INIT_DFI_LP_WAKEUP_TypeDef; typedef union{ /*!< INIT_DFI_DRAM_CLK_DISABLE register definition*/ __IO uint32_t INIT_DFI_DRAM_CLK_DISABLE; struct { __IO uint32_t init_dfi_dram_clk_disable :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_INIT_DFI_DRAM_CLK_DISABLE_TypeDef; typedef union{ /*!< STAT_DFI_TRAINING_ERROR register definition*/ __I uint32_t STAT_DFI_TRAINING_ERROR; struct { __I uint32_t stat_dfi_training_error :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_DFI_TRAINING_ERROR_TypeDef; typedef union{ /*!< STAT_DFI_ERROR register definition*/ __I uint32_t STAT_DFI_ERROR; struct { __I uint32_t stat_dfi_error :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_DFI_ERROR_TypeDef; typedef union{ /*!< STAT_DFI_ERROR_INFO register definition*/ __I uint32_t STAT_DFI_ERROR_INFO; struct { __I uint32_t stat_dfi_error_info :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_STAT_DFI_ERROR_INFO_TypeDef; typedef union{ /*!< CFG_DFI_DATA_BYTE_DISABLE register definition*/ __IO uint32_t CFG_DFI_DATA_BYTE_DISABLE; struct { __IO uint32_t cfg_dfi_data_byte_disable :5; __I uint32_t reserved :27; } bitfield; } DDR_CSR_APB_CFG_DFI_DATA_BYTE_DISABLE_TypeDef; typedef union{ /*!< STAT_DFI_INIT_COMPLETE register definition*/ __I uint32_t STAT_DFI_INIT_COMPLETE; struct { __I uint32_t stat_dfi_init_complete :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_DFI_INIT_COMPLETE_TypeDef; typedef union{ /*!< STAT_DFI_TRAINING_COMPLETE register definition*/ __I uint32_t STAT_DFI_TRAINING_COMPLETE; struct { __I uint32_t stat_dfi_training_complete :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_STAT_DFI_TRAINING_COMPLETE_TypeDef; typedef union{ /*!< CFG_DFI_LVL_SEL register definition*/ __IO uint32_t CFG_DFI_LVL_SEL; struct { __IO uint32_t cfg_dfi_lvl_sel :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DFI_LVL_SEL_TypeDef; typedef union{ /*!< CFG_DFI_LVL_PERIODIC register definition*/ __IO uint32_t CFG_DFI_LVL_PERIODIC; struct { __IO uint32_t cfg_dfi_lvl_periodic :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_DFI_LVL_PERIODIC_TypeDef; typedef union{ /*!< CFG_DFI_LVL_PATTERN register definition*/ __IO uint32_t CFG_DFI_LVL_PATTERN; struct { __IO uint32_t cfg_dfi_lvl_pattern :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_CFG_DFI_LVL_PATTERN_TypeDef; typedef union{ /*!< PHY_DFI_INIT_START register definition*/ __IO uint32_t PHY_DFI_INIT_START; struct { __IO uint32_t phy_dfi_init_start :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_DFI_INIT_START_TypeDef; typedef union{ /*!< CFG_AXI_START_ADDRESS_AXI1_0 register definition*/ __IO uint32_t CFG_AXI_START_ADDRESS_AXI1_0; struct { __IO uint32_t cfg_axi_start_address_axi1_0 :32; } bitfield; } DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI1_0_TypeDef; typedef union{ /*!< CFG_AXI_START_ADDRESS_AXI1_1 register definition*/ __IO uint32_t CFG_AXI_START_ADDRESS_AXI1_1; struct { __IO uint32_t cfg_axi_start_address_axi1_1 :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI1_1_TypeDef; typedef union{ /*!< CFG_AXI_START_ADDRESS_AXI2_0 register definition*/ __IO uint32_t CFG_AXI_START_ADDRESS_AXI2_0; struct { __IO uint32_t cfg_axi_start_address_axi2_0 :32; } bitfield; } DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI2_0_TypeDef; typedef union{ /*!< CFG_AXI_START_ADDRESS_AXI2_1 register definition*/ __IO uint32_t CFG_AXI_START_ADDRESS_AXI2_1; struct { __IO uint32_t cfg_axi_start_address_axi2_1 :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI2_1_TypeDef; typedef union{ /*!< CFG_AXI_END_ADDRESS_AXI1_0 register definition*/ __IO uint32_t CFG_AXI_END_ADDRESS_AXI1_0; struct { __IO uint32_t cfg_axi_end_address_axi1_0 :32; } bitfield; } DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI1_0_TypeDef; typedef union{ /*!< CFG_AXI_END_ADDRESS_AXI1_1 register definition*/ __IO uint32_t CFG_AXI_END_ADDRESS_AXI1_1; struct { __IO uint32_t cfg_axi_end_address_axi1_1 :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI1_1_TypeDef; typedef union{ /*!< CFG_AXI_END_ADDRESS_AXI2_0 register definition*/ __IO uint32_t CFG_AXI_END_ADDRESS_AXI2_0; struct { __IO uint32_t cfg_axi_end_address_axi2_0 :32; } bitfield; } DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI2_0_TypeDef; typedef union{ /*!< CFG_AXI_END_ADDRESS_AXI2_1 register definition*/ __IO uint32_t CFG_AXI_END_ADDRESS_AXI2_1; struct { __IO uint32_t cfg_axi_end_address_axi2_1 :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI2_1_TypeDef; typedef union{ /*!< CFG_MEM_START_ADDRESS_AXI1_0 register definition*/ __IO uint32_t CFG_MEM_START_ADDRESS_AXI1_0; struct { __IO uint32_t cfg_mem_start_address_axi1_0 :32; } bitfield; } DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI1_0_TypeDef; typedef union{ /*!< CFG_MEM_START_ADDRESS_AXI1_1 register definition*/ __IO uint32_t CFG_MEM_START_ADDRESS_AXI1_1; struct { __IO uint32_t cfg_mem_start_address_axi1_1 :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI1_1_TypeDef; typedef union{ /*!< CFG_MEM_START_ADDRESS_AXI2_0 register definition*/ __IO uint32_t CFG_MEM_START_ADDRESS_AXI2_0; struct { __IO uint32_t cfg_mem_start_address_axi2_0 :32; } bitfield; } DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI2_0_TypeDef; typedef union{ /*!< CFG_MEM_START_ADDRESS_AXI2_1 register definition*/ __IO uint32_t CFG_MEM_START_ADDRESS_AXI2_1; struct { __IO uint32_t cfg_mem_start_address_axi2_1 :2; __I uint32_t reserved :30; } bitfield; } DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI2_1_TypeDef; typedef union{ /*!< CFG_ENABLE_BUS_HOLD_AXI1 register definition*/ __IO uint32_t CFG_ENABLE_BUS_HOLD_AXI1; struct { __IO uint32_t cfg_enable_bus_hold_axi1 :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ENABLE_BUS_HOLD_AXI1_TypeDef; typedef union{ /*!< CFG_ENABLE_BUS_HOLD_AXI2 register definition*/ __IO uint32_t CFG_ENABLE_BUS_HOLD_AXI2; struct { __IO uint32_t cfg_enable_bus_hold_axi2 :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_CFG_ENABLE_BUS_HOLD_AXI2_TypeDef; typedef union{ /*!< CFG_AXI_AUTO_PCH register definition*/ __IO uint32_t CFG_AXI_AUTO_PCH; struct { __IO uint32_t cfg_axi_auto_pch :32; } bitfield; } DDR_CSR_APB_CFG_AXI_AUTO_PCH_TypeDef; typedef union{ /*!< PHY_RESET_CONTROL register definition*/ __IO uint32_t PHY_RESET_CONTROL; struct { __IO uint32_t phy_reset_control :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_PHY_RESET_CONTROL_TypeDef; typedef union{ /*!< PHY_PC_RANK register definition*/ __IO uint32_t PHY_PC_RANK; struct { __IO uint32_t phy_pc_rank :4; __I uint32_t reserved :28; } bitfield; } DDR_CSR_APB_PHY_PC_RANK_TypeDef; typedef union{ /*!< PHY_RANKS_TO_TRAIN register definition*/ __IO uint32_t PHY_RANKS_TO_TRAIN; struct { __IO uint32_t phy_ranks_to_train :16; __I uint32_t reserved :16; } bitfield; } DDR_CSR_APB_PHY_RANKS_TO_TRAIN_TypeDef; typedef union{ /*!< PHY_WRITE_REQUEST register definition*/ __IO uint32_t PHY_WRITE_REQUEST; struct { __IO uint32_t phy_write_request :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_WRITE_REQUEST_TypeDef; typedef union{ /*!< PHY_WRITE_REQUEST_DONE register definition*/ __I uint32_t PHY_WRITE_REQUEST_DONE; struct { __I uint32_t phy_write_request_done :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_WRITE_REQUEST_DONE_TypeDef; typedef union{ /*!< PHY_READ_REQUEST register definition*/ __IO uint32_t PHY_READ_REQUEST; struct { __IO uint32_t phy_read_request :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_READ_REQUEST_TypeDef; typedef union{ /*!< PHY_READ_REQUEST_DONE register definition*/ __I uint32_t PHY_READ_REQUEST_DONE; struct { __I uint32_t phy_read_request_done :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_READ_REQUEST_DONE_TypeDef; typedef union{ /*!< PHY_WRITE_LEVEL_DELAY register definition*/ __IO uint32_t PHY_WRITE_LEVEL_DELAY; struct { __IO uint32_t phy_write_level_delay :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_PHY_WRITE_LEVEL_DELAY_TypeDef; typedef union{ /*!< PHY_GATE_TRAIN_DELAY register definition*/ __IO uint32_t PHY_GATE_TRAIN_DELAY; struct { __IO uint32_t phy_gate_train_delay :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_PHY_GATE_TRAIN_DELAY_TypeDef; typedef union{ /*!< PHY_EYE_TRAIN_DELAY register definition*/ __IO uint32_t PHY_EYE_TRAIN_DELAY; struct { __IO uint32_t phy_eye_train_delay :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_PHY_EYE_TRAIN_DELAY_TypeDef; typedef union{ /*!< PHY_EYE_PAT register definition*/ __IO uint32_t PHY_EYE_PAT; struct { __IO uint32_t phy_eye_pat :8; __I uint32_t reserved :24; } bitfield; } DDR_CSR_APB_PHY_EYE_PAT_TypeDef; typedef union{ /*!< PHY_START_RECAL register definition*/ __IO uint32_t PHY_START_RECAL; struct { __IO uint32_t phy_start_recal :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_START_RECAL_TypeDef; typedef union{ /*!< PHY_CLR_DFI_LVL_PERIODIC register definition*/ __IO uint32_t PHY_CLR_DFI_LVL_PERIODIC; struct { __IO uint32_t phy_clr_dfi_lvl_periodic :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_CLR_DFI_LVL_PERIODIC_TypeDef; typedef union{ /*!< PHY_TRAIN_STEP_ENABLE register definition*/ __IO uint32_t PHY_TRAIN_STEP_ENABLE; struct { __IO uint32_t phy_train_step_enable :6; __I uint32_t reserved :26; } bitfield; } DDR_CSR_APB_PHY_TRAIN_STEP_ENABLE_TypeDef; typedef union{ /*!< PHY_LPDDR_DQ_CAL_PAT register definition*/ __IO uint32_t PHY_LPDDR_DQ_CAL_PAT; struct { __IO uint32_t phy_lpddr_dq_cal_pat :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_LPDDR_DQ_CAL_PAT_TypeDef; typedef union{ /*!< PHY_INDPNDT_TRAINING register definition*/ __IO uint32_t PHY_INDPNDT_TRAINING; struct { __IO uint32_t phy_indpndt_training :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_INDPNDT_TRAINING_TypeDef; typedef union{ /*!< PHY_ENCODED_QUAD_CS register definition*/ __IO uint32_t PHY_ENCODED_QUAD_CS; struct { __IO uint32_t phy_encoded_quad_cs :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_ENCODED_QUAD_CS_TypeDef; typedef union{ /*!< PHY_HALF_CLK_DLY_ENABLE register definition*/ __IO uint32_t PHY_HALF_CLK_DLY_ENABLE; struct { __IO uint32_t phy_half_clk_dly_enable :1; __I uint32_t reserved :31; } bitfield; } DDR_CSR_APB_PHY_HALF_CLK_DLY_ENABLE_TypeDef; /*------------ ADDR_MAP register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_MANUAL_ADDRESS_MAP_TypeDef CFG_MANUAL_ADDRESS_MAP; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_CHIPADDR_MAP_TypeDef CFG_CHIPADDR_MAP; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_CIDADDR_MAP_TypeDef CFG_CIDADDR_MAP; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_MB_AUTOPCH_COL_BIT_POS_LOW_TypeDef CFG_MB_AUTOPCH_COL_BIT_POS_LOW; /*!< Offset: 0xc */ __IO DDR_CSR_APB_CFG_MB_AUTOPCH_COL_BIT_POS_HIGH_TypeDef CFG_MB_AUTOPCH_COL_BIT_POS_HIGH; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_CFG_BANKADDR_MAP_0_TypeDef CFG_BANKADDR_MAP_0; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_CFG_BANKADDR_MAP_1_TypeDef CFG_BANKADDR_MAP_1; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_CFG_ROWADDR_MAP_0_TypeDef CFG_ROWADDR_MAP_0; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_CFG_ROWADDR_MAP_1_TypeDef CFG_ROWADDR_MAP_1; /*!< Offset: 0x20 */ __IO DDR_CSR_APB_CFG_ROWADDR_MAP_2_TypeDef CFG_ROWADDR_MAP_2; /*!< Offset: 0x24 */ __IO DDR_CSR_APB_CFG_ROWADDR_MAP_3_TypeDef CFG_ROWADDR_MAP_3; /*!< Offset: 0x28 */ __IO DDR_CSR_APB_CFG_COLADDR_MAP_0_TypeDef CFG_COLADDR_MAP_0; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_CFG_COLADDR_MAP_1_TypeDef CFG_COLADDR_MAP_1; /*!< Offset: 0x30 */ __IO DDR_CSR_APB_CFG_COLADDR_MAP_2_TypeDef CFG_COLADDR_MAP_2; /*!< Offset: 0x34 */ } DDR_CSR_APB_ADDR_MAP_TypeDef; /*------------ MC_BASE3 register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_VRCG_ENABLE_TypeDef CFG_VRCG_ENABLE; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_VRCG_DISABLE_TypeDef CFG_VRCG_DISABLE; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_WRITE_LATENCY_SET_TypeDef CFG_WRITE_LATENCY_SET; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_THERMAL_OFFSET_TypeDef CFG_THERMAL_OFFSET; /*!< Offset: 0xc */ __IO DDR_CSR_APB_CFG_SOC_ODT_TypeDef CFG_SOC_ODT; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_CFG_ODTE_CK_TypeDef CFG_ODTE_CK; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_CFG_ODTE_CS_TypeDef CFG_ODTE_CS; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_CFG_ODTD_CA_TypeDef CFG_ODTD_CA; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_CFG_LPDDR4_FSP_OP_TypeDef CFG_LPDDR4_FSP_OP; /*!< Offset: 0x20 */ __IO DDR_CSR_APB_CFG_GENERATE_REFRESH_ON_SRX_TypeDef CFG_GENERATE_REFRESH_ON_SRX; /*!< Offset: 0x24 */ __IO DDR_CSR_APB_CFG_DBI_CL_TypeDef CFG_DBI_CL; /*!< Offset: 0x28 */ __IO DDR_CSR_APB_CFG_NON_DBI_CL_TypeDef CFG_NON_DBI_CL; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_INIT_FORCE_WRITE_DATA_0_TypeDef INIT_FORCE_WRITE_DATA_0; /*!< Offset: 0x30 */ __I uint32_t UNUSED_SPACE0[63]; /*!< Offset: 0x34 */ } DDR_CSR_APB_MC_BASE3_TypeDef; /*------------ MC_BASE1 register bundle definition -----------*/ typedef struct /*!< Offset: 0x3c00 */ { __IO DDR_CSR_APB_CFG_WRITE_CRC_TypeDef CFG_WRITE_CRC; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_MPR_READ_FORMAT_TypeDef CFG_MPR_READ_FORMAT; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_WR_CMD_LAT_CRC_DM_TypeDef CFG_WR_CMD_LAT_CRC_DM; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_FINE_GRAN_REF_MODE_TypeDef CFG_FINE_GRAN_REF_MODE; /*!< Offset: 0xc */ __IO DDR_CSR_APB_CFG_TEMP_SENSOR_READOUT_TypeDef CFG_TEMP_SENSOR_READOUT; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_CFG_PER_DRAM_ADDR_EN_TypeDef CFG_PER_DRAM_ADDR_EN; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_CFG_GEARDOWN_MODE_TypeDef CFG_GEARDOWN_MODE; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_CFG_WR_PREAMBLE_TypeDef CFG_WR_PREAMBLE; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_CFG_RD_PREAMBLE_TypeDef CFG_RD_PREAMBLE; /*!< Offset: 0x20 */ __IO DDR_CSR_APB_CFG_RD_PREAMB_TRN_MODE_TypeDef CFG_RD_PREAMB_TRN_MODE; /*!< Offset: 0x24 */ __IO DDR_CSR_APB_CFG_SR_ABORT_TypeDef CFG_SR_ABORT; /*!< Offset: 0x28 */ __IO DDR_CSR_APB_CFG_CS_TO_CMDADDR_LATENCY_TypeDef CFG_CS_TO_CMDADDR_LATENCY; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_CFG_INT_VREF_MON_TypeDef CFG_INT_VREF_MON; /*!< Offset: 0x30 */ __IO DDR_CSR_APB_CFG_TEMP_CTRL_REF_MODE_TypeDef CFG_TEMP_CTRL_REF_MODE; /*!< Offset: 0x34 */ __IO DDR_CSR_APB_CFG_TEMP_CTRL_REF_RANGE_TypeDef CFG_TEMP_CTRL_REF_RANGE; /*!< Offset: 0x38 */ __IO DDR_CSR_APB_CFG_MAX_PWR_DOWN_MODE_TypeDef CFG_MAX_PWR_DOWN_MODE; /*!< Offset: 0x3c */ __IO DDR_CSR_APB_CFG_READ_DBI_TypeDef CFG_READ_DBI; /*!< Offset: 0x40 */ __IO DDR_CSR_APB_CFG_WRITE_DBI_TypeDef CFG_WRITE_DBI; /*!< Offset: 0x44 */ __IO DDR_CSR_APB_CFG_DATA_MASK_TypeDef CFG_DATA_MASK; /*!< Offset: 0x48 */ __IO DDR_CSR_APB_CFG_CA_PARITY_PERSIST_ERR_TypeDef CFG_CA_PARITY_PERSIST_ERR; /*!< Offset: 0x4c */ __IO DDR_CSR_APB_CFG_RTT_PARK_TypeDef CFG_RTT_PARK; /*!< Offset: 0x50 */ __IO DDR_CSR_APB_CFG_ODT_INBUF_4_PD_TypeDef CFG_ODT_INBUF_4_PD; /*!< Offset: 0x54 */ __IO DDR_CSR_APB_CFG_CA_PARITY_ERR_STATUS_TypeDef CFG_CA_PARITY_ERR_STATUS; /*!< Offset: 0x58 */ __IO DDR_CSR_APB_CFG_CRC_ERROR_CLEAR_TypeDef CFG_CRC_ERROR_CLEAR; /*!< Offset: 0x5c */ __IO DDR_CSR_APB_CFG_CA_PARITY_LATENCY_TypeDef CFG_CA_PARITY_LATENCY; /*!< Offset: 0x60 */ __IO DDR_CSR_APB_CFG_CCD_S_TypeDef CFG_CCD_S; /*!< Offset: 0x64 */ __IO DDR_CSR_APB_CFG_CCD_L_TypeDef CFG_CCD_L; /*!< Offset: 0x68 */ __IO DDR_CSR_APB_CFG_VREFDQ_TRN_ENABLE_TypeDef CFG_VREFDQ_TRN_ENABLE; /*!< Offset: 0x6c */ __IO DDR_CSR_APB_CFG_VREFDQ_TRN_RANGE_TypeDef CFG_VREFDQ_TRN_RANGE; /*!< Offset: 0x70 */ __IO DDR_CSR_APB_CFG_VREFDQ_TRN_VALUE_TypeDef CFG_VREFDQ_TRN_VALUE; /*!< Offset: 0x74 */ __IO DDR_CSR_APB_CFG_RRD_S_TypeDef CFG_RRD_S; /*!< Offset: 0x78 */ __IO DDR_CSR_APB_CFG_RRD_L_TypeDef CFG_RRD_L; /*!< Offset: 0x7c */ __IO DDR_CSR_APB_CFG_WTR_S_TypeDef CFG_WTR_S; /*!< Offset: 0x80 */ __IO DDR_CSR_APB_CFG_WTR_L_TypeDef CFG_WTR_L; /*!< Offset: 0x84 */ __IO DDR_CSR_APB_CFG_WTR_S_CRC_DM_TypeDef CFG_WTR_S_CRC_DM; /*!< Offset: 0x88 */ __IO DDR_CSR_APB_CFG_WTR_L_CRC_DM_TypeDef CFG_WTR_L_CRC_DM; /*!< Offset: 0x8c */ __IO DDR_CSR_APB_CFG_WR_CRC_DM_TypeDef CFG_WR_CRC_DM; /*!< Offset: 0x90 */ __IO DDR_CSR_APB_CFG_RFC1_TypeDef CFG_RFC1; /*!< Offset: 0x94 */ __IO DDR_CSR_APB_CFG_RFC2_TypeDef CFG_RFC2; /*!< Offset: 0x98 */ __IO DDR_CSR_APB_CFG_RFC4_TypeDef CFG_RFC4; /*!< Offset: 0x9c */ __I uint32_t UNUSED_SPACE0[9]; /*!< Offset: 0xa0 */ __IO DDR_CSR_APB_CFG_NIBBLE_DEVICES_TypeDef CFG_NIBBLE_DEVICES; /*!< Offset: 0xc4 */ __I uint32_t UNUSED_SPACE1[6]; /*!< Offset: 0xc8 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS0_0_TypeDef CFG_BIT_MAP_INDEX_CS0_0; /*!< Offset: 0xe0 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS0_1_TypeDef CFG_BIT_MAP_INDEX_CS0_1; /*!< Offset: 0xe4 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS1_0_TypeDef CFG_BIT_MAP_INDEX_CS1_0; /*!< Offset: 0xe8 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS1_1_TypeDef CFG_BIT_MAP_INDEX_CS1_1; /*!< Offset: 0xec */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS2_0_TypeDef CFG_BIT_MAP_INDEX_CS2_0; /*!< Offset: 0xf0 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS2_1_TypeDef CFG_BIT_MAP_INDEX_CS2_1; /*!< Offset: 0xf4 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS3_0_TypeDef CFG_BIT_MAP_INDEX_CS3_0; /*!< Offset: 0xf8 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS3_1_TypeDef CFG_BIT_MAP_INDEX_CS3_1; /*!< Offset: 0xfc */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS4_0_TypeDef CFG_BIT_MAP_INDEX_CS4_0; /*!< Offset: 0x100 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS4_1_TypeDef CFG_BIT_MAP_INDEX_CS4_1; /*!< Offset: 0x104 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS5_0_TypeDef CFG_BIT_MAP_INDEX_CS5_0; /*!< Offset: 0x108 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS5_1_TypeDef CFG_BIT_MAP_INDEX_CS5_1; /*!< Offset: 0x10c */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS6_0_TypeDef CFG_BIT_MAP_INDEX_CS6_0; /*!< Offset: 0x110 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS6_1_TypeDef CFG_BIT_MAP_INDEX_CS6_1; /*!< Offset: 0x114 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS7_0_TypeDef CFG_BIT_MAP_INDEX_CS7_0; /*!< Offset: 0x118 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS7_1_TypeDef CFG_BIT_MAP_INDEX_CS7_1; /*!< Offset: 0x11c */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS8_0_TypeDef CFG_BIT_MAP_INDEX_CS8_0; /*!< Offset: 0x120 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS8_1_TypeDef CFG_BIT_MAP_INDEX_CS8_1; /*!< Offset: 0x124 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS9_0_TypeDef CFG_BIT_MAP_INDEX_CS9_0; /*!< Offset: 0x128 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS9_1_TypeDef CFG_BIT_MAP_INDEX_CS9_1; /*!< Offset: 0x12c */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS10_0_TypeDef CFG_BIT_MAP_INDEX_CS10_0; /*!< Offset: 0x130 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS10_1_TypeDef CFG_BIT_MAP_INDEX_CS10_1; /*!< Offset: 0x134 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS11_0_TypeDef CFG_BIT_MAP_INDEX_CS11_0; /*!< Offset: 0x138 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS11_1_TypeDef CFG_BIT_MAP_INDEX_CS11_1; /*!< Offset: 0x13c */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS12_0_TypeDef CFG_BIT_MAP_INDEX_CS12_0; /*!< Offset: 0x140 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS12_1_TypeDef CFG_BIT_MAP_INDEX_CS12_1; /*!< Offset: 0x144 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS13_0_TypeDef CFG_BIT_MAP_INDEX_CS13_0; /*!< Offset: 0x148 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS13_1_TypeDef CFG_BIT_MAP_INDEX_CS13_1; /*!< Offset: 0x14c */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS14_0_TypeDef CFG_BIT_MAP_INDEX_CS14_0; /*!< Offset: 0x150 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS14_1_TypeDef CFG_BIT_MAP_INDEX_CS14_1; /*!< Offset: 0x154 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS15_0_TypeDef CFG_BIT_MAP_INDEX_CS15_0; /*!< Offset: 0x158 */ __IO DDR_CSR_APB_CFG_BIT_MAP_INDEX_CS15_1_TypeDef CFG_BIT_MAP_INDEX_CS15_1; /*!< Offset: 0x15c */ __IO DDR_CSR_APB_CFG_NUM_LOGICAL_RANKS_PER_3DS_TypeDef CFG_NUM_LOGICAL_RANKS_PER_3DS; /*!< Offset: 0x160 */ __IO DDR_CSR_APB_CFG_RFC_DLR1_TypeDef CFG_RFC_DLR1; /*!< Offset: 0x164 */ __IO DDR_CSR_APB_CFG_RFC_DLR2_TypeDef CFG_RFC_DLR2; /*!< Offset: 0x168 */ __IO DDR_CSR_APB_CFG_RFC_DLR4_TypeDef CFG_RFC_DLR4; /*!< Offset: 0x16c */ __IO DDR_CSR_APB_CFG_RRD_DLR_TypeDef CFG_RRD_DLR; /*!< Offset: 0x170 */ __IO DDR_CSR_APB_CFG_FAW_DLR_TypeDef CFG_FAW_DLR; /*!< Offset: 0x174 */ __I uint32_t UNUSED_SPACE2[8]; /*!< Offset: 0x178 */ __IO DDR_CSR_APB_CFG_ADVANCE_ACTIVATE_READY_TypeDef CFG_ADVANCE_ACTIVATE_READY; /*!< Offset: 0x198 */ __I uint32_t UNUSED_SPACE3[6]; /*!< Offset: 0x19c */ } DDR_CSR_APB_MC_BASE1_TypeDef; /*------------ MC_BASE2 register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CTRLR_SOFT_RESET_N_TypeDef CTRLR_SOFT_RESET_N; /*!< Offset: 0x0 */ __I uint32_t UNUSED_SPACE0; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_LOOKAHEAD_PCH_TypeDef CFG_LOOKAHEAD_PCH; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_LOOKAHEAD_ACT_TypeDef CFG_LOOKAHEAD_ACT; /*!< Offset: 0xc */ __IO DDR_CSR_APB_INIT_AUTOINIT_DISABLE_TypeDef INIT_AUTOINIT_DISABLE; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_INIT_FORCE_RESET_TypeDef INIT_FORCE_RESET; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_INIT_GEARDOWN_EN_TypeDef INIT_GEARDOWN_EN; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_INIT_DISABLE_CKE_TypeDef INIT_DISABLE_CKE; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_INIT_CS_TypeDef INIT_CS; /*!< Offset: 0x20 */ __IO DDR_CSR_APB_INIT_PRECHARGE_ALL_TypeDef INIT_PRECHARGE_ALL; /*!< Offset: 0x24 */ __IO DDR_CSR_APB_INIT_REFRESH_TypeDef INIT_REFRESH; /*!< Offset: 0x28 */ __IO DDR_CSR_APB_INIT_ZQ_CAL_REQ_TypeDef INIT_ZQ_CAL_REQ; /*!< Offset: 0x2c */ __I DDR_CSR_APB_INIT_ACK_TypeDef INIT_ACK; /*!< Offset: 0x30 */ __IO DDR_CSR_APB_CFG_BL_TypeDef CFG_BL; /*!< Offset: 0x34 */ __IO DDR_CSR_APB_CTRLR_INIT_TypeDef CTRLR_INIT; /*!< Offset: 0x38 */ __I DDR_CSR_APB_CTRLR_INIT_DONE_TypeDef CTRLR_INIT_DONE; /*!< Offset: 0x3c */ __IO DDR_CSR_APB_CFG_AUTO_REF_EN_TypeDef CFG_AUTO_REF_EN; /*!< Offset: 0x40 */ __IO DDR_CSR_APB_CFG_RAS_TypeDef CFG_RAS; /*!< Offset: 0x44 */ __IO DDR_CSR_APB_CFG_RCD_TypeDef CFG_RCD; /*!< Offset: 0x48 */ __IO DDR_CSR_APB_CFG_RRD_TypeDef CFG_RRD; /*!< Offset: 0x4c */ __IO DDR_CSR_APB_CFG_RP_TypeDef CFG_RP; /*!< Offset: 0x50 */ __IO DDR_CSR_APB_CFG_RC_TypeDef CFG_RC; /*!< Offset: 0x54 */ __IO DDR_CSR_APB_CFG_FAW_TypeDef CFG_FAW; /*!< Offset: 0x58 */ __IO DDR_CSR_APB_CFG_RFC_TypeDef CFG_RFC; /*!< Offset: 0x5c */ __IO DDR_CSR_APB_CFG_RTP_TypeDef CFG_RTP; /*!< Offset: 0x60 */ __IO DDR_CSR_APB_CFG_WR_TypeDef CFG_WR; /*!< Offset: 0x64 */ __IO DDR_CSR_APB_CFG_WTR_TypeDef CFG_WTR; /*!< Offset: 0x68 */ __I uint32_t UNUSED_SPACE1; /*!< Offset: 0x6c */ __IO DDR_CSR_APB_CFG_PASR_TypeDef CFG_PASR; /*!< Offset: 0x70 */ __IO DDR_CSR_APB_CFG_XP_TypeDef CFG_XP; /*!< Offset: 0x74 */ __IO DDR_CSR_APB_CFG_XSR_TypeDef CFG_XSR; /*!< Offset: 0x78 */ __I uint32_t UNUSED_SPACE2; /*!< Offset: 0x7c */ __IO DDR_CSR_APB_CFG_CL_TypeDef CFG_CL; /*!< Offset: 0x80 */ __I uint32_t UNUSED_SPACE3; /*!< Offset: 0x84 */ __IO DDR_CSR_APB_CFG_READ_TO_WRITE_TypeDef CFG_READ_TO_WRITE; /*!< Offset: 0x88 */ __IO DDR_CSR_APB_CFG_WRITE_TO_WRITE_TypeDef CFG_WRITE_TO_WRITE; /*!< Offset: 0x8c */ __IO DDR_CSR_APB_CFG_READ_TO_READ_TypeDef CFG_READ_TO_READ; /*!< Offset: 0x90 */ __IO DDR_CSR_APB_CFG_WRITE_TO_READ_TypeDef CFG_WRITE_TO_READ; /*!< Offset: 0x94 */ __IO DDR_CSR_APB_CFG_READ_TO_WRITE_ODT_TypeDef CFG_READ_TO_WRITE_ODT; /*!< Offset: 0x98 */ __IO DDR_CSR_APB_CFG_WRITE_TO_WRITE_ODT_TypeDef CFG_WRITE_TO_WRITE_ODT; /*!< Offset: 0x9c */ __IO DDR_CSR_APB_CFG_READ_TO_READ_ODT_TypeDef CFG_READ_TO_READ_ODT; /*!< Offset: 0xa0 */ __IO DDR_CSR_APB_CFG_WRITE_TO_READ_ODT_TypeDef CFG_WRITE_TO_READ_ODT; /*!< Offset: 0xa4 */ __IO DDR_CSR_APB_CFG_MIN_READ_IDLE_TypeDef CFG_MIN_READ_IDLE; /*!< Offset: 0xa8 */ __IO DDR_CSR_APB_CFG_MRD_TypeDef CFG_MRD; /*!< Offset: 0xac */ __IO DDR_CSR_APB_CFG_BT_TypeDef CFG_BT; /*!< Offset: 0xb0 */ __IO DDR_CSR_APB_CFG_DS_TypeDef CFG_DS; /*!< Offset: 0xb4 */ __IO DDR_CSR_APB_CFG_QOFF_TypeDef CFG_QOFF; /*!< Offset: 0xb8 */ __I uint32_t UNUSED_SPACE4[2]; /*!< Offset: 0xbc */ __IO DDR_CSR_APB_CFG_RTT_TypeDef CFG_RTT; /*!< Offset: 0xc4 */ __IO DDR_CSR_APB_CFG_DLL_DISABLE_TypeDef CFG_DLL_DISABLE; /*!< Offset: 0xc8 */ __IO DDR_CSR_APB_CFG_REF_PER_TypeDef CFG_REF_PER; /*!< Offset: 0xcc */ __IO DDR_CSR_APB_CFG_STARTUP_DELAY_TypeDef CFG_STARTUP_DELAY; /*!< Offset: 0xd0 */ __IO DDR_CSR_APB_CFG_MEM_COLBITS_TypeDef CFG_MEM_COLBITS; /*!< Offset: 0xd4 */ __IO DDR_CSR_APB_CFG_MEM_ROWBITS_TypeDef CFG_MEM_ROWBITS; /*!< Offset: 0xd8 */ __IO DDR_CSR_APB_CFG_MEM_BANKBITS_TypeDef CFG_MEM_BANKBITS; /*!< Offset: 0xdc */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS0_TypeDef CFG_ODT_RD_MAP_CS0; /*!< Offset: 0xe0 */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS1_TypeDef CFG_ODT_RD_MAP_CS1; /*!< Offset: 0xe4 */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS2_TypeDef CFG_ODT_RD_MAP_CS2; /*!< Offset: 0xe8 */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS3_TypeDef CFG_ODT_RD_MAP_CS3; /*!< Offset: 0xec */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS4_TypeDef CFG_ODT_RD_MAP_CS4; /*!< Offset: 0xf0 */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS5_TypeDef CFG_ODT_RD_MAP_CS5; /*!< Offset: 0xf4 */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS6_TypeDef CFG_ODT_RD_MAP_CS6; /*!< Offset: 0xf8 */ __IO DDR_CSR_APB_CFG_ODT_RD_MAP_CS7_TypeDef CFG_ODT_RD_MAP_CS7; /*!< Offset: 0xfc */ __I uint32_t UNUSED_SPACE5[8]; /*!< Offset: 0x100 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS0_TypeDef CFG_ODT_WR_MAP_CS0; /*!< Offset: 0x120 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS1_TypeDef CFG_ODT_WR_MAP_CS1; /*!< Offset: 0x124 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS2_TypeDef CFG_ODT_WR_MAP_CS2; /*!< Offset: 0x128 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS3_TypeDef CFG_ODT_WR_MAP_CS3; /*!< Offset: 0x12c */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS4_TypeDef CFG_ODT_WR_MAP_CS4; /*!< Offset: 0x130 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS5_TypeDef CFG_ODT_WR_MAP_CS5; /*!< Offset: 0x134 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS6_TypeDef CFG_ODT_WR_MAP_CS6; /*!< Offset: 0x138 */ __IO DDR_CSR_APB_CFG_ODT_WR_MAP_CS7_TypeDef CFG_ODT_WR_MAP_CS7; /*!< Offset: 0x13c */ __I uint32_t UNUSED_SPACE6[8]; /*!< Offset: 0x140 */ __IO DDR_CSR_APB_CFG_ODT_RD_TURN_ON_TypeDef CFG_ODT_RD_TURN_ON; /*!< Offset: 0x160 */ __IO DDR_CSR_APB_CFG_ODT_WR_TURN_ON_TypeDef CFG_ODT_WR_TURN_ON; /*!< Offset: 0x164 */ __IO DDR_CSR_APB_CFG_ODT_RD_TURN_OFF_TypeDef CFG_ODT_RD_TURN_OFF; /*!< Offset: 0x168 */ __IO DDR_CSR_APB_CFG_ODT_WR_TURN_OFF_TypeDef CFG_ODT_WR_TURN_OFF; /*!< Offset: 0x16c */ __I uint32_t UNUSED_SPACE7[2]; /*!< Offset: 0x170 */ __IO DDR_CSR_APB_CFG_EMR3_TypeDef CFG_EMR3; /*!< Offset: 0x178 */ __IO DDR_CSR_APB_CFG_TWO_T_TypeDef CFG_TWO_T; /*!< Offset: 0x17c */ __IO DDR_CSR_APB_CFG_TWO_T_SEL_CYCLE_TypeDef CFG_TWO_T_SEL_CYCLE; /*!< Offset: 0x180 */ __IO DDR_CSR_APB_CFG_REGDIMM_TypeDef CFG_REGDIMM; /*!< Offset: 0x184 */ __IO DDR_CSR_APB_CFG_MOD_TypeDef CFG_MOD; /*!< Offset: 0x188 */ __IO DDR_CSR_APB_CFG_XS_TypeDef CFG_XS; /*!< Offset: 0x18c */ __IO DDR_CSR_APB_CFG_XSDLL_TypeDef CFG_XSDLL; /*!< Offset: 0x190 */ __IO DDR_CSR_APB_CFG_XPR_TypeDef CFG_XPR; /*!< Offset: 0x194 */ __IO DDR_CSR_APB_CFG_AL_MODE_TypeDef CFG_AL_MODE; /*!< Offset: 0x198 */ __IO DDR_CSR_APB_CFG_CWL_TypeDef CFG_CWL; /*!< Offset: 0x19c */ __IO DDR_CSR_APB_CFG_BL_MODE_TypeDef CFG_BL_MODE; /*!< Offset: 0x1a0 */ __IO DDR_CSR_APB_CFG_TDQS_TypeDef CFG_TDQS; /*!< Offset: 0x1a4 */ __IO DDR_CSR_APB_CFG_RTT_WR_TypeDef CFG_RTT_WR; /*!< Offset: 0x1a8 */ __IO DDR_CSR_APB_CFG_LP_ASR_TypeDef CFG_LP_ASR; /*!< Offset: 0x1ac */ __IO DDR_CSR_APB_CFG_AUTO_SR_TypeDef CFG_AUTO_SR; /*!< Offset: 0x1b0 */ __IO DDR_CSR_APB_CFG_SRT_TypeDef CFG_SRT; /*!< Offset: 0x1b4 */ __IO DDR_CSR_APB_CFG_ADDR_MIRROR_TypeDef CFG_ADDR_MIRROR; /*!< Offset: 0x1b8 */ __IO DDR_CSR_APB_CFG_ZQ_CAL_TYPE_TypeDef CFG_ZQ_CAL_TYPE; /*!< Offset: 0x1bc */ __IO DDR_CSR_APB_CFG_ZQ_CAL_PER_TypeDef CFG_ZQ_CAL_PER; /*!< Offset: 0x1c0 */ __IO DDR_CSR_APB_CFG_AUTO_ZQ_CAL_EN_TypeDef CFG_AUTO_ZQ_CAL_EN; /*!< Offset: 0x1c4 */ __IO DDR_CSR_APB_CFG_MEMORY_TYPE_TypeDef CFG_MEMORY_TYPE; /*!< Offset: 0x1c8 */ __IO DDR_CSR_APB_CFG_ONLY_SRANK_CMDS_TypeDef CFG_ONLY_SRANK_CMDS; /*!< Offset: 0x1cc */ __IO DDR_CSR_APB_CFG_NUM_RANKS_TypeDef CFG_NUM_RANKS; /*!< Offset: 0x1d0 */ __IO DDR_CSR_APB_CFG_QUAD_RANK_TypeDef CFG_QUAD_RANK; /*!< Offset: 0x1d4 */ __I uint32_t UNUSED_SPACE8; /*!< Offset: 0x1d8 */ __IO DDR_CSR_APB_CFG_EARLY_RANK_TO_WR_START_TypeDef CFG_EARLY_RANK_TO_WR_START; /*!< Offset: 0x1dc */ __IO DDR_CSR_APB_CFG_EARLY_RANK_TO_RD_START_TypeDef CFG_EARLY_RANK_TO_RD_START; /*!< Offset: 0x1e0 */ __IO DDR_CSR_APB_CFG_PASR_BANK_TypeDef CFG_PASR_BANK; /*!< Offset: 0x1e4 */ __IO DDR_CSR_APB_CFG_PASR_SEG_TypeDef CFG_PASR_SEG; /*!< Offset: 0x1e8 */ __IO DDR_CSR_APB_INIT_MRR_MODE_TypeDef INIT_MRR_MODE; /*!< Offset: 0x1ec */ __IO DDR_CSR_APB_INIT_MR_W_REQ_TypeDef INIT_MR_W_REQ; /*!< Offset: 0x1f0 */ __IO DDR_CSR_APB_INIT_MR_ADDR_TypeDef INIT_MR_ADDR; /*!< Offset: 0x1f4 */ __IO DDR_CSR_APB_INIT_MR_WR_DATA_TypeDef INIT_MR_WR_DATA; /*!< Offset: 0x1f8 */ __IO DDR_CSR_APB_INIT_MR_WR_MASK_TypeDef INIT_MR_WR_MASK; /*!< Offset: 0x1fc */ __IO DDR_CSR_APB_INIT_NOP_TypeDef INIT_NOP; /*!< Offset: 0x200 */ __IO DDR_CSR_APB_CFG_INIT_DURATION_TypeDef CFG_INIT_DURATION; /*!< Offset: 0x204 */ __IO DDR_CSR_APB_CFG_ZQINIT_CAL_DURATION_TypeDef CFG_ZQINIT_CAL_DURATION; /*!< Offset: 0x208 */ __IO DDR_CSR_APB_CFG_ZQ_CAL_L_DURATION_TypeDef CFG_ZQ_CAL_L_DURATION; /*!< Offset: 0x20c */ __IO DDR_CSR_APB_CFG_ZQ_CAL_S_DURATION_TypeDef CFG_ZQ_CAL_S_DURATION; /*!< Offset: 0x210 */ __IO DDR_CSR_APB_CFG_ZQ_CAL_R_DURATION_TypeDef CFG_ZQ_CAL_R_DURATION; /*!< Offset: 0x214 */ __IO DDR_CSR_APB_CFG_MRR_TypeDef CFG_MRR; /*!< Offset: 0x218 */ __IO DDR_CSR_APB_CFG_MRW_TypeDef CFG_MRW; /*!< Offset: 0x21c */ __IO DDR_CSR_APB_CFG_ODT_POWERDOWN_TypeDef CFG_ODT_POWERDOWN; /*!< Offset: 0x220 */ __IO DDR_CSR_APB_CFG_WL_TypeDef CFG_WL; /*!< Offset: 0x224 */ __IO DDR_CSR_APB_CFG_RL_TypeDef CFG_RL; /*!< Offset: 0x228 */ __IO DDR_CSR_APB_CFG_CAL_READ_PERIOD_TypeDef CFG_CAL_READ_PERIOD; /*!< Offset: 0x22c */ __IO DDR_CSR_APB_CFG_NUM_CAL_READS_TypeDef CFG_NUM_CAL_READS; /*!< Offset: 0x230 */ __IO DDR_CSR_APB_INIT_SELF_REFRESH_TypeDef INIT_SELF_REFRESH; /*!< Offset: 0x234 */ __I DDR_CSR_APB_INIT_SELF_REFRESH_STATUS_TypeDef INIT_SELF_REFRESH_STATUS; /*!< Offset: 0x238 */ __IO DDR_CSR_APB_INIT_POWER_DOWN_TypeDef INIT_POWER_DOWN; /*!< Offset: 0x23c */ __I DDR_CSR_APB_INIT_POWER_DOWN_STATUS_TypeDef INIT_POWER_DOWN_STATUS; /*!< Offset: 0x240 */ __IO DDR_CSR_APB_INIT_FORCE_WRITE_TypeDef INIT_FORCE_WRITE; /*!< Offset: 0x244 */ __IO DDR_CSR_APB_INIT_FORCE_WRITE_CS_TypeDef INIT_FORCE_WRITE_CS; /*!< Offset: 0x248 */ __IO DDR_CSR_APB_CFG_CTRLR_INIT_DISABLE_TypeDef CFG_CTRLR_INIT_DISABLE; /*!< Offset: 0x24c */ __I DDR_CSR_APB_CTRLR_READY_TypeDef CTRLR_READY; /*!< Offset: 0x250 */ __I DDR_CSR_APB_INIT_RDIMM_READY_TypeDef INIT_RDIMM_READY; /*!< Offset: 0x254 */ __IO DDR_CSR_APB_INIT_RDIMM_COMPLETE_TypeDef INIT_RDIMM_COMPLETE; /*!< Offset: 0x258 */ __IO DDR_CSR_APB_CFG_RDIMM_LAT_TypeDef CFG_RDIMM_LAT; /*!< Offset: 0x25c */ __IO DDR_CSR_APB_CFG_RDIMM_BSIDE_INVERT_TypeDef CFG_RDIMM_BSIDE_INVERT; /*!< Offset: 0x260 */ __IO DDR_CSR_APB_CFG_LRDIMM_TypeDef CFG_LRDIMM; /*!< Offset: 0x264 */ __IO DDR_CSR_APB_INIT_MEMORY_RESET_MASK_TypeDef INIT_MEMORY_RESET_MASK; /*!< Offset: 0x268 */ __IO DDR_CSR_APB_CFG_RD_PREAMB_TOGGLE_TypeDef CFG_RD_PREAMB_TOGGLE; /*!< Offset: 0x26c */ __IO DDR_CSR_APB_CFG_RD_POSTAMBLE_TypeDef CFG_RD_POSTAMBLE; /*!< Offset: 0x270 */ __IO DDR_CSR_APB_CFG_PU_CAL_TypeDef CFG_PU_CAL; /*!< Offset: 0x274 */ __IO DDR_CSR_APB_CFG_DQ_ODT_TypeDef CFG_DQ_ODT; /*!< Offset: 0x278 */ __IO DDR_CSR_APB_CFG_CA_ODT_TypeDef CFG_CA_ODT; /*!< Offset: 0x27c */ __IO DDR_CSR_APB_CFG_ZQLATCH_DURATION_TypeDef CFG_ZQLATCH_DURATION; /*!< Offset: 0x280 */ __IO DDR_CSR_APB_INIT_CAL_SELECT_TypeDef INIT_CAL_SELECT; /*!< Offset: 0x284 */ __IO DDR_CSR_APB_INIT_CAL_L_R_REQ_TypeDef INIT_CAL_L_R_REQ; /*!< Offset: 0x288 */ __IO DDR_CSR_APB_INIT_CAL_L_B_SIZE_TypeDef INIT_CAL_L_B_SIZE; /*!< Offset: 0x28c */ __I DDR_CSR_APB_INIT_CAL_L_R_ACK_TypeDef INIT_CAL_L_R_ACK; /*!< Offset: 0x290 */ __I DDR_CSR_APB_INIT_CAL_L_READ_COMPLETE_TypeDef INIT_CAL_L_READ_COMPLETE; /*!< Offset: 0x294 */ __I uint32_t UNUSED_SPACE9[2]; /*!< Offset: 0x298 */ __IO DDR_CSR_APB_INIT_RWFIFO_TypeDef INIT_RWFIFO; /*!< Offset: 0x2a0 */ __IO DDR_CSR_APB_INIT_RD_DQCAL_TypeDef INIT_RD_DQCAL; /*!< Offset: 0x2a4 */ __IO DDR_CSR_APB_INIT_START_DQSOSC_TypeDef INIT_START_DQSOSC; /*!< Offset: 0x2a8 */ __IO DDR_CSR_APB_INIT_STOP_DQSOSC_TypeDef INIT_STOP_DQSOSC; /*!< Offset: 0x2ac */ __IO DDR_CSR_APB_INIT_ZQ_CAL_START_TypeDef INIT_ZQ_CAL_START; /*!< Offset: 0x2b0 */ __IO DDR_CSR_APB_CFG_WR_POSTAMBLE_TypeDef CFG_WR_POSTAMBLE; /*!< Offset: 0x2b4 */ __I uint32_t UNUSED_SPACE10; /*!< Offset: 0x2b8 */ __IO DDR_CSR_APB_INIT_CAL_L_ADDR_0_TypeDef INIT_CAL_L_ADDR_0; /*!< Offset: 0x2bc */ __IO DDR_CSR_APB_INIT_CAL_L_ADDR_1_TypeDef INIT_CAL_L_ADDR_1; /*!< Offset: 0x2c0 */ __IO DDR_CSR_APB_CFG_CTRLUPD_TRIG_TypeDef CFG_CTRLUPD_TRIG; /*!< Offset: 0x2c4 */ __IO DDR_CSR_APB_CFG_CTRLUPD_START_DELAY_TypeDef CFG_CTRLUPD_START_DELAY; /*!< Offset: 0x2c8 */ __IO DDR_CSR_APB_CFG_DFI_T_CTRLUPD_MAX_TypeDef CFG_DFI_T_CTRLUPD_MAX; /*!< Offset: 0x2cc */ __IO DDR_CSR_APB_CFG_CTRLR_BUSY_SEL_TypeDef CFG_CTRLR_BUSY_SEL; /*!< Offset: 0x2d0 */ __IO DDR_CSR_APB_CFG_CTRLR_BUSY_VALUE_TypeDef CFG_CTRLR_BUSY_VALUE; /*!< Offset: 0x2d4 */ __IO DDR_CSR_APB_CFG_CTRLR_BUSY_TURN_OFF_DELAY_TypeDef CFG_CTRLR_BUSY_TURN_OFF_DELAY; /*!< Offset: 0x2d8 */ __IO DDR_CSR_APB_CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW_TypeDef CFG_CTRLR_BUSY_SLOW_RESTART_WINDOW; /*!< Offset: 0x2dc */ __IO DDR_CSR_APB_CFG_CTRLR_BUSY_RESTART_HOLDOFF_TypeDef CFG_CTRLR_BUSY_RESTART_HOLDOFF; /*!< Offset: 0x2e0 */ __IO DDR_CSR_APB_CFG_PARITY_RDIMM_DELAY_TypeDef CFG_PARITY_RDIMM_DELAY; /*!< Offset: 0x2e4 */ __IO DDR_CSR_APB_CFG_CTRLR_BUSY_ENABLE_TypeDef CFG_CTRLR_BUSY_ENABLE; /*!< Offset: 0x2e8 */ __IO DDR_CSR_APB_CFG_ASYNC_ODT_TypeDef CFG_ASYNC_ODT; /*!< Offset: 0x2ec */ __IO DDR_CSR_APB_CFG_ZQ_CAL_DURATION_TypeDef CFG_ZQ_CAL_DURATION; /*!< Offset: 0x2f0 */ __IO DDR_CSR_APB_CFG_MRRI_TypeDef CFG_MRRI; /*!< Offset: 0x2f4 */ __IO DDR_CSR_APB_INIT_ODT_FORCE_EN_TypeDef INIT_ODT_FORCE_EN; /*!< Offset: 0x2f8 */ __IO DDR_CSR_APB_INIT_ODT_FORCE_RANK_TypeDef INIT_ODT_FORCE_RANK; /*!< Offset: 0x2fc */ __IO DDR_CSR_APB_CFG_PHYUPD_ACK_DELAY_TypeDef CFG_PHYUPD_ACK_DELAY; /*!< Offset: 0x300 */ __IO DDR_CSR_APB_CFG_MIRROR_X16_BG0_BG1_TypeDef CFG_MIRROR_X16_BG0_BG1; /*!< Offset: 0x304 */ __IO DDR_CSR_APB_INIT_PDA_MR_W_REQ_TypeDef INIT_PDA_MR_W_REQ; /*!< Offset: 0x308 */ __IO DDR_CSR_APB_INIT_PDA_NIBBLE_SELECT_TypeDef INIT_PDA_NIBBLE_SELECT; /*!< Offset: 0x30c */ __IO DDR_CSR_APB_CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH_TypeDef CFG_DRAM_CLK_DISABLE_IN_SELF_REFRESH; /*!< Offset: 0x310 */ __IO DDR_CSR_APB_CFG_CKSRE_TypeDef CFG_CKSRE; /*!< Offset: 0x314 */ __IO DDR_CSR_APB_CFG_CKSRX_TypeDef CFG_CKSRX; /*!< Offset: 0x318 */ __IO DDR_CSR_APB_CFG_RCD_STAB_TypeDef CFG_RCD_STAB; /*!< Offset: 0x31c */ __IO DDR_CSR_APB_CFG_DFI_T_CTRL_DELAY_TypeDef CFG_DFI_T_CTRL_DELAY; /*!< Offset: 0x320 */ __IO DDR_CSR_APB_CFG_DFI_T_DRAM_CLK_ENABLE_TypeDef CFG_DFI_T_DRAM_CLK_ENABLE; /*!< Offset: 0x324 */ __IO DDR_CSR_APB_CFG_IDLE_TIME_TO_SELF_REFRESH_TypeDef CFG_IDLE_TIME_TO_SELF_REFRESH; /*!< Offset: 0x328 */ __IO DDR_CSR_APB_CFG_IDLE_TIME_TO_POWER_DOWN_TypeDef CFG_IDLE_TIME_TO_POWER_DOWN; /*!< Offset: 0x32c */ __IO DDR_CSR_APB_CFG_BURST_RW_REFRESH_HOLDOFF_TypeDef CFG_BURST_RW_REFRESH_HOLDOFF; /*!< Offset: 0x330 */ __I DDR_CSR_APB_INIT_REFRESH_COUNT_TypeDef INIT_REFRESH_COUNT; /*!< Offset: 0x334 */ __I uint32_t UNUSED_SPACE11[19]; /*!< Offset: 0x338 */ __IO DDR_CSR_APB_CFG_BG_INTERLEAVE_TypeDef CFG_BG_INTERLEAVE; /*!< Offset: 0x384 */ __I uint32_t UNUSED_SPACE12[29]; /*!< Offset: 0x388 */ __IO DDR_CSR_APB_CFG_REFRESH_DURING_PHY_TRAINING_TypeDef CFG_REFRESH_DURING_PHY_TRAINING; /*!< Offset: 0x3fc */ } DDR_CSR_APB_MC_BASE2_TypeDef; /*------------ MEM_TEST register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_MT_EN_TypeDef MT_EN; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_MT_EN_SINGLE_TypeDef MT_EN_SINGLE; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_MT_STOP_ON_ERROR_TypeDef MT_STOP_ON_ERROR; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_MT_RD_ONLY_TypeDef MT_RD_ONLY; /*!< Offset: 0xc */ __IO DDR_CSR_APB_MT_WR_ONLY_TypeDef MT_WR_ONLY; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_MT_DATA_PATTERN_TypeDef MT_DATA_PATTERN; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_MT_ADDR_PATTERN_TypeDef MT_ADDR_PATTERN; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_MT_DATA_INVERT_TypeDef MT_DATA_INVERT; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_MT_ADDR_BITS_TypeDef MT_ADDR_BITS; /*!< Offset: 0x20 */ __I DDR_CSR_APB_MT_ERROR_STS_TypeDef MT_ERROR_STS; /*!< Offset: 0x24 */ __I DDR_CSR_APB_MT_DONE_ACK_TypeDef MT_DONE_ACK; /*!< Offset: 0x28 */ __I uint32_t UNUSED_SPACE0[34]; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_MT_START_ADDR_0_TypeDef MT_START_ADDR_0; /*!< Offset: 0xb4 */ __IO DDR_CSR_APB_MT_START_ADDR_1_TypeDef MT_START_ADDR_1; /*!< Offset: 0xb8 */ __IO DDR_CSR_APB_MT_ERROR_MASK_0_TypeDef MT_ERROR_MASK_0; /*!< Offset: 0xbc */ __IO DDR_CSR_APB_MT_ERROR_MASK_1_TypeDef MT_ERROR_MASK_1; /*!< Offset: 0xc0 */ __IO DDR_CSR_APB_MT_ERROR_MASK_2_TypeDef MT_ERROR_MASK_2; /*!< Offset: 0xc4 */ __IO DDR_CSR_APB_MT_ERROR_MASK_3_TypeDef MT_ERROR_MASK_3; /*!< Offset: 0xc8 */ __IO DDR_CSR_APB_MT_ERROR_MASK_4_TypeDef MT_ERROR_MASK_4; /*!< Offset: 0xcc */ __I uint32_t UNUSED_SPACE1[104]; /*!< Offset: 0xd0 */ __IO DDR_CSR_APB_MT_USER_DATA_PATTERN_TypeDef MT_USER_DATA_PATTERN; /*!< Offset: 0x270 */ __I uint32_t UNUSED_SPACE2[2]; /*!< Offset: 0x274 */ __IO DDR_CSR_APB_MT_ALG_AUTO_PCH_TypeDef MT_ALG_AUTO_PCH; /*!< Offset: 0x27c */ __I uint32_t UNUSED_SPACE3[2]; /*!< Offset: 0x280 */ } DDR_CSR_APB_MEM_TEST_TypeDef; /*------------ MPFE register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P0_TypeDef CFG_STARVE_TIMEOUT_P0; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P1_TypeDef CFG_STARVE_TIMEOUT_P1; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P2_TypeDef CFG_STARVE_TIMEOUT_P2; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P3_TypeDef CFG_STARVE_TIMEOUT_P3; /*!< Offset: 0xc */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P4_TypeDef CFG_STARVE_TIMEOUT_P4; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P5_TypeDef CFG_STARVE_TIMEOUT_P5; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P6_TypeDef CFG_STARVE_TIMEOUT_P6; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_CFG_STARVE_TIMEOUT_P7_TypeDef CFG_STARVE_TIMEOUT_P7; /*!< Offset: 0x1c */ __I uint32_t UNUSED_SPACE0[33]; /*!< Offset: 0x20 */ } DDR_CSR_APB_MPFE_TypeDef; /*------------ REORDER register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_REORDER_EN_TypeDef CFG_REORDER_EN; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_REORDER_QUEUE_EN_TypeDef CFG_REORDER_QUEUE_EN; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_INTRAPORT_REORDER_EN_TypeDef CFG_INTRAPORT_REORDER_EN; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_MAINTAIN_COHERENCY_TypeDef CFG_MAINTAIN_COHERENCY; /*!< Offset: 0xc */ __IO DDR_CSR_APB_CFG_Q_AGE_LIMIT_TypeDef CFG_Q_AGE_LIMIT; /*!< Offset: 0x10 */ __I uint32_t UNUSED_SPACE0; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_CFG_RO_CLOSED_PAGE_POLICY_TypeDef CFG_RO_CLOSED_PAGE_POLICY; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_CFG_REORDER_RW_ONLY_TypeDef CFG_REORDER_RW_ONLY; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_CFG_RO_PRIORITY_EN_TypeDef CFG_RO_PRIORITY_EN; /*!< Offset: 0x20 */ } DDR_CSR_APB_REORDER_TypeDef; /*------------ RMW register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_DM_EN_TypeDef CFG_DM_EN; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_RMW_EN_TypeDef CFG_RMW_EN; /*!< Offset: 0x4 */ } DDR_CSR_APB_RMW_TypeDef; /*------------ ECC register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_ECC_CORRECTION_EN_TypeDef CFG_ECC_CORRECTION_EN; /*!< Offset: 0x0 */ __I uint32_t UNUSED_SPACE0[15]; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_ECC_BYPASS_TypeDef CFG_ECC_BYPASS; /*!< Offset: 0x40 */ __IO DDR_CSR_APB_INIT_WRITE_DATA_1B_ECC_ERROR_GEN_TypeDef INIT_WRITE_DATA_1B_ECC_ERROR_GEN; /*!< Offset: 0x44 */ __IO DDR_CSR_APB_INIT_WRITE_DATA_2B_ECC_ERROR_GEN_TypeDef INIT_WRITE_DATA_2B_ECC_ERROR_GEN; /*!< Offset: 0x48 */ __I uint32_t UNUSED_SPACE1[4]; /*!< Offset: 0x4c */ __IO DDR_CSR_APB_CFG_ECC_1BIT_INT_THRESH_TypeDef CFG_ECC_1BIT_INT_THRESH; /*!< Offset: 0x5c */ __I DDR_CSR_APB_STAT_INT_ECC_1BIT_THRESH_TypeDef STAT_INT_ECC_1BIT_THRESH; /*!< Offset: 0x60 */ __I uint32_t UNUSED_SPACE2[2]; /*!< Offset: 0x64 */ } DDR_CSR_APB_ECC_TypeDef; /*------------ READ_CAPT register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_INIT_READ_CAPTURE_ADDR_TypeDef INIT_READ_CAPTURE_ADDR; /*!< Offset: 0x0 */ __I DDR_CSR_APB_INIT_READ_CAPTURE_DATA_0_TypeDef INIT_READ_CAPTURE_DATA_0; /*!< Offset: 0x4 */ __I DDR_CSR_APB_INIT_READ_CAPTURE_DATA_1_TypeDef INIT_READ_CAPTURE_DATA_1; /*!< Offset: 0x8 */ __I DDR_CSR_APB_INIT_READ_CAPTURE_DATA_2_TypeDef INIT_READ_CAPTURE_DATA_2; /*!< Offset: 0xc */ __I DDR_CSR_APB_INIT_READ_CAPTURE_DATA_3_TypeDef INIT_READ_CAPTURE_DATA_3; /*!< Offset: 0x10 */ __I DDR_CSR_APB_INIT_READ_CAPTURE_DATA_4_TypeDef INIT_READ_CAPTURE_DATA_4; /*!< Offset: 0x14 */ __I uint32_t UNUSED_SPACE0[12]; /*!< Offset: 0x18 */ } DDR_CSR_APB_READ_CAPT_TypeDef; /*------------ MTA register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_ERROR_GROUP_SEL_TypeDef CFG_ERROR_GROUP_SEL; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_DATA_SEL_TypeDef CFG_DATA_SEL; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_TRIG_MODE_TypeDef CFG_TRIG_MODE; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_POST_TRIG_CYCS_TypeDef CFG_POST_TRIG_CYCS; /*!< Offset: 0xc */ __IO DDR_CSR_APB_CFG_TRIG_MASK_TypeDef CFG_TRIG_MASK; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_CFG_EN_MASK_TypeDef CFG_EN_MASK; /*!< Offset: 0x14 */ __IO DDR_CSR_APB_MTC_ACQ_ADDR_TypeDef MTC_ACQ_ADDR; /*!< Offset: 0x18 */ __I DDR_CSR_APB_MTC_ACQ_CYCS_STORED_TypeDef MTC_ACQ_CYCS_STORED; /*!< Offset: 0x1c */ __I DDR_CSR_APB_MTC_ACQ_TRIG_DETECT_TypeDef MTC_ACQ_TRIG_DETECT; /*!< Offset: 0x20 */ __I DDR_CSR_APB_MTC_ACQ_MEM_TRIG_ADDR_TypeDef MTC_ACQ_MEM_TRIG_ADDR; /*!< Offset: 0x24 */ __I DDR_CSR_APB_MTC_ACQ_MEM_LAST_ADDR_TypeDef MTC_ACQ_MEM_LAST_ADDR; /*!< Offset: 0x28 */ __I DDR_CSR_APB_MTC_ACK_TypeDef MTC_ACK; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_CFG_TRIG_MT_ADDR_0_TypeDef CFG_TRIG_MT_ADDR_0; /*!< Offset: 0x30 */ __IO DDR_CSR_APB_CFG_TRIG_MT_ADDR_1_TypeDef CFG_TRIG_MT_ADDR_1; /*!< Offset: 0x34 */ __IO DDR_CSR_APB_CFG_TRIG_ERR_MASK_0_TypeDef CFG_TRIG_ERR_MASK_0; /*!< Offset: 0x38 */ __IO DDR_CSR_APB_CFG_TRIG_ERR_MASK_1_TypeDef CFG_TRIG_ERR_MASK_1; /*!< Offset: 0x3c */ __IO DDR_CSR_APB_CFG_TRIG_ERR_MASK_2_TypeDef CFG_TRIG_ERR_MASK_2; /*!< Offset: 0x40 */ __IO DDR_CSR_APB_CFG_TRIG_ERR_MASK_3_TypeDef CFG_TRIG_ERR_MASK_3; /*!< Offset: 0x44 */ __IO DDR_CSR_APB_CFG_TRIG_ERR_MASK_4_TypeDef CFG_TRIG_ERR_MASK_4; /*!< Offset: 0x48 */ __IO DDR_CSR_APB_MTC_ACQ_WR_DATA_0_TypeDef MTC_ACQ_WR_DATA_0; /*!< Offset: 0x4c */ __IO DDR_CSR_APB_MTC_ACQ_WR_DATA_1_TypeDef MTC_ACQ_WR_DATA_1; /*!< Offset: 0x50 */ __IO DDR_CSR_APB_MTC_ACQ_WR_DATA_2_TypeDef MTC_ACQ_WR_DATA_2; /*!< Offset: 0x54 */ __I DDR_CSR_APB_MTC_ACQ_RD_DATA_0_TypeDef MTC_ACQ_RD_DATA_0; /*!< Offset: 0x58 */ __I DDR_CSR_APB_MTC_ACQ_RD_DATA_1_TypeDef MTC_ACQ_RD_DATA_1; /*!< Offset: 0x5c */ __I DDR_CSR_APB_MTC_ACQ_RD_DATA_2_TypeDef MTC_ACQ_RD_DATA_2; /*!< Offset: 0x60 */ __I uint32_t UNUSED_SPACE0[50]; /*!< Offset: 0x64 */ __IO DDR_CSR_APB_CFG_PRE_TRIG_CYCS_TypeDef CFG_PRE_TRIG_CYCS; /*!< Offset: 0x12c */ __I uint32_t UNUSED_SPACE1[2]; /*!< Offset: 0x130 */ __I DDR_CSR_APB_MTC_ACQ_ERROR_CNT_TypeDef MTC_ACQ_ERROR_CNT; /*!< Offset: 0x138 */ __I uint32_t UNUSED_SPACE2[2]; /*!< Offset: 0x13c */ __I DDR_CSR_APB_MTC_ACQ_ERROR_CNT_OVFL_TypeDef MTC_ACQ_ERROR_CNT_OVFL; /*!< Offset: 0x144 */ __I uint32_t UNUSED_SPACE3[2]; /*!< Offset: 0x148 */ __IO DDR_CSR_APB_CFG_DATA_SEL_FIRST_ERROR_TypeDef CFG_DATA_SEL_FIRST_ERROR; /*!< Offset: 0x150 */ __I uint32_t UNUSED_SPACE4[2]; /*!< Offset: 0x154 */ } DDR_CSR_APB_MTA_TypeDef; /*------------ DYN_WIDTH_ADJ register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_DQ_WIDTH_TypeDef CFG_DQ_WIDTH; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_ACTIVE_DQ_SEL_TypeDef CFG_ACTIVE_DQ_SEL; /*!< Offset: 0x4 */ } DDR_CSR_APB_DYN_WIDTH_ADJ_TypeDef; /*------------ CA_PAR_ERR register bundle definition -----------*/ typedef struct { __I DDR_CSR_APB_STAT_CA_PARITY_ERROR_TypeDef STAT_CA_PARITY_ERROR; /*!< Offset: 0x0 */ __I uint32_t UNUSED_SPACE0[2]; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_INIT_CA_PARITY_ERROR_GEN_REQ_TypeDef INIT_CA_PARITY_ERROR_GEN_REQ; /*!< Offset: 0xc */ __IO DDR_CSR_APB_INIT_CA_PARITY_ERROR_GEN_CMD_TypeDef INIT_CA_PARITY_ERROR_GEN_CMD; /*!< Offset: 0x10 */ __I DDR_CSR_APB_INIT_CA_PARITY_ERROR_GEN_ACK_TypeDef INIT_CA_PARITY_ERROR_GEN_ACK; /*!< Offset: 0x14 */ __I uint32_t UNUSED_SPACE1[2]; /*!< Offset: 0x18 */ } DDR_CSR_APB_CA_PAR_ERR_TypeDef; /*------------ DFI register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_CFG_DFI_T_RDDATA_EN_TypeDef CFG_DFI_T_RDDATA_EN; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_DFI_T_PHY_RDLAT_TypeDef CFG_DFI_T_PHY_RDLAT; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_CFG_DFI_T_PHY_WRLAT_TypeDef CFG_DFI_T_PHY_WRLAT; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_CFG_DFI_PHYUPD_EN_TypeDef CFG_DFI_PHYUPD_EN; /*!< Offset: 0xc */ __IO DDR_CSR_APB_INIT_DFI_LP_DATA_REQ_TypeDef INIT_DFI_LP_DATA_REQ; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_INIT_DFI_LP_CTRL_REQ_TypeDef INIT_DFI_LP_CTRL_REQ; /*!< Offset: 0x14 */ __I DDR_CSR_APB_STAT_DFI_LP_ACK_TypeDef STAT_DFI_LP_ACK; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_INIT_DFI_LP_WAKEUP_TypeDef INIT_DFI_LP_WAKEUP; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_INIT_DFI_DRAM_CLK_DISABLE_TypeDef INIT_DFI_DRAM_CLK_DISABLE; /*!< Offset: 0x20 */ __I DDR_CSR_APB_STAT_DFI_TRAINING_ERROR_TypeDef STAT_DFI_TRAINING_ERROR; /*!< Offset: 0x24 */ __I DDR_CSR_APB_STAT_DFI_ERROR_TypeDef STAT_DFI_ERROR; /*!< Offset: 0x28 */ __I DDR_CSR_APB_STAT_DFI_ERROR_INFO_TypeDef STAT_DFI_ERROR_INFO; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_CFG_DFI_DATA_BYTE_DISABLE_TypeDef CFG_DFI_DATA_BYTE_DISABLE; /*!< Offset: 0x30 */ __I DDR_CSR_APB_STAT_DFI_INIT_COMPLETE_TypeDef STAT_DFI_INIT_COMPLETE; /*!< Offset: 0x34 */ __I DDR_CSR_APB_STAT_DFI_TRAINING_COMPLETE_TypeDef STAT_DFI_TRAINING_COMPLETE; /*!< Offset: 0x38 */ __IO DDR_CSR_APB_CFG_DFI_LVL_SEL_TypeDef CFG_DFI_LVL_SEL; /*!< Offset: 0x3c */ __IO DDR_CSR_APB_CFG_DFI_LVL_PERIODIC_TypeDef CFG_DFI_LVL_PERIODIC; /*!< Offset: 0x40 */ __IO DDR_CSR_APB_CFG_DFI_LVL_PATTERN_TypeDef CFG_DFI_LVL_PATTERN; /*!< Offset: 0x44 */ __I uint32_t UNUSED_SPACE0[2]; /*!< Offset: 0x48 */ __IO DDR_CSR_APB_PHY_DFI_INIT_START_TypeDef PHY_DFI_INIT_START; /*!< Offset: 0x50 */ __I uint32_t UNUSED_SPACE1; /*!< Offset: 0x54 */ } DDR_CSR_APB_DFI_TypeDef; /*------------ AXI_IF register bundle definition -----------*/ typedef struct { __I uint32_t UNUSED_SPACE0[6]; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI1_0_TypeDef CFG_AXI_START_ADDRESS_AXI1_0; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI1_1_TypeDef CFG_AXI_START_ADDRESS_AXI1_1; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI2_0_TypeDef CFG_AXI_START_ADDRESS_AXI2_0; /*!< Offset: 0x20 */ __IO DDR_CSR_APB_CFG_AXI_START_ADDRESS_AXI2_1_TypeDef CFG_AXI_START_ADDRESS_AXI2_1; /*!< Offset: 0x24 */ __I uint32_t UNUSED_SPACE1[188]; /*!< Offset: 0x28 */ __IO DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI1_0_TypeDef CFG_AXI_END_ADDRESS_AXI1_0; /*!< Offset: 0x318 */ __IO DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI1_1_TypeDef CFG_AXI_END_ADDRESS_AXI1_1; /*!< Offset: 0x31c */ __IO DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI2_0_TypeDef CFG_AXI_END_ADDRESS_AXI2_0; /*!< Offset: 0x320 */ __IO DDR_CSR_APB_CFG_AXI_END_ADDRESS_AXI2_1_TypeDef CFG_AXI_END_ADDRESS_AXI2_1; /*!< Offset: 0x324 */ __I uint32_t UNUSED_SPACE2[188]; /*!< Offset: 0x328 */ __IO DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI1_0_TypeDef CFG_MEM_START_ADDRESS_AXI1_0; /*!< Offset: 0x618 */ __IO DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI1_1_TypeDef CFG_MEM_START_ADDRESS_AXI1_1; /*!< Offset: 0x61c */ __IO DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI2_0_TypeDef CFG_MEM_START_ADDRESS_AXI2_0; /*!< Offset: 0x620 */ __IO DDR_CSR_APB_CFG_MEM_START_ADDRESS_AXI2_1_TypeDef CFG_MEM_START_ADDRESS_AXI2_1; /*!< Offset: 0x624 */ __I uint32_t UNUSED_SPACE3[187]; /*!< Offset: 0x628 */ __IO DDR_CSR_APB_CFG_ENABLE_BUS_HOLD_AXI1_TypeDef CFG_ENABLE_BUS_HOLD_AXI1; /*!< Offset: 0x914 */ __IO DDR_CSR_APB_CFG_ENABLE_BUS_HOLD_AXI2_TypeDef CFG_ENABLE_BUS_HOLD_AXI2; /*!< Offset: 0x918 */ __I uint32_t UNUSED_SPACE4[93]; /*!< Offset: 0x91c */ __IO DDR_CSR_APB_CFG_AXI_AUTO_PCH_TypeDef CFG_AXI_AUTO_PCH; /*!< Offset: 0xa90 */ } DDR_CSR_APB_AXI_IF_TypeDef; /*------------ csr_custom register bundle definition -----------*/ typedef struct { __IO DDR_CSR_APB_PHY_RESET_CONTROL_TypeDef PHY_RESET_CONTROL; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_PHY_PC_RANK_TypeDef PHY_PC_RANK; /*!< Offset: 0x4 */ __IO DDR_CSR_APB_PHY_RANKS_TO_TRAIN_TypeDef PHY_RANKS_TO_TRAIN; /*!< Offset: 0x8 */ __IO DDR_CSR_APB_PHY_WRITE_REQUEST_TypeDef PHY_WRITE_REQUEST; /*!< Offset: 0xc */ __I DDR_CSR_APB_PHY_WRITE_REQUEST_DONE_TypeDef PHY_WRITE_REQUEST_DONE; /*!< Offset: 0x10 */ __IO DDR_CSR_APB_PHY_READ_REQUEST_TypeDef PHY_READ_REQUEST; /*!< Offset: 0x14 */ __I DDR_CSR_APB_PHY_READ_REQUEST_DONE_TypeDef PHY_READ_REQUEST_DONE; /*!< Offset: 0x18 */ __IO DDR_CSR_APB_PHY_WRITE_LEVEL_DELAY_TypeDef PHY_WRITE_LEVEL_DELAY; /*!< Offset: 0x1c */ __IO DDR_CSR_APB_PHY_GATE_TRAIN_DELAY_TypeDef PHY_GATE_TRAIN_DELAY; /*!< Offset: 0x20 */ __IO DDR_CSR_APB_PHY_EYE_TRAIN_DELAY_TypeDef PHY_EYE_TRAIN_DELAY; /*!< Offset: 0x24 */ __IO DDR_CSR_APB_PHY_EYE_PAT_TypeDef PHY_EYE_PAT; /*!< Offset: 0x28 */ __IO DDR_CSR_APB_PHY_START_RECAL_TypeDef PHY_START_RECAL; /*!< Offset: 0x2c */ __IO DDR_CSR_APB_PHY_CLR_DFI_LVL_PERIODIC_TypeDef PHY_CLR_DFI_LVL_PERIODIC; /*!< Offset: 0x30 */ __IO DDR_CSR_APB_PHY_TRAIN_STEP_ENABLE_TypeDef PHY_TRAIN_STEP_ENABLE; /*!< Offset: 0x34 */ __IO DDR_CSR_APB_PHY_LPDDR_DQ_CAL_PAT_TypeDef PHY_LPDDR_DQ_CAL_PAT; /*!< Offset: 0x38 */ __IO DDR_CSR_APB_PHY_INDPNDT_TRAINING_TypeDef PHY_INDPNDT_TRAINING; /*!< Offset: 0x3c */ __IO DDR_CSR_APB_PHY_ENCODED_QUAD_CS_TypeDef PHY_ENCODED_QUAD_CS; /*!< Offset: 0x40 */ __IO DDR_CSR_APB_PHY_HALF_CLK_DLY_ENABLE_TypeDef PHY_HALF_CLK_DLY_ENABLE; /*!< Offset: 0x44 */ __I uint32_t UNUSED_SPACE0[25]; /*!< Offset: 0x48 */ } DDR_CSR_APB_csr_custom_TypeDef; /*------------ DDR_CSR_APB definition -----------*/ typedef struct { __I uint32_t UNUSED_SPACE0[2304]; /*!< Offset: 0x0 */ __IO DDR_CSR_APB_ADDR_MAP_TypeDef ADDR_MAP; /*!< Offset: 0x2400 */ __I uint32_t UNUSED_SPACE1[242]; /*!< Offset: 0x2438 */ __IO DDR_CSR_APB_MC_BASE3_TypeDef MC_BASE3; /*!< Offset: 0x2800 */ __I uint32_t UNUSED_SPACE2[1204]; /*!< Offset: 0x2930 */ __IO DDR_CSR_APB_MC_BASE1_TypeDef MC_BASE1; /*!< Offset: 0x3c00 */ __I uint32_t UNUSED_SPACE3[147]; /*!< Offset: 0x3db4 */ __IO DDR_CSR_APB_MC_BASE2_TypeDef MC_BASE2; /*!< Offset: 0x4000 */ __IO DDR_CSR_APB_MEM_TEST_TypeDef MEM_TEST; /*!< Offset: 0x4400 */ __I uint32_t UNUSED_SPACE4[350]; /*!< Offset: 0x4688 */ __IO DDR_CSR_APB_MPFE_TypeDef MPFE; /*!< Offset: 0x4c00 */ __I uint32_t UNUSED_SPACE5[215]; /*!< Offset: 0x4ca4 */ __IO DDR_CSR_APB_REORDER_TypeDef REORDER; /*!< Offset: 0x5000 */ __I uint32_t UNUSED_SPACE6[247]; /*!< Offset: 0x5024 */ __IO DDR_CSR_APB_RMW_TypeDef RMW; /*!< Offset: 0x5400 */ __I uint32_t UNUSED_SPACE7[254]; /*!< Offset: 0x5408 */ __IO DDR_CSR_APB_ECC_TypeDef ECC; /*!< Offset: 0x5800 */ __I uint32_t UNUSED_SPACE8[229]; /*!< Offset: 0x586c */ __IO DDR_CSR_APB_READ_CAPT_TypeDef READ_CAPT; /*!< Offset: 0x5c00 */ __I uint32_t UNUSED_SPACE9[494]; /*!< Offset: 0x5c48 */ __IO DDR_CSR_APB_MTA_TypeDef MTA; /*!< Offset: 0x6400 */ __I uint32_t UNUSED_SPACE10[1449]; /*!< Offset: 0x655c */ __IO DDR_CSR_APB_DYN_WIDTH_ADJ_TypeDef DYN_WIDTH_ADJ; /*!< Offset: 0x7c00 */ __I uint32_t UNUSED_SPACE11[254]; /*!< Offset: 0x7c08 */ __IO DDR_CSR_APB_CA_PAR_ERR_TypeDef CA_PAR_ERR; /*!< Offset: 0x8000 */ __I uint32_t UNUSED_SPACE12[8184]; /*!< Offset: 0x8020 */ __IO DDR_CSR_APB_DFI_TypeDef DFI; /*!< Offset: 0x10000 */ __I uint32_t UNUSED_SPACE13[2794]; /*!< Offset: 0x10058 */ __IO DDR_CSR_APB_AXI_IF_TypeDef AXI_IF; /*!< Offset: 0x12c00 */ __I uint32_t UNUSED_SPACE14[41563]; /*!< Offset: 0x13694 */ __IO DDR_CSR_APB_csr_custom_TypeDef csr_custom; /*!< Offset: 0x3c000 */ } DDR_CSR_APB_TypeDef; /*============================== IOSCBCFG definitions ===========================*/ typedef union{ /*!< CONTROL__1 register definition*/ __IO uint32_t CONTROL__1; struct { __IO uint32_t INTEN_SCB :1; __IO uint32_t INTEN_ERROR :1; __IO uint32_t INTEN_TIMEOUT :1; __IO uint32_t INTEN_BUSERR :1; __I uint32_t Reserved :4; __IO uint32_t RESET_CYCLE :1; __I uint32_t Reserved1 :7; __IO uint32_t SCBCLOCK_ON :1; __I uint32_t Reserved2 :15; } bitfield; } IOSCBCFG_CONTROL__1_TypeDef; typedef union{ /*!< STATUS register definition*/ __I uint32_t STATUS; struct { __I uint32_t SCB_INTERRUPT :1; __I uint32_t SCB_ERROR :1; __I uint32_t TIMEOUT :1; __I uint32_t SCB_BUSERR :1; __I uint32_t Reserved :28; } bitfield; } IOSCBCFG_STATUS_TypeDef; typedef union{ /*!< TIMER register definition*/ __IO uint32_t TIMER; struct { __IO uint32_t TIMEOUT :8; __IO uint32_t REQUEST_TIME :8; __I uint32_t Reserved :16; } bitfield; } IOSCBCFG_TIMER_TypeDef; /*------------ IOSCBCFG definition -----------*/ typedef struct { __IO IOSCBCFG_CONTROL__1_TypeDef CONTROL__1; /*!< Offset: 0x0 */ __I IOSCBCFG_STATUS_TypeDef STATUS; /*!< Offset: 0x4 */ __IO IOSCBCFG_TIMER_TypeDef TIMER; /*!< Offset: 0x8 */ } IOSCBCFG_TypeDef; /*============================== g5_mss_top_scb_regs definitions ===========================*/ typedef union{ /*!< SOFT_RESET register definition*/ __IO uint32_t SOFT_RESET; struct { __O uint32_t NV_MAP :1; __O uint32_t V_MAP :1; __I uint32_t reserved_01 :6; __O uint32_t PERIPH :1; __I uint32_t reserved_02 :7; __I uint32_t BLOCKID :16; } bitfield; } g5_mss_top_scb_regs_SOFT_RESET_TypeDef; typedef union{ /*!< AXI_WSETUP register definition*/ __IO uint32_t AXI_WSETUP; struct { __IO uint32_t ADDR :6; __IO uint32_t BURST :2; __IO uint32_t LENGTH :8; __IO uint32_t SIZE :3; __IO uint32_t LOCK :1; __IO uint32_t CACHE :4; __IO uint32_t PROT :3; __IO uint32_t QOS :4; __IO uint32_t SYSTEM :1; } bitfield; } g5_mss_top_scb_regs_AXI_WSETUP_TypeDef; typedef union{ /*!< AXI_WADDR register definition*/ __IO uint32_t AXI_WADDR; struct { __IO uint32_t ADDR :32; } bitfield; } g5_mss_top_scb_regs_AXI_WADDR_TypeDef; typedef union{ /*!< AXI_WDATA register definition*/ __IO uint32_t AXI_WDATA; struct { __IO uint32_t DATA :32; } bitfield; } g5_mss_top_scb_regs_AXI_WDATA_TypeDef; typedef union{ /*!< AXI_RSETUP register definition*/ __IO uint32_t AXI_RSETUP; struct { __IO uint32_t ADDR :6; __IO uint32_t BURST :2; __IO uint32_t LENGTH :8; __IO uint32_t SIZE :3; __IO uint32_t LOCK :1; __IO uint32_t CACHE :4; __IO uint32_t PROT :3; __IO uint32_t QOS :4; __IO uint32_t SYSTEM :1; } bitfield; } g5_mss_top_scb_regs_AXI_RSETUP_TypeDef; typedef union{ /*!< AXI_RADDR register definition*/ __IO uint32_t AXI_RADDR; struct { __IO uint32_t ADDR :32; } bitfield; } g5_mss_top_scb_regs_AXI_RADDR_TypeDef; typedef union{ /*!< AXI_RDATA register definition*/ __IO uint32_t AXI_RDATA; struct { __IO uint32_t DATA :32; } bitfield; } g5_mss_top_scb_regs_AXI_RDATA_TypeDef; typedef union{ /*!< AXI_STATUS register definition*/ __IO uint32_t AXI_STATUS; struct { __IO uint32_t WRITE_BUSY :1; __IO uint32_t READ_BUSY :1; __IO uint32_t WRITE_ERROR :1; __IO uint32_t READ_ERROR :1; __IO uint32_t WRITE_COUNT :5; __IO uint32_t READ_COUNT :5; __IO uint32_t READ_OVERRUN :1; __IO uint32_t WRITE_OVERRUN :1; __IO uint32_t WRITE_RESPONSE :2; __IO uint32_t READ_RESPONSE :2; __IO uint32_t MSS_RESET :1; __I uint32_t reserved_01 :3; __IO uint32_t INT_ENABLE_READ_ORUN :1; __IO uint32_t INT_ENABLE_WRITE_ORUN :1; __IO uint32_t INT_ENABLE_RRESP :1; __IO uint32_t INT_ENABLE_WRESP :1; __IO uint32_t INT_ENABLE_SYSREG :1; __I uint32_t reserved_02 :3; } bitfield; } g5_mss_top_scb_regs_AXI_STATUS_TypeDef; typedef union{ /*!< AXI_CONTROL register definition*/ __IO uint32_t AXI_CONTROL; struct { __IO uint32_t ABORT :1; __I uint32_t reserved_01 :7; __IO uint32_t STALL_WRITE :1; __I uint32_t reserved_02 :7; __IO uint32_t START_WRITE :1; __I uint32_t reserved_03 :15; } bitfield; } g5_mss_top_scb_regs_AXI_CONTROL_TypeDef; typedef union{ /*!< REDUNDANCY register definition*/ __IO uint32_t REDUNDANCY; struct { __IO uint32_t RESET :1; __IO uint32_t ISOLATE :1; __IO uint32_t NOCLOCK :1; __I uint32_t reserved_01 :29; } bitfield; } g5_mss_top_scb_regs_REDUNDANCY_TypeDef; typedef union{ /*!< BIST_CONFIG register definition*/ __IO uint32_t BIST_CONFIG; struct { __I uint32_t enabled :1; __IO uint32_t enable :1; __IO uint32_t reset :1; __IO uint32_t diag_select :1; __I uint32_t reserved_01 :4; __IO uint32_t select :5; __I uint32_t reserved_02 :3; __IO uint32_t margin :3; __I uint32_t reserved_03 :13; } bitfield; } g5_mss_top_scb_regs_BIST_CONFIG_TypeDef; typedef union{ /*!< BIST_DATA register definition*/ __IO uint32_t BIST_DATA; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BIST_DATA_TypeDef; typedef union{ /*!< BIST_COMMAND register definition*/ __IO uint32_t BIST_COMMAND; struct { __IO uint32_t update :1; __IO uint32_t capture :1; __IO uint32_t shift :1; __I uint32_t busy :1; __I uint32_t reserved_01 :4; __IO uint32_t length :7; __I uint32_t reserved_02 :17; } bitfield; } g5_mss_top_scb_regs_BIST_COMMAND_TypeDef; typedef union{ /*!< MSS_RESET_CR register definition*/ __IO uint32_t MSS_RESET_CR; struct { __IO uint32_t CPU :1; __IO uint32_t MSS :1; __I uint32_t CPUINRESET :1; __IO uint32_t REBOOT_REQUEST :1; __I uint32_t reserved_01 :4; __IO uint32_t SGMII :1; __I uint32_t reserved_02 :7; __I uint32_t REASON :9; __I uint32_t reserved_03 :7; } bitfield; } g5_mss_top_scb_regs_MSS_RESET_CR_TypeDef; typedef union{ /*!< MSS_STATUS register definition*/ __IO uint32_t MSS_STATUS; struct { __IO uint32_t boot_status :4; __I uint32_t watchdog :5; __I uint32_t debug_active :1; __I uint32_t halt_cpu0 :1; __I uint32_t halt_cpu1 :1; __I uint32_t halt_cpu2 :1; __I uint32_t halt_cpu3 :1; __I uint32_t halt_cpu4 :1; __I uint32_t ecc_error_l2 :1; __I uint32_t ecc_error_other :1; __I uint32_t reserved_01 :15; } bitfield; } g5_mss_top_scb_regs_MSS_STATUS_TypeDef; typedef union{ /*!< BOOT_ADDR0 register definition*/ __IO uint32_t BOOT_ADDR0; struct { __IO uint32_t address :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ADDR0_TypeDef; typedef union{ /*!< BOOT_ADDR1 register definition*/ __IO uint32_t BOOT_ADDR1; struct { __IO uint32_t address :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ADDR1_TypeDef; typedef union{ /*!< BOOT_ADDR2 register definition*/ __IO uint32_t BOOT_ADDR2; struct { __IO uint32_t address :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ADDR2_TypeDef; typedef union{ /*!< BOOT_ADDR3 register definition*/ __IO uint32_t BOOT_ADDR3; struct { __IO uint32_t address :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ADDR3_TypeDef; typedef union{ /*!< BOOT_ADDR4 register definition*/ __IO uint32_t BOOT_ADDR4; struct { __IO uint32_t address :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ADDR4_TypeDef; typedef union{ /*!< BOOT_ROM0 register definition*/ __IO uint32_t BOOT_ROM0; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM0_TypeDef; typedef union{ /*!< BOOT_ROM1 register definition*/ __IO uint32_t BOOT_ROM1; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM1_TypeDef; typedef union{ /*!< BOOT_ROM2 register definition*/ __IO uint32_t BOOT_ROM2; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM2_TypeDef; typedef union{ /*!< BOOT_ROM3 register definition*/ __IO uint32_t BOOT_ROM3; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM3_TypeDef; typedef union{ /*!< BOOT_ROM4 register definition*/ __IO uint32_t BOOT_ROM4; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM4_TypeDef; typedef union{ /*!< BOOT_ROM5 register definition*/ __IO uint32_t BOOT_ROM5; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM5_TypeDef; typedef union{ /*!< BOOT_ROM6 register definition*/ __IO uint32_t BOOT_ROM6; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM6_TypeDef; typedef union{ /*!< BOOT_ROM7 register definition*/ __IO uint32_t BOOT_ROM7; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_BOOT_ROM7_TypeDef; typedef union{ /*!< FLASH_FREEZE register definition*/ __IO uint32_t FLASH_FREEZE; struct { __IO uint32_t in_progress :1; __I uint32_t reserved_01 :31; } bitfield; } g5_mss_top_scb_regs_FLASH_FREEZE_TypeDef; typedef union{ /*!< G5CIO register definition*/ __IO uint32_t G5CIO; struct { __IO uint32_t ioout :1; __I uint32_t reserved_01 :31; } bitfield; } g5_mss_top_scb_regs_G5CIO_TypeDef; typedef union{ /*!< DEVICE_ID register definition*/ __IO uint32_t DEVICE_ID; struct { __IO uint32_t idp :16; __IO uint32_t idv :4; __I uint32_t reserved_01 :12; } bitfield; } g5_mss_top_scb_regs_DEVICE_ID_TypeDef; typedef union{ /*!< MESSAGE_INT register definition*/ __IO uint32_t MESSAGE_INT; struct { __IO uint32_t active :1; __I uint32_t reserved_01 :31; } bitfield; } g5_mss_top_scb_regs_MESSAGE_INT_TypeDef; typedef union{ /*!< MESSAGE register definition*/ __IO uint32_t MESSAGE; struct { __IO uint32_t data :32; } bitfield; } g5_mss_top_scb_regs_MESSAGE_TypeDef; typedef union{ /*!< DEVRST_INT register definition*/ __IO uint32_t DEVRST_INT; struct { __IO uint32_t active :1; __I uint32_t reserved_01 :31; } bitfield; } g5_mss_top_scb_regs_DEVRST_INT_TypeDef; typedef union{ /*!< SCB_INTERRUPT register definition*/ __IO uint32_t SCB_INTERRUPT; struct { __IO uint32_t active :1; __I uint32_t reserved_01 :31; } bitfield; } g5_mss_top_scb_regs_SCB_INTERRUPT_TypeDef; typedef union{ /*!< MSS_INTERRUPT register definition*/ __IO uint32_t MSS_INTERRUPT; struct { __IO uint32_t active :1; __I uint32_t reserved_01 :31; } bitfield; } g5_mss_top_scb_regs_MSS_INTERRUPT_TypeDef; typedef union{ /*!< DEVICE_CONFIG_CR register definition*/ __IO uint32_t DEVICE_CONFIG_CR; struct { __IO uint32_t FACTORY_TEST_MODE :1; __I uint32_t RESERVED :1; __IO uint32_t CRYPTO_DISABLE :1; __IO uint32_t CAN_ALLOWED :1; __IO uint32_t CPU_ALLOWED :1; __IO uint32_t CPU_DISABLE :1; __I uint32_t reserved_01 :2; __IO uint32_t CPU_BIST_DISABLE :1; __I uint32_t reserved_02 :7; __IO uint32_t DISABLE_XIP :1; __I uint32_t reserved_03 :15; } bitfield; } g5_mss_top_scb_regs_DEVICE_CONFIG_CR_TypeDef; typedef union{ /*!< ATHENA_CR register definition*/ __IO uint32_t ATHENA_CR; struct { __IO uint32_t mss_mode :3; __I uint32_t reserved_01 :1; __IO uint32_t stream_enable :1; __I uint32_t reserved_02 :27; } bitfield; } g5_mss_top_scb_regs_ATHENA_CR_TypeDef; typedef union{ /*!< ENVM_CR register definition*/ __IO uint32_t ENVM_CR; struct { __IO uint32_t clock_period :6; __I uint32_t reserved_01 :2; __IO uint32_t clock_continuous :1; __IO uint32_t clock_suppress :1; __I uint32_t reserved_02 :6; __IO uint32_t readahead :1; __IO uint32_t slowread :1; __IO uint32_t interrupt_enable :1; __I uint32_t reserved_03 :5; __IO uint32_t timer :8; } bitfield; } g5_mss_top_scb_regs_ENVM_CR_TypeDef; typedef union{ /*!< ENVM_POWER_CR register definition*/ __IO uint32_t ENVM_POWER_CR; struct { __IO uint32_t reset :1; __IO uint32_t pd1 :1; __IO uint32_t pd2 :1; __IO uint32_t pd3 :1; __IO uint32_t pd4 :1; __IO uint32_t iso :1; __IO uint32_t sleep :1; __I uint32_t reserved_01 :1; __IO uint32_t override :1; __I uint32_t reserved_02 :23; } bitfield; } g5_mss_top_scb_regs_ENVM_POWER_CR_TypeDef; typedef union{ /*!< RAM_SHUTDOWN_CR register definition*/ __IO uint32_t RAM_SHUTDOWN_CR; struct { __IO uint32_t can0 :1; __IO uint32_t can1 :1; __IO uint32_t usb :1; __IO uint32_t gem0 :1; __IO uint32_t gem1 :1; __IO uint32_t mmc :1; __IO uint32_t athena :1; __IO uint32_t ddrc :1; __IO uint32_t e51 :1; __IO uint32_t u54_1 :1; __IO uint32_t u54_2 :1; __IO uint32_t u54_3 :1; __IO uint32_t u54_4 :1; __IO uint32_t l2 :1; __I uint32_t reserved_01 :18; } bitfield; } g5_mss_top_scb_regs_RAM_SHUTDOWN_CR_TypeDef; typedef union{ /*!< RAM_MARGIN_CR register definition*/ __IO uint32_t RAM_MARGIN_CR; struct { __IO uint32_t enable :1; __IO uint32_t can0 :2; __IO uint32_t can1 :2; __IO uint32_t usb :2; __IO uint32_t gem0 :2; __IO uint32_t gem1 :2; __IO uint32_t mmc :2; __IO uint32_t ddrc :2; __IO uint32_t e51 :2; __IO uint32_t u54_1 :2; __IO uint32_t u54_2 :2; __IO uint32_t u54_3 :2; __IO uint32_t u54_4 :2; __IO uint32_t l2 :2; __I uint32_t reserved_01 :5; } bitfield; } g5_mss_top_scb_regs_RAM_MARGIN_CR_TypeDef; typedef union{ /*!< TRACE_CR register definition*/ __IO uint32_t TRACE_CR; struct { __IO uint32_t CPU_DEBUG_DISABLE :1; __IO uint32_t ULTRASOC_DISABLE_JTAG :1; __IO uint32_t ULTRASOC_DISABLE_AXI :1; __I uint32_t reserved_01 :5; __IO uint32_t ULTRASOC_FABRIC :1; __I uint32_t reserved_02 :23; } bitfield; } g5_mss_top_scb_regs_TRACE_CR_TypeDef; typedef union{ /*!< MSSIO_CONTROL_CR register definition*/ __IO uint32_t MSSIO_CONTROL_CR; struct { __IO uint32_t lp_state_mss :1; __IO uint32_t lp_state_ip_mss :1; __IO uint32_t lp_state_op_mss :1; __IO uint32_t lp_state_persist_mss :1; __IO uint32_t lp_state_bypass_mss :1; __IO uint32_t lp_pll_locked_mss :1; __IO uint32_t lp_stop_clocks_out_mss :1; __I uint32_t lp_stop_clocks_done_mss :1; __IO uint32_t mss_dce :3; __IO uint32_t mss_core_up :1; __IO uint32_t mss_flash_valid :1; __IO uint32_t mss_io_en :1; __IO uint32_t mss_sel_hw_dyn :1; __IO uint32_t mss_sel_hw_def :1; __I uint32_t reserved_01 :16; } bitfield; } g5_mss_top_scb_regs_MSSIO_CONTROL_CR_TypeDef; typedef union{ /*!< MSS_IO_LOCKDOWN_CR register definition*/ __I uint32_t MSS_IO_LOCKDOWN_CR; struct { __I uint32_t mssio_b2_lockdn_en :1; __I uint32_t mssio_b4_lockdn_en :1; __I uint32_t sgmii_io_lockdn_en :1; __I uint32_t ddr_io_lockdn_en :1; __I uint32_t reserved_01 :28; } bitfield; } g5_mss_top_scb_regs_MSS_IO_LOCKDOWN_CR_TypeDef; typedef union{ /*!< MSSIO_BANK2_CFG_CR register definition*/ __IO uint32_t MSSIO_BANK2_CFG_CR; struct { __IO uint32_t bank_pcode :6; __I uint32_t reserved_01 :2; __IO uint32_t bank_ncode :6; __I uint32_t reserved_02 :2; __IO uint32_t vs :4; __I uint32_t reserved_03 :12; } bitfield; } g5_mss_top_scb_regs_MSSIO_BANK2_CFG_CR_TypeDef; typedef union{ /*!< MSSIO_BANK4_CFG_CR register definition*/ __IO uint32_t MSSIO_BANK4_CFG_CR; struct { __IO uint32_t bank_pcode :6; __I uint32_t reserved_01 :2; __IO uint32_t bank_ncode :6; __I uint32_t reserved_02 :2; __IO uint32_t vs :4; __I uint32_t reserved_03 :12; } bitfield; } g5_mss_top_scb_regs_MSSIO_BANK4_CFG_CR_TypeDef; typedef union{ /*!< DLL0_CTRL0 register definition*/ __IO uint32_t DLL0_CTRL0; struct { __IO uint32_t phase_p :2; __IO uint32_t phase_s :2; __IO uint32_t sel_p :2; __IO uint32_t sel_s :2; __IO uint32_t ref_sel :1; __IO uint32_t fb_sel :1; __IO uint32_t div_sel :1; __I uint32_t reserved :3; __IO uint32_t alu_upd :2; __I uint32_t reserved2 :3; __IO uint32_t lock_frc :1; __IO uint32_t lock_flt :2; __I uint32_t reserved3 :2; __IO uint32_t lock_high :4; __IO uint32_t lock_low :4; } bitfield; } g5_mss_top_scb_regs_DLL0_CTRL0_TypeDef; typedef union{ /*!< DLL0_CTRL1 register definition*/ __IO uint32_t DLL0_CTRL1; struct { __IO uint32_t set_alu :8; __IO uint32_t adj_del4 :7; __IO uint32_t test_s :1; __I uint32_t reserved :7; __IO uint32_t test_ring :1; __IO uint32_t init_code :6; __IO uint32_t relock_fast :1; __I uint32_t reserved2 :1; } bitfield; } g5_mss_top_scb_regs_DLL0_CTRL1_TypeDef; typedef union{ /*!< DLL0_STAT0 register definition*/ __IO uint32_t DLL0_STAT0; struct { __IO uint32_t reset :1; __IO uint32_t bypass :1; __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :3; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :1; __I uint32_t reserved8 :1; __IO uint32_t phase_move_clk :1; __I uint32_t reserved9 :1; __I uint32_t reserved10 :2; __I uint32_t reserved11 :8; __I uint32_t reserved12 :8; } bitfield; } g5_mss_top_scb_regs_DLL0_STAT0_TypeDef; typedef union{ /*!< DLL0_STAT1 register definition*/ __I uint32_t DLL0_STAT1; struct { __I uint32_t sro_del4 :7; __I uint32_t reserved :1; __I uint32_t reserved2 :8; __I uint32_t sro_alu_cnt :9; __I uint32_t reserved3 :1; __I uint32_t reserved4 :2; __I uint32_t reserved5 :2; __I uint32_t reserved6 :2; } bitfield; } g5_mss_top_scb_regs_DLL0_STAT1_TypeDef; typedef union{ /*!< DLL0_STAT2 register definition*/ __I uint32_t DLL0_STAT2; struct { __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t sro_lock :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :1; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :9; __I uint32_t reserved8 :8; __I uint32_t reserved9 :8; } bitfield; } g5_mss_top_scb_regs_DLL0_STAT2_TypeDef; typedef union{ /*!< DLL0_TEST register definition*/ __IO uint32_t DLL0_TEST; struct { __IO uint32_t cfm_enable :1; __IO uint32_t cfm_select :1; __IO uint32_t ref_select :1; __I uint32_t reserved :1; __I uint32_t reserved_01 :28; } bitfield; } g5_mss_top_scb_regs_DLL0_TEST_TypeDef; typedef union{ /*!< DLL1_CTRL0 register definition*/ __IO uint32_t DLL1_CTRL0; struct { __IO uint32_t phase_p :2; __IO uint32_t phase_s :2; __IO uint32_t sel_p :2; __IO uint32_t sel_s :2; __IO uint32_t ref_sel :1; __IO uint32_t fb_sel :1; __IO uint32_t div_sel :1; __I uint32_t reserved :3; __IO uint32_t alu_upd :2; __I uint32_t reserved2 :3; __IO uint32_t lock_frc :1; __IO uint32_t lock_flt :2; __I uint32_t reserved3 :2; __IO uint32_t lock_high :4; __IO uint32_t lock_low :4; } bitfield; } g5_mss_top_scb_regs_DLL1_CTRL0_TypeDef; typedef union{ /*!< DLL1_CTRL1 register definition*/ __IO uint32_t DLL1_CTRL1; struct { __IO uint32_t set_alu :8; __IO uint32_t adj_del4 :7; __IO uint32_t test_s :1; __I uint32_t reserved :7; __IO uint32_t test_ring :1; __IO uint32_t init_code :6; __IO uint32_t relock_fast :1; __I uint32_t reserved2 :1; } bitfield; } g5_mss_top_scb_regs_DLL1_CTRL1_TypeDef; typedef union{ /*!< DLL1_STAT0 register definition*/ __IO uint32_t DLL1_STAT0; struct { __IO uint32_t reset :1; __IO uint32_t bypass :1; __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :3; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :1; __I uint32_t reserved8 :1; __IO uint32_t phase_move_clk :1; __I uint32_t reserved9 :1; __I uint32_t reserved10 :2; __I uint32_t reserved11 :8; __I uint32_t reserved12 :8; } bitfield; } g5_mss_top_scb_regs_DLL1_STAT0_TypeDef; typedef union{ /*!< DLL1_STAT1 register definition*/ __I uint32_t DLL1_STAT1; struct { __I uint32_t sro_del4 :7; __I uint32_t reserved :1; __I uint32_t reserved2 :8; __I uint32_t sro_alu_cnt :9; __I uint32_t reserved3 :1; __I uint32_t reserved4 :2; __I uint32_t reserved5 :2; __I uint32_t reserved6 :2; } bitfield; } g5_mss_top_scb_regs_DLL1_STAT1_TypeDef; typedef union{ /*!< DLL1_STAT2 register definition*/ __I uint32_t DLL1_STAT2; struct { __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t sro_lock :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :1; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :9; __I uint32_t reserved8 :8; __I uint32_t reserved9 :8; } bitfield; } g5_mss_top_scb_regs_DLL1_STAT2_TypeDef; typedef union{ /*!< DLL1_TEST register definition*/ __IO uint32_t DLL1_TEST; struct { __IO uint32_t cfm_enable :1; __IO uint32_t cfm_select :1; __IO uint32_t ref_select :1; __I uint32_t reserved :1; __I uint32_t reserved_01 :28; } bitfield; } g5_mss_top_scb_regs_DLL1_TEST_TypeDef; typedef union{ /*!< DLL2_CTRL0 register definition*/ __IO uint32_t DLL2_CTRL0; struct { __IO uint32_t phase_p :2; __IO uint32_t phase_s :2; __IO uint32_t sel_p :2; __IO uint32_t sel_s :2; __IO uint32_t ref_sel :1; __IO uint32_t fb_sel :1; __IO uint32_t div_sel :1; __I uint32_t reserved :3; __IO uint32_t alu_upd :2; __I uint32_t reserved2 :3; __IO uint32_t lock_frc :1; __IO uint32_t lock_flt :2; __I uint32_t reserved3 :2; __IO uint32_t lock_high :4; __IO uint32_t lock_low :4; } bitfield; } g5_mss_top_scb_regs_DLL2_CTRL0_TypeDef; typedef union{ /*!< DLL2_CTRL1 register definition*/ __IO uint32_t DLL2_CTRL1; struct { __IO uint32_t set_alu :8; __IO uint32_t adj_del4 :7; __IO uint32_t test_s :1; __I uint32_t reserved :7; __IO uint32_t test_ring :1; __IO uint32_t init_code :6; __IO uint32_t relock_fast :1; __I uint32_t reserved2 :1; } bitfield; } g5_mss_top_scb_regs_DLL2_CTRL1_TypeDef; typedef union{ /*!< DLL2_STAT0 register definition*/ __IO uint32_t DLL2_STAT0; struct { __IO uint32_t reset :1; __IO uint32_t bypass :1; __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :3; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :1; __I uint32_t reserved8 :1; __IO uint32_t phase_move_clk :1; __I uint32_t reserved9 :1; __I uint32_t reserved10 :2; __I uint32_t reserved11 :8; __I uint32_t reserved12 :8; } bitfield; } g5_mss_top_scb_regs_DLL2_STAT0_TypeDef; typedef union{ /*!< DLL2_STAT1 register definition*/ __I uint32_t DLL2_STAT1; struct { __I uint32_t sro_del4 :7; __I uint32_t reserved :1; __I uint32_t reserved2 :8; __I uint32_t sro_alu_cnt :9; __I uint32_t reserved3 :1; __I uint32_t reserved4 :2; __I uint32_t reserved5 :2; __I uint32_t reserved6 :2; } bitfield; } g5_mss_top_scb_regs_DLL2_STAT1_TypeDef; typedef union{ /*!< DLL2_STAT2 register definition*/ __I uint32_t DLL2_STAT2; struct { __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t sro_lock :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :1; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :9; __I uint32_t reserved8 :8; __I uint32_t reserved9 :8; } bitfield; } g5_mss_top_scb_regs_DLL2_STAT2_TypeDef; typedef union{ /*!< DLL2_TEST register definition*/ __IO uint32_t DLL2_TEST; struct { __IO uint32_t cfm_enable :1; __IO uint32_t cfm_select :1; __IO uint32_t ref_select :1; __I uint32_t reserved :1; __I uint32_t reserved_01 :28; } bitfield; } g5_mss_top_scb_regs_DLL2_TEST_TypeDef; typedef union{ /*!< DLL3_CTRL0 register definition*/ __IO uint32_t DLL3_CTRL0; struct { __IO uint32_t phase_p :2; __IO uint32_t phase_s :2; __IO uint32_t sel_p :2; __IO uint32_t sel_s :2; __IO uint32_t ref_sel :1; __IO uint32_t fb_sel :1; __IO uint32_t div_sel :1; __I uint32_t reserved :3; __IO uint32_t alu_upd :2; __I uint32_t reserved2 :3; __IO uint32_t lock_frc :1; __IO uint32_t lock_flt :2; __I uint32_t reserved3 :2; __IO uint32_t lock_high :4; __IO uint32_t lock_low :4; } bitfield; } g5_mss_top_scb_regs_DLL3_CTRL0_TypeDef; typedef union{ /*!< DLL3_CTRL1 register definition*/ __IO uint32_t DLL3_CTRL1; struct { __IO uint32_t set_alu :8; __IO uint32_t adj_del4 :7; __IO uint32_t test_s :1; __I uint32_t reserved :7; __IO uint32_t test_ring :1; __IO uint32_t init_code :6; __IO uint32_t relock_fast :1; __I uint32_t reserved2 :1; } bitfield; } g5_mss_top_scb_regs_DLL3_CTRL1_TypeDef; typedef union{ /*!< DLL3_STAT0 register definition*/ __IO uint32_t DLL3_STAT0; struct { __IO uint32_t reset :1; __IO uint32_t bypass :1; __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :3; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :1; __I uint32_t reserved8 :1; __IO uint32_t phase_move_clk :1; __I uint32_t reserved9 :1; __I uint32_t reserved10 :2; __I uint32_t reserved11 :8; __I uint32_t reserved12 :8; } bitfield; } g5_mss_top_scb_regs_DLL3_STAT0_TypeDef; typedef union{ /*!< DLL3_STAT1 register definition*/ __I uint32_t DLL3_STAT1; struct { __I uint32_t sro_del4 :7; __I uint32_t reserved :1; __I uint32_t reserved2 :8; __I uint32_t sro_alu_cnt :9; __I uint32_t reserved3 :1; __I uint32_t reserved4 :2; __I uint32_t reserved5 :2; __I uint32_t reserved6 :2; } bitfield; } g5_mss_top_scb_regs_DLL3_STAT1_TypeDef; typedef union{ /*!< DLL3_STAT2 register definition*/ __I uint32_t DLL3_STAT2; struct { __I uint32_t reserved :1; __I uint32_t reserved2 :1; __I uint32_t sro_lock :1; __I uint32_t reserved3 :1; __I uint32_t reserved4 :1; __I uint32_t reserved5 :1; __I uint32_t reserved6 :1; __I uint32_t reserved7 :9; __I uint32_t reserved8 :8; __I uint32_t reserved9 :8; } bitfield; } g5_mss_top_scb_regs_DLL3_STAT2_TypeDef; typedef union{ /*!< DLL3_TEST register definition*/ __IO uint32_t DLL3_TEST; struct { __IO uint32_t cfm_enable :1; __IO uint32_t cfm_select :1; __IO uint32_t ref_select :1; __I uint32_t reserved :1; __I uint32_t reserved_01 :28; } bitfield; } g5_mss_top_scb_regs_DLL3_TEST_TypeDef; typedef union{ /*!< MSSIO_VB2_CFG register definition*/ __IO uint32_t MSSIO_VB2_CFG; struct { __IO uint32_t dpc_io_cfg_ibufmd_0 :1; __IO uint32_t dpc_io_cfg_ibufmd_1 :1; __IO uint32_t dpc_io_cfg_ibufmd_2 :1; __IO uint32_t dpc_io_cfg_drv_0 :1; __IO uint32_t dpc_io_cfg_drv_1 :1; __IO uint32_t dpc_io_cfg_drv_2 :1; __IO uint32_t dpc_io_cfg_drv_3 :1; __IO uint32_t dpc_io_cfg_clamp :1; __IO uint32_t dpc_io_cfg_enhyst :1; __IO uint32_t dpc_io_cfg_lockdn_en :1; __IO uint32_t dpc_io_cfg_wpd :1; __IO uint32_t dpc_io_cfg_wpu :1; __IO uint32_t dpc_io_cfg_atp_en :1; __IO uint32_t dpc_io_cfg_lp_persist_en :1; __IO uint32_t dpc_io_cfg_lp_bypass_en :1; __I uint32_t reserved_01 :17; } bitfield; } g5_mss_top_scb_regs_MSSIO_VB2_CFG_TypeDef; typedef union{ /*!< MSSIO_VB4_CFG register definition*/ __IO uint32_t MSSIO_VB4_CFG; struct { __IO uint32_t dpc_io_cfg_ibufmd_0 :1; __IO uint32_t dpc_io_cfg_ibufmd_1 :1; __IO uint32_t dpc_io_cfg_ibufmd_2 :1; __IO uint32_t dpc_io_cfg_drv_0 :1; __IO uint32_t dpc_io_cfg_drv_1 :1; __IO uint32_t dpc_io_cfg_drv_2 :1; __IO uint32_t dpc_io_cfg_drv_3 :1; __IO uint32_t dpc_io_cfg_clamp :1; __IO uint32_t dpc_io_cfg_enhyst :1; __IO uint32_t dpc_io_cfg_lockdn_en :1; __IO uint32_t dpc_io_cfg_wpd :1; __IO uint32_t dpc_io_cfg_wpu :1; __IO uint32_t dpc_io_cfg_atp_en :1; __IO uint32_t dpc_io_cfg_lp_persist_en :1; __IO uint32_t dpc_io_cfg_lp_bypass_en :1; __I uint32_t reserved_01 :17; } bitfield; } g5_mss_top_scb_regs_MSSIO_VB4_CFG_TypeDef; /*------------ g5_mss_top_scb_regs definition -----------*/ typedef struct { __IO g5_mss_top_scb_regs_SOFT_RESET_TypeDef SOFT_RESET; /*!< Offset: 0x0 */ __I uint32_t UNUSED_SPACE0[3]; /*!< Offset: 0x4 */ __IO g5_mss_top_scb_regs_AXI_WSETUP_TypeDef AXI_WSETUP; /*!< Offset: 0x10 */ __IO g5_mss_top_scb_regs_AXI_WADDR_TypeDef AXI_WADDR; /*!< Offset: 0x14 */ __IO g5_mss_top_scb_regs_AXI_WDATA_TypeDef AXI_WDATA; /*!< Offset: 0x18 */ __IO g5_mss_top_scb_regs_AXI_RSETUP_TypeDef AXI_RSETUP; /*!< Offset: 0x1c */ __IO g5_mss_top_scb_regs_AXI_RADDR_TypeDef AXI_RADDR; /*!< Offset: 0x20 */ __IO g5_mss_top_scb_regs_AXI_RDATA_TypeDef AXI_RDATA; /*!< Offset: 0x24 */ __IO g5_mss_top_scb_regs_AXI_STATUS_TypeDef AXI_STATUS; /*!< Offset: 0x28 */ __IO g5_mss_top_scb_regs_AXI_CONTROL_TypeDef AXI_CONTROL; /*!< Offset: 0x2c */ __IO g5_mss_top_scb_regs_REDUNDANCY_TypeDef REDUNDANCY; /*!< Offset: 0x30 */ __I uint32_t UNUSED_SPACE1[7]; /*!< Offset: 0x34 */ __IO g5_mss_top_scb_regs_BIST_CONFIG_TypeDef BIST_CONFIG; /*!< Offset: 0x50 */ __IO g5_mss_top_scb_regs_BIST_DATA_TypeDef BIST_DATA; /*!< Offset: 0x54 */ __IO g5_mss_top_scb_regs_BIST_COMMAND_TypeDef BIST_COMMAND; /*!< Offset: 0x58 */ __I uint32_t UNUSED_SPACE2[41]; /*!< Offset: 0x5c */ __IO g5_mss_top_scb_regs_MSS_RESET_CR_TypeDef MSS_RESET_CR; /*!< Offset: 0x100 */ __IO g5_mss_top_scb_regs_MSS_STATUS_TypeDef MSS_STATUS; /*!< Offset: 0x104 */ __IO g5_mss_top_scb_regs_BOOT_ADDR0_TypeDef BOOT_ADDR0; /*!< Offset: 0x108 */ __IO g5_mss_top_scb_regs_BOOT_ADDR1_TypeDef BOOT_ADDR1; /*!< Offset: 0x10c */ __IO g5_mss_top_scb_regs_BOOT_ADDR2_TypeDef BOOT_ADDR2; /*!< Offset: 0x110 */ __IO g5_mss_top_scb_regs_BOOT_ADDR3_TypeDef BOOT_ADDR3; /*!< Offset: 0x114 */ __IO g5_mss_top_scb_regs_BOOT_ADDR4_TypeDef BOOT_ADDR4; /*!< Offset: 0x118 */ __I uint32_t UNUSED_SPACE3; /*!< Offset: 0x11c */ __IO g5_mss_top_scb_regs_BOOT_ROM0_TypeDef BOOT_ROM0; /*!< Offset: 0x120 */ __IO g5_mss_top_scb_regs_BOOT_ROM1_TypeDef BOOT_ROM1; /*!< Offset: 0x124 */ __IO g5_mss_top_scb_regs_BOOT_ROM2_TypeDef BOOT_ROM2; /*!< Offset: 0x128 */ __IO g5_mss_top_scb_regs_BOOT_ROM3_TypeDef BOOT_ROM3; /*!< Offset: 0x12c */ __IO g5_mss_top_scb_regs_BOOT_ROM4_TypeDef BOOT_ROM4; /*!< Offset: 0x130 */ __IO g5_mss_top_scb_regs_BOOT_ROM5_TypeDef BOOT_ROM5; /*!< Offset: 0x134 */ __IO g5_mss_top_scb_regs_BOOT_ROM6_TypeDef BOOT_ROM6; /*!< Offset: 0x138 */ __IO g5_mss_top_scb_regs_BOOT_ROM7_TypeDef BOOT_ROM7; /*!< Offset: 0x13c */ __I uint32_t UNUSED_SPACE4[16]; /*!< Offset: 0x140 */ __IO g5_mss_top_scb_regs_FLASH_FREEZE_TypeDef FLASH_FREEZE; /*!< Offset: 0x180 */ __IO g5_mss_top_scb_regs_G5CIO_TypeDef G5CIO; /*!< Offset: 0x184 */ __IO g5_mss_top_scb_regs_DEVICE_ID_TypeDef DEVICE_ID; /*!< Offset: 0x188 */ __IO g5_mss_top_scb_regs_MESSAGE_INT_TypeDef MESSAGE_INT; /*!< Offset: 0x18c */ __IO g5_mss_top_scb_regs_MESSAGE_TypeDef MESSAGE; /*!< Offset: 0x190 */ __IO g5_mss_top_scb_regs_DEVRST_INT_TypeDef DEVRST_INT; /*!< Offset: 0x194 */ __IO g5_mss_top_scb_regs_SCB_INTERRUPT_TypeDef SCB_INTERRUPT; /*!< Offset: 0x198 */ __IO g5_mss_top_scb_regs_MSS_INTERRUPT_TypeDef MSS_INTERRUPT; /*!< Offset: 0x19c */ __IO g5_mss_top_scb_regs_DEVICE_CONFIG_CR_TypeDef DEVICE_CONFIG_CR; /*!< Offset: 0x1a0 */ __IO g5_mss_top_scb_regs_ATHENA_CR_TypeDef ATHENA_CR; /*!< Offset: 0x1a4 */ __IO g5_mss_top_scb_regs_ENVM_CR_TypeDef ENVM_CR; /*!< Offset: 0x1a8 */ __IO g5_mss_top_scb_regs_ENVM_POWER_CR_TypeDef ENVM_POWER_CR; /*!< Offset: 0x1ac */ __IO g5_mss_top_scb_regs_RAM_SHUTDOWN_CR_TypeDef RAM_SHUTDOWN_CR; /*!< Offset: 0x1b0 */ __IO g5_mss_top_scb_regs_RAM_MARGIN_CR_TypeDef RAM_MARGIN_CR; /*!< Offset: 0x1b4 */ __IO g5_mss_top_scb_regs_TRACE_CR_TypeDef TRACE_CR; /*!< Offset: 0x1b8 */ __IO g5_mss_top_scb_regs_MSSIO_CONTROL_CR_TypeDef MSSIO_CONTROL_CR; /*!< Offset: 0x1bc */ __I g5_mss_top_scb_regs_MSS_IO_LOCKDOWN_CR_TypeDef MSS_IO_LOCKDOWN_CR; /*!< Offset: 0x1c0 */ __IO g5_mss_top_scb_regs_MSSIO_BANK2_CFG_CR_TypeDef MSSIO_BANK2_CFG_CR; /*!< Offset: 0x1c4 */ __IO g5_mss_top_scb_regs_MSSIO_BANK4_CFG_CR_TypeDef MSSIO_BANK4_CFG_CR; /*!< Offset: 0x1c8 */ __I uint32_t UNUSED_SPACE5[13]; /*!< Offset: 0x1cc */ __IO g5_mss_top_scb_regs_DLL0_CTRL0_TypeDef DLL0_CTRL0; /*!< Offset: 0x200 */ __IO g5_mss_top_scb_regs_DLL0_CTRL1_TypeDef DLL0_CTRL1; /*!< Offset: 0x204 */ __IO g5_mss_top_scb_regs_DLL0_STAT0_TypeDef DLL0_STAT0; /*!< Offset: 0x208 */ __I g5_mss_top_scb_regs_DLL0_STAT1_TypeDef DLL0_STAT1; /*!< Offset: 0x20c */ __I g5_mss_top_scb_regs_DLL0_STAT2_TypeDef DLL0_STAT2; /*!< Offset: 0x210 */ __IO g5_mss_top_scb_regs_DLL0_TEST_TypeDef DLL0_TEST; /*!< Offset: 0x214 */ __I uint32_t UNUSED_SPACE6[2]; /*!< Offset: 0x218 */ __IO g5_mss_top_scb_regs_DLL1_CTRL0_TypeDef DLL1_CTRL0; /*!< Offset: 0x220 */ __IO g5_mss_top_scb_regs_DLL1_CTRL1_TypeDef DLL1_CTRL1; /*!< Offset: 0x224 */ __IO g5_mss_top_scb_regs_DLL1_STAT0_TypeDef DLL1_STAT0; /*!< Offset: 0x228 */ __I g5_mss_top_scb_regs_DLL1_STAT1_TypeDef DLL1_STAT1; /*!< Offset: 0x22c */ __I g5_mss_top_scb_regs_DLL1_STAT2_TypeDef DLL1_STAT2; /*!< Offset: 0x230 */ __IO g5_mss_top_scb_regs_DLL1_TEST_TypeDef DLL1_TEST; /*!< Offset: 0x234 */ __I uint32_t UNUSED_SPACE7[2]; /*!< Offset: 0x238 */ __IO g5_mss_top_scb_regs_DLL2_CTRL0_TypeDef DLL2_CTRL0; /*!< Offset: 0x240 */ __IO g5_mss_top_scb_regs_DLL2_CTRL1_TypeDef DLL2_CTRL1; /*!< Offset: 0x244 */ __IO g5_mss_top_scb_regs_DLL2_STAT0_TypeDef DLL2_STAT0; /*!< Offset: 0x248 */ __I g5_mss_top_scb_regs_DLL2_STAT1_TypeDef DLL2_STAT1; /*!< Offset: 0x24c */ __I g5_mss_top_scb_regs_DLL2_STAT2_TypeDef DLL2_STAT2; /*!< Offset: 0x250 */ __IO g5_mss_top_scb_regs_DLL2_TEST_TypeDef DLL2_TEST; /*!< Offset: 0x254 */ __I uint32_t UNUSED_SPACE8[2]; /*!< Offset: 0x258 */ __IO g5_mss_top_scb_regs_DLL3_CTRL0_TypeDef DLL3_CTRL0; /*!< Offset: 0x260 */ __IO g5_mss_top_scb_regs_DLL3_CTRL1_TypeDef DLL3_CTRL1; /*!< Offset: 0x264 */ __IO g5_mss_top_scb_regs_DLL3_STAT0_TypeDef DLL3_STAT0; /*!< Offset: 0x268 */ __I g5_mss_top_scb_regs_DLL3_STAT1_TypeDef DLL3_STAT1; /*!< Offset: 0x26c */ __I g5_mss_top_scb_regs_DLL3_STAT2_TypeDef DLL3_STAT2; /*!< Offset: 0x270 */ __IO g5_mss_top_scb_regs_DLL3_TEST_TypeDef DLL3_TEST; /*!< Offset: 0x274 */ __IO g5_mss_top_scb_regs_MSSIO_VB2_CFG_TypeDef MSSIO_VB2_CFG; /*!< Offset: 0x278 */ __IO g5_mss_top_scb_regs_MSSIO_VB4_CFG_TypeDef MSSIO_VB4_CFG; /*!< Offset: 0x27c */ } g5_mss_top_scb_regs_TypeDef; #define CFG_DDR_SGMII_PHY_BASE (0x20007000) /*!< ( CFG_DDR_SGMII_PHY ) Base Address */ #define DDRCFG_BASE (0x20080000) /*!< ( DDRCFG ) Base Address */ #define SYSREGSCB_BASE (0x20003000) /*!< ( SYSREGSCB ) Base Address */ #define IOSCBCFG_BASE (0x37080000) /*!< ( IOSCBCFG ) Base Address */ extern CFG_DDR_SGMII_PHY_TypeDef * const CFG_DDR_SGMII_PHY ; extern DDR_CSR_APB_TypeDef * const DDRCFG ; extern IOSCBCFG_TypeDef * const SCBCFG_REGS ; extern g5_mss_top_scb_regs_TypeDef * const SCB_REGS ; #ifdef __cplusplus } #endif #endif /* MSS_DDR_REGS_H_ */ mss_ddr_test_pattern.c000066400000000000000000000227431432224323300412460ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ #include const uint32_t ddr_test_pattern[768] = { 0x48b301bc, 0x79330115, 0xf5330139, 0x693301bc, 0x893b00a9, 0x093b0128, 0x0d3b00c9, 0x551b00cd, 0x161b0077, 0x8d510197, 0x0127581b, 0x00e7161b, 0x01066633, 0x561b8d31, 0x8d310037, 0x8f3b9da9, 0xd61b01e5, 0x959b0112, 0xd51b00f2, 0x8e4d0132, 0x00d2959b, 0x8e2d8dc9, 0x00a2d29b, 0x005642b3, 0xa4507637, 0x005f0f3b, 0x00dac5b3, 0xceb6061b, 0x00cf063b, 0x01a5f5b3, 0x0155c5b3, 0x01460a3b, 0x00ba0a3b, 0x01ad161b, 0x006d559b, 0x015d151b, 0x561b8dd1, 0x8e4900bd, 0x551b8db1, 0x161b019d, 0x8e49007d, 0x05bb8db1, 0x161b00ba, 0x5a1b01e9, 0x151b0029, 0x6a330139, 0x561b00ca, 0x8e4900d9, 0x00ca4a33, 0x0169551b, 0x00a9161b, 0x4a338e49, 0xe63300ca, 0xf533012d, 0x7633012d, 0x8e490196, 0x00ca0a3b, 0x0077d51b, 0x0197961b, 0x00ba0a3b, 0x00b989bb, 0x959b8d51, 0xd61b00e7, 0x8e4d0127, 0xd59b8e29, 0x8e2d0037, 0xbef9a5b7, 0x3f75859b, 0x9f319f2d, 0x01770bbb, 0x011fd61b, 0x00ff971b, 0x013fd59b, 0x961b8f51, 0x8e4d00df, 0xdf9b8f31, 0x4fb300af, 0xc73301f7, 0x8fbb01a6, 0x773301fb, 0x8f350137, 0x015f8abb, 0x00ea8abb, 0x01a9961b, 0x0069d71b, 0x0159959b, 0xd61b8f51, 0x8e4d00b9, 0xd59b8f31, 0x961b0199, 0x8e4d0079, 0x873b8f31, 0x161b00ea, 0x5a9b01ea, 0x159b002a, 0xeab3013a, 0x561b00ca, 0x8e4d00da, 0x00cacab3, 0x016a559b, 0x00aa161b, 0xcab38e4d, 0x663300ca, 0x75b30149, 0x76330149, 0x8e4d01b6, 0x00ca8abb, 0x00ea8abb, 0x00ec8cbb, 0x019b161b, 0x007b571b, 0x559b8f51, 0x161b012b, 0x8e4d00eb, 0x5b1b8f31, 0x4b33003b, 0x87370167, 0x071bc671, 0x9fb98f27, 0x016787bb, 0x171b9cbd, 0x579b00ff, 0x561b011f, 0x8f5d013f, 0x00df179b, 0x8f3d8fd1, 0x00af5f1b, 0x01e74f33, 0x013d4733, 0x01e48f3b, 0x01977733, 0x01a74733, 0x00df06bb, 0xd79b9eb9, 0x971b006c, 0x961b01ac, 0x8fd9015c, 0x00bcd71b, 0x8fb98f51, 0x019cd61b, 0x007c971b, 0x8fb98f51, 0x971b9ebd, 0xd79b01ea, 0x961b002a, 0x8fd9013a, 0x00dad71b, 0x8fb98f51, 0x016ad61b, 0x00aa971b, 0x8fb98f51, 0x015a6733, 0x015a7633, 0x01277733, 0x9fb98f51, 0x9fb96722, 0x9fb56702, 0x67e2c71c, 0x01578abb, 0x262377c2, 0x8a3b0157, 0x77e20147, 0x01472823, 0x0127893b, 0x2a2367c2, 0x8dbb0127, 0x778201b7, 0x00dd86bb, 0x8cbbcf14, 0x77a20197, 0x01972e23, 0x013789bb, 0x20236786, 0x8d3b0337, 0x222301a7, 0x742a03a7, 0x696a748a, 0x6a2a69ca, 0x7b666a8a, 0x7c267bc6, 0x6d667c86, 0x614d6dc6, 0xe7b78082, 0x87936a09, 0xc51c6677, 0xbb67b7b7, 0xe8578793, 0xf7b7c55c, 0x87933c6e, 0xc91c3727, 0xa54ff7b7, 0x53a78793, 0x57b7c95c, 0x8793510e, 0xcd1c27f7, 0x9b0577b7, 0x88c78793, 0xe7b7cd5c, 0x87931f83, 0xd11c9ab7, 0x5be0d7b7, 0xd1978793, 0x00052023, 0x00052223, 0x8082d15c, 0x7139ce79, 0xf426f822, 0xe852f04a, 0xec4efc06, 0xe05ae456, 0x84aa411c, 0x073b892e, 0xc11800f6, 0xfa138432, 0x756303f7, 0x415c00c7, 0xc15c2785, 0x020a0f63, 0x04000993, 0x414989bb, 0x0009879b, 0x02f46763, 0x8a931982, 0xd9930284, 0x85ca0209, 0x8533864e, 0x50ef014a, 0x043b4b00, 0x85d60144, 0xc0ef8526, 0x041bf7cf, 0x994efc04, 0x89ca4a01, 0x00890b3b, 0x03f00a93, 0x85cea039, 0xc0ef8526, 0x8993f60f, 0x07bb0409, 0xe8e3413b, 0x579bfefa, 0x06130064, 0x063bfc00, 0x559b02f6, 0x059a0064, 0x9e2195ca, 0x0006079b, 0x7442c38d, 0x02848513, 0x74a270e2, 0x69e27902, 0x6b026aa2, 0x6a429552, 0x92011602, 0x506f6121, 0x70e24400, 0x74a27442, 0x69e27902, 0x6aa26a42, 0x61216b02, 0x80828082, 0xf0227179, 0xf406ec26, 0x41544110, 0x579b84ae, 0x969b01d6, 0x8fd50036, 0x0186d59b, 0x0106d69b, 0x00d104a3, 0x0087d693, 0x0ff6f693, 0x171b07a2, 0x8fd50036, 0x00f11523, 0x0187579b, 0x00f10623, 0x0107579b, 0x06a38321, 0x771300f1, 0x17930ff7, 0x8f5d00b6, 0x00b10423, 0x00e11723, 0x03f67613, 0x03700793, 0xe763842a, 0x079312c7, 0x863b0380, 0x852240c7, 0x00025597, 0x19858593, 0xea5ff0ef, 0x8522002c, 0xf0ef4621, 0x4783e9bf, 0x802300b4, 0x578300f4, 0x80a300a4, 0x441c00f4, 0x0087d79b, 0x00f48123, 0x81a3441c, 0x478300f4, 0x822300f4, 0x578300f4, 0x82a300e4, 0x445c00f4, 0x0087d79b, 0x00f48323, 0x83a3445c, 0x478300f4, 0x84230134, 0x578300f4, 0x84a30124, 0x481c00f4, 0x0087d79b, 0x00f48523, 0x85a3481c, 0x478300f4, 0xb303679c, 0x04e30407, 0x8522fe03, 0x60a26402, 0x83020141, 0xe0221141, 0x7d1ce406, 0xef89842a, 0x4501643c, 0xb303679c, 0x0d630287, 0x85220003, 0x60a26402, 0x83020141, 0x679c67bc, 0xd3ed67bc, 0xdd799782, 0x640260a2, 0x80820141, 0x679c653c, 0x0307b303, 0x00030363, 0x45018302, 0x711d8082, 0x102cf42e, 0xf832ec06, 0xe0bafc36, 0xe8c2e4be, 0xe42eecc6, 0x261240ef, 0x612560e2, 0x11418082, 0xe406e022, 0x842a611c, 0xc7914fbc, 0x70ef6128, 0x30239d6f, 0x643c0404, 0x53fc679c, 0x6828c791, 0x9c4f70ef, 0x04043823, 0xcf897c1c, 0x53386398, 0x67bce709, 0x57fc679c, 0x6c28c791, 0x9a8f70ef, 0x04043c23, 0x09042783, 0x177d777d, 0x60a28ff9, 0x08f42823, 0x01416402, 0x71798082, 0xf406f022, 0xe84aec26, 0xe052e44e, 0xc9795429, 0x09052783, 0x440184aa, 0xc7e98b85, 0x00053983, 0xf0ef892e, 0x842af4ff, 0x864aed55, 0x85264581, 0x0c6000ef, 0xed0d842a, 0x0289b703, 0x00197a13, 0xa783cb29, 0x77b30709, 0xf79300f9, 0xe7b36007, 0xc3a10147, 0x97028526, 0x6490cd0d, 0x00029597, 0x43058593, 0x0002c517, 0xb7850513, 0xf17ff0ef, 0xf0ef8526, 0x842aec7f, 0x6490c535, 0x00029597, 0x41058593, 0x0002c517, 0xbc850513, 0xef7ff0ef, 0x7c9ca891, 0x639cc39d, 0xc3856bbc, 0x97828526, 0xcd01842a, 0x95976490, 0x85930002, 0xc5173e65, 0x05130002, 0xf0efb6e5, 0xa583ecdf, 0x79330709, 0x791300b9, 0x69336009, 0x0d630149, 0x85260009, 0xed3ff0ef, 0xac2357fd, 0xa78308f4, 0x9bf90904, 0x08f4a823, 0x852270a2, 0x64e27402, 0x69a26942, 0x61456a02, 0x71798082, 0xe84af022, 0xf406e44e, 0x7938ec26, 0x892e87aa, 0x89b26304, 0xf8070513, 0xf8048493, 0x07078413, 0x08050793, 0x00879463, 0xa8394501, 0x00090a63, 0x8763611c, 0x60dc0127, 0x84938526, 0xb7cdf807, 0xf0ef85ce, 0xd965ec5f, 0x740270a2, 0x694264e2, 0x614569a2, 0x11018082, 0xec06e822, 0x7508842a, 0x860a468d, 0x0002f597, 0x73858593, 0x488000ef, 0x8522e911, 0x800ff0ef, 0xc11c4782, 0xc51c4792, 0xc15c47a2, 0xf0ef8522, 0x60e2eb2f, 0x61056442, 0x715d8082, 0xf84ae0a2, 0xe486f44e, 0xf052fc26, 0xe85aec56, 0x653ce45e, 0x458189ae, 0x842a679c, 0x63848932, 0x867ff0ef, 0x09042783, 0x0693862a, 0x8b850200, 0x0693c399, 0x601c02b0, 0x451785a6, 0x05130003, 0x63980265, 0x4a1784ce, 0x0a130003, 0x40ef05aa, 0x4a977e02, 0x8a930003, 0x4b17046a, 0x0b130003, 0x4b97036b, 0x8b930003, 0xd063026b, 0x640c0404, 0x0002d517, 0xe6850513, 0x0019191b, 0x7b2240ef, 0x29857824, 0x07040413, 0xf8048493, 0x08048793, 0x02f41c63, 0x640660a6, 0x85a64601, 0xb0ef8522, 0x86aa54f1, 0x85d2864e, 0xa0ef855a, 0x8b9b4852, 0x86520019, 0x852285a6, 0xa95ff0ef, 0x85a689de, 0x8522864a, 0x7601b0ef, 0xbb7d84aa, 0x854e75a2, 0x45f2a0ef, 0x85d2bd69, 0xa0ef854e, 0xb5e14552, 0x651785ee, 0x05130003, 0x83635765, 0x855a000a, 0x43f2a0ef, 0x854e85d2, 0x4372a0ef, 0xb7192a85, 0x856685ee, 0x000a8363, 0xa0ef855a, 0x85d24252, 0xa0ef854e, 0x2a8541d2, 0x9863bf25, 0x86560147, 0xe42e8522, 0x99fff0ef, 0x865e65a2, 0xb0ef8522, 0x85aa6f61, 0x4158b799, 0x00ff0637, 0x0187569b, 0x0187179b, 0x169b8fd5, 0x8ef10087, 0x66c18fd5, 0xf0068693, 0x0087571b, 0x8fd98f75, 0x93811782, 0x8082953e, 0xec4e7139, 0x89aae852, 0x85328a2e, 0x00034597, 0xac058593, 0xf04af426, 0xfc06e456, 0x8ab2f822, 0x84ba8936, 0x00f290ef, 0x66c1e539, 0x85ce8652, 0x80ef842a, 0x571b0132, 0x179b0185, 0x8fd90185, 0x00ff06b7, 0x0085171b, 0x8fd98f75, 0x551b6741, 0x07130085, 0x8d79f007, 0x20238d5d, 0x479100a9, 0x70e2c09c, 0x74428522, 0x790274a2, 0x6a4269e2, 0x61216aa2, 0xe5978082, 0x85930003, 0x855657e5, 0x7b2290ef, 0xe909842a, 0x864a66c1, 0x854e85d2, 0x37d200ef, 0xb7e947d1, 0x0003e597, 0x56458593, 0x90ef8556, 0x842a7902, 0x66c1e911, 0x85d2864a, 0x40ef854e, 0x07936302, 0xb75d0200, 0x00030597, 0x5b058593, 0x90ef8556, 0x842a76c2, 0x66c1e909, 0x85d2864a, 0xf0ef854e, 0x47c112c1, 0x547db751, 0x7131b749, 0xf526f922, 0xed4ef14a, 0xe556e952, 0xfcdee15a, 0xf4e6f8e2, 0xeceef0ea, 0xfd068936, 0x89ae84aa, 0xb0ef8a32, 0x842a64e1, 0x00036b17, 0x168b0b13, 0x02010b93, 0x00033c17, 0xb64c0c13, 0x03010a93, 0x01c10c93, 0x02810d13, 0x01810d93, 0x5e632901, 0x57e10004, 0x00f40663, 0x450557d5, 0x0ef41563, 0x00036917, 0x1b090913, 0x4601a855, 0x852685a2, 0x3351b0ef, 0x855ae42a, 0x740290ef, 0x862a67a2, 0x853e85da, 0x6ea290ef, 0x865ee921, 0x852685a2, 0xe5aff0ef, 0x0e051763, 0x85627582, 0x24b2a0ef, 0x661786d6, 0x06130003, 0x85a22166, 0xb0ef8526, 0xc90d75b1, 0x47915742, 0x02f71663, 0xc39d411c, 0x00036517, 0x20850513, 0x21f2a0ef, 0x00036517, 0x20c50513, 0xdf3fc0ef, 0x852685a2, 0x5b41b0ef, 0xb7b5842a, 0x866a86e6, 0x852685a2, 0xe26ff0ef, 0x7602e541, 0x86d6876e, 0x855285ca, 0xe21ff0ef, 0x47e2e53d, 0x1f634672, 0x75a204f6, 0x90ef8556, 0xdd4d0172, 0x00036917, 0x15c90913, 0x460185a2, 0xb0ef8526, 0x842a2831, 0x85ce4601, 0xb0ef8526, 0x86aa2771, 0x85ca8622, 0x00036517, 0x1a850513, 0x1a72a0ef, 0x70ea4501, 0x74aa744a, 0x69ea790a, 0x6aaa6a4a, 0x7be66b0a, 0x7ca67c46, 0x6de67d06, 0x80826129, 0x00036917, 0x11c90913, 0x6917bf45, 0x09130003, 0xb75d12a9, 0x00036917, 0x0d890913, 0x6917bf71, 0x09130003, 0xbf490ae9, 0x00347179, 0xf022860a, 0xf406ec26, 0x842ae84a, 0xf0ef84ae, 0xcd1dcbef, 0x45814601, 0xb0ef8522, 0x892a1fb1, 0x85a64601, 0xb0ef8522, 0x86aa1ef1, 0x6597864a, 0x85930003, 0x6517ffa5, 0x05130003, 0xa0ef0125, 0x45011192, 0x740270a2, 0x694264e2, 0x80826145, 0x660266a2, 0x852285a6, 0xe17ff0ef, 0x715db7e5, 0x00037597, 0xe5858593, 0xe486fc26, 0xf84ae0a2, 0xf052f44e, 0xe85aec56, 0xc0ef84aa, 0x5a6301c1, 0xc0ef0205, 0x862a3421, 0x00037597, 0xe3058593, 0x00036517, 0x11050513, 0x0bf2a0ef, 0x60a64501, 0x74e26406, 0x79a27942, 0x6ae27a02, 0x61616b42, 0x842a8082, 0x651785a6, 0x05130003, 0xa0efa325 }; mss_io.c000066400000000000000000000514631432224323300363110ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_io.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MSS IO related code * */ #include #include #include "mpfs_hal/mss_hal.h" #ifdef LIBERO_SETTING_ALT_IOMUX1_CR #if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) == (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) static uint8_t io_mux_and_bank_config_alt(void); #endif #endif /******************************************************************************* * external functions */ /* * IOMUX values from Libero */ IOMUX_CONFIG iomux_config_values = { LIBERO_SETTING_IOMUX0_CR, /* Selects whether the peripheral is connected to the Fabric or IOMUX structure. */ LIBERO_SETTING_IOMUX1_CR, /* BNK4 SDV PAD 0 to 7, each IO has 4 bits */ LIBERO_SETTING_IOMUX2_CR, /* BNK4 SDV PAD 8 to 13 */ LIBERO_SETTING_IOMUX3_CR, /* BNK2 SDV PAD 14 to 21 */ LIBERO_SETTING_IOMUX4_CR, /* BNK2 SDV PAD 22 to 29 */ LIBERO_SETTING_IOMUX5_CR, /* BNK2 PAD 30 to 37 */ LIBERO_SETTING_IOMUX6_CR /* Sets whether the MMC/SD Voltage select lines are inverted on entry to the IOMUX structure */ }; #ifdef LIBERO_SETTING_ALT_IOMUX1_CR IOMUX_CONFIG iomux_alt_config_values = { LIBERO_SETTING_ALT_IOMUX0_CR, /* Selects whether the peripheral is connected to the Fabric or IOMUX structure. */ LIBERO_SETTING_ALT_IOMUX1_CR, /* BNK4 SDV PAD 0 to 7, each IO has 4 bits */ LIBERO_SETTING_ALT_IOMUX2_CR, /* BNK4 SDV PAD 8 to 13 */ LIBERO_SETTING_ALT_IOMUX3_CR, /* BNK2 SDV PAD 14 to 21 */ LIBERO_SETTING_ALT_IOMUX4_CR, /* BNK2 SDV PAD 22 to 29 */ LIBERO_SETTING_ALT_IOMUX5_CR, /* BNK2 PAD 30 to 37 */ LIBERO_SETTING_ALT_IOMUX6_CR /* Sets whether the MMC/SD Voltage select lines are inverted on entry to the IOMUX structure */ }; #endif /* * Bank 4 and 2 settings, the 38 MSSIO. */ MSSIO_BANK4_CONFIG mssio_bank4_io_config = { /* LIBERO_SETTING_mssio_bank4_io_cfg_0_cr x_vddi Ratio Rx<0-2> == 001 drv<3-6> == 1111 7:clamp == 0 enhyst == 0 lockdn_en == 1 10:wpd == 0 atp_en`== 0 lpmd_ibuf == 0 lpmd_obuf == 0 persist == 0 */ LIBERO_SETTING_MSSIO_BANK4_IO_CFG_0_1_CR, LIBERO_SETTING_MSSIO_BANK4_IO_CFG_2_3_CR, LIBERO_SETTING_MSSIO_BANK4_IO_CFG_4_5_CR, LIBERO_SETTING_MSSIO_BANK4_IO_CFG_6_7_CR, LIBERO_SETTING_MSSIO_BANK4_IO_CFG_8_9_CR, LIBERO_SETTING_MSSIO_BANK4_IO_CFG_10_11_CR, LIBERO_SETTING_MSSIO_BANK4_IO_CFG_12_13_CR, }; /* * Bank 4 and 2 settings, the 38 MSSIO. */ #ifdef LIBERO_SETTING_ALT_IOMUX1_CR MSSIO_BANK4_CONFIG mssio_alt_bank4_io_config = { /* LIBERO_SETTING_mssio_bank4_io_cfg_0_cr x_vddi Ratio Rx<0-2> == 001 drv<3-6> == 1111 7:clamp == 0 enhyst == 0 lockdn_en == 1 10:wpd == 0 atp_en`== 0 lpmd_ibuf == 0 lpmd_obuf == 0 persist == 0 */ LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_0_1_CR, LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_2_3_CR, LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_4_5_CR, LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_6_7_CR, LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_8_9_CR, LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_10_11_CR, LIBERO_SETTING_ALT_MSSIO_BANK4_IO_CFG_12_13_CR, }; #endif /* * Bank 4 and 2 settings, the 38 MSSIO. */ MSSIO_BANK2_CONFIG mssio_bank2_io_config = { /* LIBERO_SETTING_mssio_bank4_io_cfg_0_cr x_vddi Ratio Rx<0-2> == 001 drv<3-6> == 1111 7:clamp == 0 enhyst == 0 lockdn_en == 1 10:wpd == 0 atp_en`== 0 lpmd_ibuf == 0 lpmd_obuf == 0 persist == 0 */ LIBERO_SETTING_MSSIO_BANK2_IO_CFG_0_1_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_2_3_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_4_5_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_6_7_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_8_9_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_10_11_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_12_13_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_14_15_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_16_17_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_18_19_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_20_21_CR, LIBERO_SETTING_MSSIO_BANK2_IO_CFG_22_23_CR }; #ifdef LIBERO_SETTING_ALT_IOMUX1_CR MSSIO_BANK2_CONFIG mssio_alt_bank2_io_config = { /* LIBERO_SETTING_mssio_bank4_io_cfg_0_cr x_vddi Ratio Rx<0-2> == 001 drv<3-6> == 1111 7:clamp == 0 enhyst == 0 lockdn_en == 1 10:wpd == 0 atp_en`== 0 lpmd_ibuf == 0 lpmd_obuf == 0 persist == 0 */ LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_0_1_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_2_3_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_4_5_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_6_7_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_8_9_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_10_11_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_12_13_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_14_15_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_16_17_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_18_19_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_20_21_CR, LIBERO_SETTING_ALT_MSSIO_BANK2_IO_CFG_22_23_CR }; #endif /******************************************************************************* * Local functions */ static uint8_t io_mux_and_bank_config(void); /***************************************************************************//** * MSSIO OFF Mode * * The following settings are applied if MMSIO unused/off * * The IO Buffers are disabled. * Output drivers are disabled (set the drv<3:0> bits to 0000, output * enable "mss_oe" bit to 0) * Disable the WPU bit set to 0 and enable the WPD bit set to 1. * Receivers are disabled. (Ibufmd<2:0> set to 7) * * MSS can enable OFF mode through configurator bit for selective MSSIO * from Bank2/Bank4 by making drv<3:0>/mss_oe bit to "0" for that * particular MSSIO making Output driver disabled and ibufmd <2:0> bit to * "7" for that particular MSSIO making input receiver disabled. * */ /***************************************************************************//** * mssio_setup() * * Setup the IOMUX and IO bank 2 and 4. * * To setup bank 2 and 4, ncode and pcode scb registers in system * register block are set as per Libero supplied values. * These need to be transferred to I/0 * * @return 0 => pass */ uint8_t mssio_setup(void) { uint8_t ret_status = 0U; ret_status = io_mux_and_bank_config(); set_bank2_and_bank4_volts(DEFAULT_MSSIO_CONFIGURATION); return (ret_status); } /***************************************************************************//** * io_mux_and_bank_config(void) * sets up the IOMUX and bank 2 and 4 pcodes and n codes * @return 0 => OK */ static uint8_t io_mux_and_bank_config(void) { /* Configure IO mux's * * IOMUX1_CR - IOMUX5_CR, five 32-bit registers, with four bits four bits * for each I/O determine what is connected to each pad * * All internal peripherals are also connected to the fabric (apart from * MMC/SDIO/GPIO/USB). The IOMUX0 register configures whether the IO * function is connected to the fabric or the IOMUX. * * IOMUX6_CR Sets whether the MMC/SD Voltage select lines are inverted on * entry to the IOMUX structure * * */ config_32_copy((void *)(&(SYSREG->IOMUX0_CR)), &(iomux_config_values), sizeof(IOMUX_CONFIG)); /* * Configure MSS IO banks * sets pcode and ncode using (mssio_bank2_cfg_cr/mssio_bank4_cfg_cr) * * The MSS IO pad configuration is provided by nineteen system registers * each configuring two IO's using 15-bits per IO * - (mssio_bank*_io_cfg_*_*_cr). | mssio_bank*_io_cfg_*_*_cr | offset | info | | field | offset | info | |:-------------------------:|:-------------:|:-----| | io_cfg_ibufmd_0 |0 | | | io_cfg_ibufmd_1 |1 | | | io_cfg_ibufmd_2 |2 | | | io_cfg_drv_0 |3 | | | Io_cfg_drv_1 |4 | | | Io_cfg_drv_2 |5 | | | io_cfg_drv_3 |6 | | | io_cfg_clamp |7 | | | io_cfg_enhyst |8 | | | io_cfg_lockdn_en |9 | | | io_cfg_wpd |10 | | | io_cfg_wpu |11 | | | io_cfg_atp_en |12 | | | io_cfg_lp_persist_en |13 | | | io_cfg_lp_bypass_en |14 | | * */ config_32_copy((void *)(&(SYSREG->MSSIO_BANK4_IO_CFG_0_1_CR)), &(mssio_bank4_io_config), sizeof(MSSIO_BANK4_CONFIG)); config_32_copy((void *)(&(SYSREG->MSSIO_BANK2_IO_CFG_0_1_CR)), &(mssio_bank2_io_config), sizeof(MSSIO_BANK2_CONFIG)); set_bank2_and_bank4_volts(DEFAULT_MSSIO_CONFIGURATION); return(0L); } /***************************************************************************//** * io_mux_and_bank_config_alt(void) * Configures alt setting * @return */ #ifdef LIBERO_SETTING_ALT_IOMUX1_CR #if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) == (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) static uint8_t io_mux_and_bank_config_alt(void) { /* Configure IO mux's * * IOMUX1_CR - IOMUX5_CR, five 32-bit registers, with four bits four bits * for each I/O determine what is connected to each pad * * All internal peripherals are also connected to the fabric (apart from * MMC/SDIO/GPIO/USB). The IOMUX0 register configures whether the IO * function is connected to the fabric or the IOMUX. * * IOMUX6_CR Sets whether the MMC/SD Voltage select lines are inverted on * entry to the IOMUX structure * * */ config_32_copy((void *)(&(SYSREG->IOMUX0_CR)), &(iomux_alt_config_values), sizeof(IOMUX_CONFIG)); /* * Configure MSS IO banks * sets pcode and ncode using (mssio_bank2_cfg_cr/mssio_bank4_cfg_cr) * * The MSS IO pad configuration is provided by nineteen system registers * each configuring two IO's using 15-bits per IO * - (mssio_bank*_io_cfg_*_*_cr). | mssio_bank*_io_cfg_*_*_cr | offset | info | | field | offset | info | |:-------------------------:|:-------------:|:-----| | io_cfg_ibufmd_0 |0 | | | io_cfg_ibufmd_1 |1 | | | io_cfg_ibufmd_2 |2 | | | io_cfg_drv_0 |3 | | | Io_cfg_drv_1 |4 | | | Io_cfg_drv_2 |5 | | | io_cfg_drv_3 |6 | | | io_cfg_clamp |7 | | | io_cfg_enhyst |8 | | | io_cfg_lockdn_en |9 | | | io_cfg_wpd |10 | | | io_cfg_wpu |11 | | | io_cfg_atp_en |12 | | | io_cfg_lp_persist_en |13 | | | io_cfg_lp_bypass_en |14 | | * */ config_32_copy((void *)(&(SYSREG->MSSIO_BANK4_IO_CFG_0_1_CR)), &(mssio_alt_bank4_io_config), sizeof(MSSIO_BANK4_CONFIG)); config_32_copy((void *)(&(SYSREG->MSSIO_BANK2_IO_CFG_0_1_CR)), &(mssio_alt_bank2_io_config), sizeof(MSSIO_BANK2_CONFIG)); set_bank2_and_bank4_volts(DEFAULT_MSSIO_CONFIGURATION); return(0L); } #endif #endif /** * set_bank2_and_bank4_volts(void) * sets bank voltage parameters * bank_pcode * bank_ncode * vs * @return */ void set_bank2_and_bank4_volts(MSSIO_CONFIG_OPTION config) { switch(config) { default: SCB_REGS->MSSIO_BANK2_CFG_CR.MSSIO_BANK2_CFG_CR =\ (uint32_t)LIBERO_SETTING_MSSIO_BANK2_CFG_CR; SCB_REGS->MSSIO_BANK4_CFG_CR.MSSIO_BANK4_CFG_CR =\ (uint32_t)LIBERO_SETTING_MSSIO_BANK4_CFG_CR; break; #ifdef LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS case ALT_MSSIO_CONFIGURATION: break; #endif } return; } /***************************************************************************//** * alternate_io_configured() * Answers question is alternate I/O configuration present * @return true/false */ uint8_t mss_is_alternate_io_configured(void) { uint8_t result = false; #ifdef LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) == (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) { result = true; } #endif return result; } /***************************************************************************//** * alternate_io_setting_sd() * Answers question is alternate setting SD? * @return returns true if sd is alternate setting */ uint8_t mss_is_alternate_io_setting_sd(void) { uint8_t result = false; #ifdef LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) == (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) { if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & DEFAULT_ON_START_MASK)!=DEFAULT_ON_START_MASK) { result = true; } } #endif return result; } /***************************************************************************//** * alternate_io_setting_sd() * Answers question is alternate setting emmc? * @return returns true if sd is alternate setting */ uint8_t mss_is_alternate_io_setting_emmc(void) { uint8_t result = false; #ifdef LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) == (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) { if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & DEFAULT_ON_START_MASK)==DEFAULT_ON_START_MASK) { result = true; } } #endif return result; } /** * Determines if MSSIO alt switch support in MSS configurator version * Does not indicate if alternate has been configured. * Indicates you can use the following to determine setup * mss_io_defaut_setting(void) * mss_is_alternate_io_configured(void) * mss_is_alternate_io_setting_emmc(void) * mss_is_alternate_io_setting_sd(void) * * @return return true/false */ uint8_t mss_does_xml_ver_support_switch(void) { uint8_t result = false; #ifdef LIBERO_SETTING_HEADER_GENERATOR_VERSION_MAJOR uint32_t header_ver = (LIBERO_SETTING_HEADER_GENERATOR_VERSION_MAJOR*100) + (LIBERO_SETTING_HEADER_GENERATOR_VERSION_MINOR*10) + LIBERO_SETTING_HEADER_GENERATOR_VERSION_PATCH; uint32_t xml_ver = (LIBERO_SETTING_XML_VERSION_MAJOR*100) + (LIBERO_SETTING_XML_VERSION_MINOR*10) + LIBERO_SETTING_XML_VERSION_PATCH; if ((header_ver >= 64U) && (xml_ver >= 56U)) { result = true; } #else (void)result; #endif return result; } /** * mss_io_default_setting(void) * @return returns what is configured on default if mss configurator version supports this. */ #ifdef LIBERO_SETTING_ALT_IOMUX1_CR uint8_t mss_io_default_setting(void) { uint8_t result; if ( mss_does_xml_ver_support_switch() == false ) { result = NO_SUPPORT_MSSIO_CONFIGURATION; } else { #ifdef LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS #if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (SD_CONFIGURED_MASK | DEFAULT_ON_START_MASK)) == (SD_CONFIGURED_MASK | DEFAULT_ON_START_MASK)) result = SD_MSSIO_CONFIGURATION; #elif ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | DEFAULT_ON_START_MASK)) == (EMMC_CONFIGURED_MASK)) result = SD_MSSIO_CONFIGURATION; #else result = NOT_SETUP_MSSIO_CONFIGURATION; #endif #endif } return(result); } #endif /** * Set the MSSIO to a desired config * @param option SD or eMMC * @return */ uint8_t switch_mssio_config(MSS_IO_OPTIONS option) { uint8_t result = false; #ifdef LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS #if ((LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS & (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) == (EMMC_CONFIGURED_MASK | SD_CONFIGURED_MASK)) switch(option) { case SD_MSSIO_CONFIGURATION: if (mss_is_alternate_io_setting_sd() == true) { io_mux_and_bank_config_alt(); } else { io_mux_and_bank_config(); } break; case EMMC_MSSIO_CONFIGURATION: if (mss_is_alternate_io_setting_emmc() == true) { io_mux_and_bank_config_alt(); } else { io_mux_and_bank_config(); } break; case NO_SUPPORT_MSSIO_CONFIGURATION: break; case NOT_SETUP_MSSIO_CONFIGURATION: break; } result = true; #else (void)option; result = false; #endif #endif return result; } /** * switch_external_mux() * Requires fpga switch hdl. This comes with reference icicle kit design. * You will need to create your own or copy when creating your own fpga design * along with an external mux in your board design if you wish to use SD/eMMC * muxing in your hardware design. * Please note this function will cause a hang if you do not have support * for switching in your fpga design, nlu use if you have this support if your * fabric design. * @param option SD_MSSIO_CONFIGURATION/EMMC_MSSIO_CONFIGURATION * @return */ __attribute__((weak)) uint8_t switch_external_mux(MSS_IO_OPTIONS option) { uint8_t result = false; #ifdef LIBERO_SETTING_FPGA_SWITCH_ADDRESS volatile uint32_t *reg_pt = (uint32_t *)LIBERO_SETTING_FPGA_SWITCH_ADDRESS; switch(option) { case SD_MSSIO_CONFIGURATION: *reg_pt = 1UL; break; case EMMC_MSSIO_CONFIGURATION: *reg_pt = 0UL; break; case NO_SUPPORT_MSSIO_CONFIGURATION: break; case NOT_SETUP_MSSIO_CONFIGURATION: break; } #endif result = true; return result; } /***************************************************************************//** * See mss_io_config.h for details of how to use this function. */ __attribute__((weak)) void mss_set_gpio_interrupt_fab_cr(uint32_t reg_value) { SYSREG->GPIO_INTERRUPT_FAB_CR = reg_value; } /***************************************************************************//** * See mss_peripherals.h for details of how to use this function. */ __attribute__((weak)) uint32_t mss_get_gpio_interrupt_fab_cr(void) { return (SYSREG->GPIO_INTERRUPT_FAB_CR); } #ifdef EXAMPLE_MSSIO_APP_CODE #include "drivers/mss_gpio/mss_gpio.h" /** * * @return 0 => OK */ int32_t gpio_toggle_test(void) { SYSREG->TEMP0 = 0x11111111; for (int l = 0 ; l < 14 ; l++) { for (int i = 0 ; i < 14 ; i++) { SYSREG->TEMP0 = 0x12345678; MSS_GPIO_set_output(GPIO0_LO, i, 0x0); } for (int i = 0 ; i < 24 ; i++) { SYSREG->TEMP0 = 0x12345678; MSS_GPIO_set_output(GPIO1_LO, i, 0x0); } SYSREG->TEMP0 = 0xFFFFFFFFUL; for (int i = 0 ; i < 14 ; i++) { SYSREG->TEMP0 = 0x12345678; MSS_GPIO_set_output(GPIO0_LO, i, 0x1); } for (int i = 0 ; i < 24 ; i++) { SYSREG->TEMP0 = 0x12345678; MSS_GPIO_set_output(GPIO1_LO, i, 0x1); } } return(0UL); } /** * * @return 0 => OK */ int32_t gpio_set_config(void) { SYSREG->SOFT_RESET_CR &= ~((1U<<20U)|(1U<<21U)|(1U<<22U)); SYSREG->SUBBLK_CLOCK_CR |= ((1U<<20U)|(1U<<21U)|(1U<<22U)); MSS_GPIO_init(GPIO0_LO); MSS_GPIO_init(GPIO1_LO); for (int i = 0 ; i < 14 ; i++) { MSS_GPIO_config(GPIO0_LO, i, MSS_GPIO_OUTPUT_MODE); } for (int i = 0 ; i < 24 ; i++) { MSS_GPIO_config(GPIO1_LO, i, MSS_GPIO_OUTPUT_MODE); } return(0UL); } #endif mss_io_config.h000066400000000000000000000433131432224323300376360ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_io_config.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MSS IO related code * */ #ifndef xUSER_CONFIG_MSS_DDRC_MSS_IO_CONFIG_H_ #define xUSER_CONFIG_MSS_DDRC_MSS_IO_CONFIG_H_ #ifdef __cplusplus extern "C" { #endif /* * fields of LIBERO_SETTING_MSSIO_CONFIGURATION_OPTIONS * */ #define EMMC_CONFIGURED_MASK (0x01U<<0U) /*!< set => eMMC is configured */ #define SD_CONFIGURED_MASK (0x01U<<1U) /*!< set => SD is configured */ #define DEFAULT_ON_START_MASK (0x01U<<2U) /*!< set => default is SD config, not set default is eMMC config */ #if !defined (LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR) /*To limit the number of interrupts fed to the PLINT, the seventy GPIO interrupts (GPIO0=14, GPIO1=24, GPIO2=32) are reduced down to 41 interrupts by OR'ing some together. There is some flexibility regarding which interrupts are OR'd or are direct. This selection is controlled by a 32-bit system register(GPIO_INTERRUPT_FAB_CR). For example, if bit 0 of the register is set to 1, gpio2_0 is chosen as a direct interrupt on the PLIC and gpio0_0 will be OR'd with any other non-direct gpio0 interrupts. Please see the GPIO driver for more details on using GPIO interrupts. */ #define LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR 0x00000000UL /* GPIO0_0_OR_GPIO2_0 [0:1] RW value= 0x0 */ /* GPIO0_1_OR_GPIO2_1 [1:1] RW value= 0x0 */ /* GPIO0_2_OR_GPIO2_2 [2:1] RW value= 0x0 */ /* GPIO0_3_OR_GPIO2_3 [3:1] RW value= 0x0 */ /* GPIO0_4_OR_GPIO2_4 [4:1] RW value= 0x0 */ /* GPIO0_5_OR_GPIO2_5 [5:1] RW value= 0x0 */ /* GPIO0_6_OR_GPIO2_6 [6:1] RW value= 0x0 */ /* GPIO0_7_OR_GPIO2_7 [7:1] RW value= 0x0 */ /* GPIO0_8_OR_GPIO2_8 [8:1] RW value= 0x0 */ /* GPIO0_9_OR_GPIO2_9 [9:1] RW value= 0x0 */ /* GPIO0_10_OR_GPIO2_10 [10:1] RW value= 0x0 */ /* GPIO0_11_OR_GPIO2_11 [11:1] RW value= 0x0 */ /* GPIO0_12_OR_GPIO2_12 [12:1] RW value= 0x0 */ /* GPIO0_13_OR_GPIO2_13 [13:1] RW value= 0x0 */ /* GPIO1_0_OR_GPIO2_14 [14:1] RW value= 0x0 */ /* GPIO1_1_OR_GPIO2_15 [15:1] RW value= 0x0 */ /* GPIO1_2_OR_GPIO2_16 [16:1] RW value= 0x0 */ /* GPIO1_3_OR_GPIO2_17 [17:1] RW value= 0x0 */ /* GPIO1_4_OR_GPIO2_18 [18:1] RW value= 0x0 */ /* GPIO1_5_OR_GPIO2_19 [19:1] RW value= 0x0 */ /* GPIO1_6_OR_GPIO2_20 [20:1] RW value= 0x0 */ /* GPIO1_7_OR_GPIO2_21 [21:1] RW value= 0x0 */ /* GPIO1_8_OR_GPIO2_22 [22:1] RW value= 0x0 */ /* GPIO1_9_OR_GPIO2_23 [23:1] RW value= 0x0 */ /* GPIO1_10_OR_GPIO2_24 [24:1] RW value= 0x0 */ /* GPIO1_11_OR_GPIO2_25 [25:1] RW value= 0x0 */ /* GPIO1_12_OR_GPIO2_26 [26:1] RW value= 0x0 */ /* GPIO1_13_OR_GPIO2_27 [27:1] RW value= 0x0 */ /* GPIO1_14_OR_GPIO2_28 [28:1] RW value= 0x0 */ /* GPIO1_15_OR_GPIO2_29 [29:1] RW value= 0x0 */ /* GPIO1_16_OR_GPIO2_30 [30:1] RW value= 0x0 */ /* GPIO1_17_OR_GPIO2_31 [31:1] RW value= 0x0 */ #endif #if !defined (LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR) /*To limit the number of interrupts fed to the PLINT, the seventy GPIO interrupts (GPIO0=14, GPIO1=24, GPIO2=32) are reduced down to 41 interrupts by OR'ing some together. There is some flexibility regarding which interrupts are OR'd or are direct. This selection is controlled by a 32-bit system register(GPIO_INTERRUPT_FAB_CR). For example, if bit 0 of the register is set to 1, gpio2_0 is chosen as a direct interrupt on the PLIC and gpio0_0 will be OR'd with any other non-direct gpio0 interrupts. Please see the GPIO driver for more details on using GPIO interrupts. */ #define LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR 0x00000000UL /* GPIO0_0_OR_GPIO2_0 [0:1] RW value= 0x0 */ /* GPIO0_1_OR_GPIO2_1 [1:1] RW value= 0x0 */ /* GPIO0_2_OR_GPIO2_2 [2:1] RW value= 0x0 */ /* GPIO0_3_OR_GPIO2_3 [3:1] RW value= 0x0 */ /* GPIO0_4_OR_GPIO2_4 [4:1] RW value= 0x0 */ /* GPIO0_5_OR_GPIO2_5 [5:1] RW value= 0x0 */ /* GPIO0_6_OR_GPIO2_6 [6:1] RW value= 0x0 */ /* GPIO0_7_OR_GPIO2_7 [7:1] RW value= 0x0 */ /* GPIO0_8_OR_GPIO2_8 [8:1] RW value= 0x0 */ /* GPIO0_9_OR_GPIO2_9 [9:1] RW value= 0x0 */ /* GPIO0_10_OR_GPIO2_10 [10:1] RW value= 0x0 */ /* GPIO0_11_OR_GPIO2_11 [11:1] RW value= 0x0 */ /* GPIO0_12_OR_GPIO2_12 [12:1] RW value= 0x0 */ /* GPIO0_13_OR_GPIO2_13 [13:1] RW value= 0x0 */ /* GPIO1_0_OR_GPIO2_14 [14:1] RW value= 0x0 */ /* GPIO1_1_OR_GPIO2_15 [15:1] RW value= 0x0 */ /* GPIO1_2_OR_GPIO2_16 [16:1] RW value= 0x0 */ /* GPIO1_3_OR_GPIO2_17 [17:1] RW value= 0x0 */ /* GPIO1_4_OR_GPIO2_18 [18:1] RW value= 0x0 */ /* GPIO1_5_OR_GPIO2_19 [19:1] RW value= 0x0 */ /* GPIO1_6_OR_GPIO2_20 [20:1] RW value= 0x0 */ /* GPIO1_7_OR_GPIO2_21 [21:1] RW value= 0x0 */ /* GPIO1_8_OR_GPIO2_22 [22:1] RW value= 0x0 */ /* GPIO1_9_OR_GPIO2_23 [23:1] RW value= 0x0 */ /* GPIO1_10_OR_GPIO2_24 [24:1] RW value= 0x0 */ /* GPIO1_11_OR_GPIO2_25 [25:1] RW value= 0x0 */ /* GPIO1_12_OR_GPIO2_26 [26:1] RW value= 0x0 */ /* GPIO1_13_OR_GPIO2_27 [27:1] RW value= 0x0 */ /* GPIO1_14_OR_GPIO2_28 [28:1] RW value= 0x0 */ /* GPIO1_15_OR_GPIO2_29 [29:1] RW value= 0x0 */ /* GPIO1_16_OR_GPIO2_30 [30:1] RW value= 0x0 */ /* GPIO1_17_OR_GPIO2_31 [31:1] RW value= 0x0 */ #endif typedef enum MSSIO_CONFIG_OPTION_ { DEFAULT_MSSIO_CONFIGURATION = 0x00, /*!< 0 default behavior */ ALT_MSSIO_CONFIGURATION = 0x01, /*!< 1 alternate config */ } MSSIO_CONFIG_OPTION; typedef enum MSS_IO_OPTIONS_ { NO_SUPPORT_MSSIO_CONFIGURATION = 0x00, /*!< 0 MSS Configurator version too early */ NOT_SETUP_MSSIO_CONFIGURATION = 0x01, /*!< 0 none configured */ SD_MSSIO_CONFIGURATION = 0x02, /*!< 0 SD config */ EMMC_MSSIO_CONFIGURATION = 0x03, /*!< 1 eMMC config */ } MSS_IO_OPTIONS; /* * There are 38 general purpose IO pads, referred to as MSSIO, to support * peripheral devices. System registers will select which signals are connected * to the IO pads. These are in addition to the SGMII IO for the Ethernet MACs, * DDR I/O and two IOs to allow interfacing to an external 32kHz crystal. All * of these MSSIOs are bonded out to pins in all packages. The MSSIOs may be * configured as the IOs of any of the MSS peripherals listed in the table * below. */ /* - MUX -> PAD options set by Libero, register iomux1_cr to iomux5_cr | option | value | Info | |:-------------:|:-------------:|:-----:| | SD_SDIO | 0x0 | | | EMMC | 0x1 | | | QSPI | 0x2 | | | SPI | 0x3 | | | USB | 0x4 | | | MMUART | 0x5 | | | I2C | 0x6 | | | CAN | 0x7 | | | MDIO | 0x8 | | | Miscellaneous | 0x9 | | | Reservedx | 0xA | | | GPIO_PAD | 0xB | | | Fabric_test | 0xC | | | Logic_0 | 0xD | | | Logic_1 | 0xE | | | Tristate | 0xF |Default| */ /** * \brief IOMUX configuration */ typedef struct IOMUX_CONFIG_ { __IO uint32_t iomux0_cr; /* peripheral is connected to the Fabric or IOMUX structure */ __IO uint32_t iomux1_cr; /* BNK4 SDV PAD 0 to 7 */ __IO uint32_t iomux2_cr; /* BNK4 SDV PAD 8 to 13 */ __IO uint32_t iomux3_cr; /* BNK2 SDV PAD 14 to 21 */ __IO uint32_t iomux4_cr; /* BNK2 SDV PAD 22 to 29 */ __IO uint32_t iomux5_cr; /* BNK2 PAD 30 to 37 */ __IO uint32_t iomux6_cr; /* MMC/SD Voltage select lines are inverted on entry to the IOMUX structure */ } IOMUX_CONFIG; /* pcode, ncode and drive strength for each bank is set using direct writes to the SCB registers The MSS IO pad configuration is provided by nineteen system registers each configuring two IO's using 15-bits per IO Theses registers are located in the MSS sysreg. - (mssio_bank*_io_cfg_*_*_cr). | mssio_bank*_io_cfg_*_*_cr | offset | info | | field | | info | |:-------------------------:|:-------------:|:-----| | io_cfg_ibufmd_0 |0 | | | io_cfg_ibufmd_1 |1 | | | io_cfg_ibufmd_2 |2 | | | io_cfg_drv_0 |3 | | | Io_cfg_drv_1 |4 | | | Io_cfg_drv_2 |5 | | | io_cfg_drv_3 |6 | | | io_cfg_clamp |7 | | | io_cfg_enhyst |8 | | | io_cfg_lockdn_en |9 | | | io_cfg_wpd |10 | | | io_cfg_wpu |11 | | | io_cfg_atp_en |12 | | | io_cfg_lp_persist_en |13 | | | io_cfg_lp_bypass_en |14 | | */ /** * \brief Bank 2 and 4 voltage settings * */ typedef struct HSS_MSSIO_Bank_Config_ { __IO uint32_t mssio_bank4_pcode_ncode_vs; /* bank 4- set pcode, ncode and drive strength */ __IO uint32_t mssio_bank2_pcode_ncode_vs; /* bank 2- set pcode, ncode and drive strength */ }MSSIO_BANK_CONFIG; /** * \brief MSS IO Bank 4 configuration */ typedef struct MSSIO_Bank4_IO_Config_ { __IO uint32_t mssio_bank4_io_cfg_0_cr; /* x_vddi Ratio Rx<0-2> == 001 drv<3-6> == 1111 7:clamp == 0 enhyst == 0 lockdn_en == 1 10:wpd == 0 atp_en`== 0 lpmd_ibuf == 0 lpmd_obuf == 0 persist == 0 */ __IO uint32_t mssio_bank4_io_cfg_1_cr; __IO uint32_t mssio_bank4_io_cfg_2_cr; __IO uint32_t mssio_bank4_io_cfg_3_cr; __IO uint32_t mssio_bank4_io_cfg_4_cr; __IO uint32_t mssio_bank4_io_cfg_5_cr; __IO uint32_t mssio_bank4_io_cfg_6_cr; }MSSIO_BANK4_CONFIG; /** * \brief MSS IO Bank 2 configuration */ typedef struct MSSIO_Bank2_IO_Config_ { __IO uint32_t mssio_bank2_io_cfg_0_cr; /* x_vddi Ratio Rx<0-2> == 001 drv<3-6> == 1111 7:clamp == 0 enhyst == 0 lockdn_en == 1 10:wpd == 0 atp_en`== 0 lpmd_ibuf == 0 lpmd_obuf == 0 persist == 0 */ __IO uint32_t mssio_bank2_io_cfg_1_cr; __IO uint32_t mssio_bank2_io_cfg_2_cr; __IO uint32_t mssio_bank2_io_cfg_3_cr; __IO uint32_t mssio_bank2_io_cfg_4_cr; __IO uint32_t mssio_bank2_io_cfg_5_cr; __IO uint32_t mssio_bank2_io_cfg_6_cr; __IO uint32_t mssio_bank2_io_cfg_7_cr; __IO uint32_t mssio_bank2_io_cfg_8_cr; __IO uint32_t mssio_bank2_io_cfg_9_cr; __IO uint32_t mssio_bank2_io_cfg_10_cr; __IO uint32_t mssio_bank2_io_cfg_11_cr; }MSSIO_BANK2_CONFIG; /***************************************************************************//** The int32_t mssio_setup(void)() Setup the IOMUX and IO bank 2 and 4. The values used in this function are set by Libero. It configures the I/O mux, which detemines what peripherals are connected to what pins, and the electrical properties of each bank and each I/O. @return This function returns status, 0 => OK Example: @code error |= mssio_setup(); @endcode */ uint8_t mssio_setup ( void ); /***************************************************************************//** The gpio_toggle_test(void)() Toggle a GPIO PIN on start-up @return This function returns status, 0 => OK Example: @code error |= mssio_setup(); @endcode */ int32_t gpio_toggle_test ( void ); /***************************************************************************//** set_bank2_and_bank4_volts() Sets bank 2 and 4 voltages, with Values coming from Libero Example: @code set_bank2_and_bank4_volts(); @endcode * */ void set_bank2_and_bank4_volts ( MSSIO_CONFIG_OPTION config ); /***************************************************************************//** switch_mssio_config() switches as instructed SD/eMMC Example: @code ASSERT(mss_does_xml_ver_support_switch() == true) if ( switch_mssio_config(EMMC_MSSIO_CONFIGURATION) == false ) { while(1u); } switch_external_mux(EMMC_MSSIO_CONFIGURATION); g_mmc.clk_rate = MSS_MMC_CLOCK_200MHZ; g_mmc.card_type = MSS_MMC_CARD_TYPE_MMC; g_mmc.bus_speed_mode = MSS_MMC_MODE_HS200; g_mmc.data_bus_width = MSS_MMC_DATA_WIDTH_4BIT; g_mmc.bus_voltage = MSS_MMC_1_8V_BUS_VOLTAGE; @endcode * */ uint8_t switch_mssio_config ( MSS_IO_OPTIONS option ) ; /***************************************************************************//** mss_does_xml_ver_support_switch() Sets bank 2 and 4 voltages, with Values coming from Libero Example: @code ASSERT(mss_does_xml_ver_support_switch() == true); @endcode * */ uint8_t mss_does_xml_ver_support_switch(void); /***************************************************************************//** mss_is_alternate_io_configured() Example: @code if ( mss_is_alternate_io_configured() == true ) { ... } @endcode * */ uint8_t mss_is_alternate_io_configured(void); /***************************************************************************//** mss_is_alternate_io_setting_emmc() Example: @code if ( mss_is_alternate_io_setting_emmc() == true ) { ... } @endcode * */ uint8_t mss_is_alternate_io_setting_emmc(void); /***************************************************************************//** mss_is_alternate_io_setting_sd() Example: @code if ( mss_is_alternate_io_setting_sd() == true ) { ... } @endcode * */ uint8_t mss_is_alternate_io_setting_sd(void); /***************************************************************************//** switch_external_mux() This is a function used to switch external mux. Requires fpga switch hdl. This comes with reference icicle kit design. Will need to create your own or copy when creating your own fpga design along with an external mux in your board design if you wish to use SD/eMMC muxing in your hardware design. Example: @code switch_external_mux(SD_MSSIO_CONFIGURATION); @endcode */ uint8_t switch_external_mux(MSS_IO_OPTIONS option); /***************************************************************************//** mss_io_default_setting() This helper function may be useful, e.g. print a message on start-up explaining configuration. Example: @code if ( mss_io_default_setting() == SD_MSSIO_CONFIGURATION ) { // ... } @endcode */ uint8_t mss_io_default_setting(void); /***************************************************************************//** This function is used to set the apb_bus_cr register value @param reg_value value of the register you want to set. This value is available from the MSS configurator LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR Example: @code (void)mss_set_gpio_interrupt_fab_cr((uint32_t)LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR); @endcode */ void mss_set_gpio_interrupt_fab_cr(uint32_t reg_value); /***************************************************************************//** This function is used to get the gpio_interrupt_fab_cr register value @return Return the gpio_interrupt_fab_cr reg value Example: @code uint32_t cr_reg; cr_reg = mss_get_gpio_interrupt_fab_cr(); @endcode */ uint32_t mss_get_gpio_interrupt_fab_cr(void); #ifdef __cplusplus } #endif #endif /* USER_CONFIG_MSS_DDRC_MSS_IO_CONFIG_H_ */ mss_nwc_init.c000066400000000000000000000340611432224323300375070ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_nwc_init.c * @author Microchip-FPGA Embedded Systems Solutions * @brief north west corner, calls required startup code * */ #include #include #include "mpfs_hal/mss_hal.h" #include "mss_nwc_init.h" #include "simulation.h" #ifdef DEBUG_DDR_INIT #include "drivers/mss/mss_mmuart/mss_uart.h" extern mss_uart_instance_t *g_debug_uart ; #endif /******************************************************************************* * Local Defines */ CFG_DDR_SGMII_PHY_TypeDef * const CFG_DDR_SGMII_PHY = ((CFG_DDR_SGMII_PHY_TypeDef *) CFG_DDR_SGMII_PHY_BASE); DDR_CSR_APB_TypeDef * const DDRCFG = ((DDR_CSR_APB_TypeDef *) DDRCFG_BASE); IOSCBCFG_TypeDef * const SCBCFG_REGS = (IOSCBCFG_TypeDef *)IOSCBCFG_BASE ; g5_mss_top_scb_regs_TypeDef * const SCB_REGS = (g5_mss_top_scb_regs_TypeDef *) SYSREGSCB_BASE; /******************************************************************************* * Local functions */ static uint64_t report_status_functions(MSS_REPORT_STATUS report_status, uint64_t next_time); /******************************************************************************* * extern defined functions */ /****************************************************************************** * Public Functions - API ******************************************************************************/ /** * mss_nwc_init(void) * Init of MSS called after hard and soft boot * Settings informed by MSS Configurator config. * - some registers set to required values * - PLL * - SGMII * - MSS IO * @return */ uint8_t mss_nwc_init(void) { uint8_t error = 0U; /* * Assumptions: * 1. We enter here shortly after start-up of E51 code by the system * controller. * 2. We are running on the E51 and all other cores are in wfi. * 3. The MSS PLL will be set to use default internal clock of 80MH * 4. MSS peripherals including the I/O are in the default power on state * * * The following implements setting of * external clock reference * MSS PLL, SHMII PLL, SGMII PLL, MSS Mux's * IO settings and IO MUX * HSIO IO calibration options * SGMII configuration * DDR configuration * Including SEG regs * MPU setup * PMP setup * ABP Peripheral address setup (High/Low) * */ /* * Set based on reference clock */ set_RTC_divisor(); /* * SCB access settings */ SCBCFG_REGS->TIMER.TIMER = MSS_SCB_ACCESS_CONFIG; /* * Release APB reset & turn on dfi clock * * reserved bit 31:2 * reset bit 1 Asserts the APB reset to the MSS corner, is asserted at * MSS reset. * clock_on bit 0 Turns on the APB clock to the MSS Corner, is off at * reset. Once corner blocks is configured the firmware * may turn off the clock, but periodically should turn * back on to allow refresh of TMR registers inside * the corner block. * */ SYSREG->DFIAPB_CR = 0x00000001U; /* * Dynamic APB enables for slaves * APB dynamic enables determine if we can write to the associated APB * registers. * ACB dynamic enables determine if we can write to the associated SCB * registers. * * bit 31:22 Reserved * bit 21 DYNEN_APB_DECODER_PRESETS * bit 20 DYNEN_APB_BANKCNTL * bit 19 DYNEN_APB_IO_CALIB * bit 18 DYNEN_APB_CFM * bit 17 DYNEN_APB_PLL1 * bit 16 DYNEN_APB_PLL0 * bit 15:13 Reserved * bit 12 DYNEN_SCB_BANKCNTL * bit 11 DYNEN_SCB_IO_CALIB * bit 10 DYNEN_SCB_CFM * bit 9 DYNEN_SCB_PLL1 * bit 8 DYNEN_SCB_PLL0 * bit 7:5 Reserved * bit 4 Persist_DATA * bit 3 CLKOUT * bit 2 PERSIST_ADD_CMD * bit 1 DATA_Lockdn * bit 0 ADD_CMD_Lockdn */ CFG_DDR_SGMII_PHY->DDRPHY_STARTUP.DDRPHY_STARTUP =\ (0x3FU << 16U) | (0x1FU << 8U); /* Enable all dynamic enables When in dynamic enable more, this allows: 1. writing directly using SCB 2. setting using RPC on a soft reset */ CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (0x01U<< 10U) | (0x7FU<<0U); /* * Configure IOMUX and I/O settings for bank 2 and 4 */ { #ifdef MSSIO_SUPPORT error |= mssio_setup(); #endif } /*************************************************************************/ /* * * In this step we enter Dynamic Enable mode. * This is done by using the following sequence: * * Please note all dynamic enables must be enabled. * If dynamic enables are not enabled, when flash valid is asserted, value * of SCB registers will be immediately written to with default values * rather than the RPC values. * * Dynamic Enable mode: * Step 1: * Make sure SCB dynamic enable bit is high * step 2: Assert MSS core_up * followed by delay * step 3: Change dce[0,1,2] to 0x00 * followed by delay * step 4: Assert flash valid * followed by delay * step 5: make sure all RPC registers are set to desired values * (using mode and direct RPC writes to RPC) * step 6: soft reset IP so SCB registers are written with RPC values. * note: We will carry out step 5/6 later, once we have modified any * RPC registers directly that may need tweaking or are not * included in the mode write state machine, carried out in a * previous step. * * Note 1: The SCB bus can be used to update/write new values to * the SCB registers through the SCB bus interface while in Dynamic * enable mode * Note 2: The MSS top block assertion of core_up and flash_valid * have no effect in themselves if MSS custom SCB register values * if the custom SCB slaves are not being reset at the same time. * If the custom SCB slaves are reset whilst core_up and * flash_valid are high, then the SCB registers get asynchronously * loaded with the values of their corresponding RPC bits. These * values remain even after negation of reset but may be * subsequently overwritten by SCB writes. * * reg MSS_LOW_POWER_CR * * bit 12 flash_valid Sets the value driven out on * mss_flash_valid_out * bit 11 core_up Sets the value driven out on * mss_core_up_out * bit 10:8 dce S Sets the value driven out on mss_dce_out * unless G5C asserts its overrides * bit 7 lp_stop_clocks_in Read back of lp_stop_clocks input * bit 6 lp_stop_clocks_out Direct control of MSS Corner LP state * control * bit 5 p_pll_locked Direct control of MSS Corner * LP state control * bit 4 lp_state_bypass Direct control of MSS Corner LP * state control * bit 3 lp_state_persist * bit 2 lp_state_op * bit 1 lp_state_ip * bit 0 lp_state_mss * * In order to re-flash/update the APB RPC register values into the * registers of a specific SCB slave,the following sequence must be * followed: * 1) Embedded software running on E51 must force the mss_core_up and * mss_flash valid must be high * 2) Then do a soft reset of the specific SCB slave that will be * re-flashed/updated. * * The APB RPC registers are used in the following ways to configure * the MSS periphery * 1) Load values to SCB registers. * core_up" and "flash_valid" determines if the SCB registers get * either: * a. Reset to their hardware default * (when core_up/flash_valis low) * b. Loaded with the APB RPC register. * (when core_up/flash_valid high) * 2) IO configuration settings * These are fed directly to the static configuration of IOA cells * within the IOG lanes of the DDR and SGMII PHYs, as long as * "core_up" and "flash_valid" are high. * a. To avoid unwanted/intermediate states on IOs, the "core_up" * and "flash_valid" should be initially 0 on MSS reset. This will * select the safe hardware defaults. The RPC registers are written * in the background and then simultaneously "flashed" as the new * IO configuration by assertion of "core_up" and "flash_valid" * being asserted. * 3) Training IP settings * These allow the direct control of the training IP via the APB * registers. * * Notes: * 1) When the MSS is reset, the SCB slaves won't take on the RPC * values. They will be reset to their hardware default values. * * 2) Although RPC registers are writable in APB space, * they only take effect on the SCB registers whenever there is a * "virtual re-flash" operation, which involves performing * a soft reset of an SCB slave (i.e. writing to the NV_MAP register * bit in the SOFT_RESET register in the SCB slave). * This mechanism would only be used if a full new configuration is to * be applied to the full SCB slave and wouldn't be used, for example * to change just a clock mux configuration. * * 3) To make configuration changes to individual registers, without * "re-flashing" all registers in an MSS custom SCB slave, it is * necessary to write directly to the SCB registers (via SCB space) in * that slave, rather than writing RPC registers via APB space * */ /* lp_state_mss :1; lp_state_ip_mss :1; lp_state_op_mss :1; lp_state_persist_mss :1; lp_state_bypass_mss :1; lp_pll_locked_mss :1; lp_stop_clocks_out_mss :1; lp_stop_clocks_in_mss :1; mss_dce :3; mss_core_up :1; mss_flash_valid :1; mss_io_en :1; */ /* DCE:111, CORE_UP:1, FLASH_VALID:0, mss_io_en:0 */ SCB_REGS->MSSIO_CONTROL_CR.MSSIO_CONTROL_CR =\ (0x07U<<8U)|(0x01U<<11U)|(0x00U<<12U)|(0x00U<<13U); delay(DELAY_CYCLES_500_NS); /* DCE:000, CORE_UP:1, FLASH_VALID:0, mss_io_en:0 */ SCB_REGS->MSSIO_CONTROL_CR.MSSIO_CONTROL_CR =\ (0x00U<<8U)|(0x01U<<11U)|(0x00U<<12U)|(0x00U<<13U); delay(DELAY_CYCLES_500_NS); /* DCE:000, CORE_UP:1, FLASH_VALID:1, mss_io_en:0 */ SCB_REGS->MSSIO_CONTROL_CR.MSSIO_CONTROL_CR =\ (0x00U<<8U)|(0x01U<<11U)|(0x01U<<12U)|(0x00U<<13U); delay(DELAY_CYCLES_500_NS); /* DCE:000, CORE_UP:1, FLASH_VALID:1, mss_io_en:1 */ SCB_REGS->MSSIO_CONTROL_CR.MSSIO_CONTROL_CR =\ (0x00U<<8U)|(0x01U<<11U)|(0x01U<<12U)|(0x01U<<13U); /* * Setup SGMII * The SGMII set-upset configures the external clock reference so this must * be called before configuring the MSS PLL */ SIM_FEEDBACK0(2); sgmii_setup(); /* * Setup the MSS PLL */ SIM_FEEDBACK0(3); mss_pll_config(); return error; } /** * mss_nwc_init_ddr(void) * Init the DDR * * @return error status, 0U => OK */ uint8_t mss_nwc_init_ddr(void) { uint8_t error = 0U; #ifdef DDR_SUPPORT uint64_t next_time; #ifdef DEBUG_DDR_INIT if (g_debug_uart == NULL) { /* * Defaults to UART0 if none selected by user boot code */ g_debug_uart = &g_mss_uart0_lo; } (void)setup_ddr_debug_port(g_debug_uart); #endif uint32_t ddr_status; ddr_status = ddr_state_machine(DDR_SS__INIT); next_time = rdcycle() + DELAY_CYCLES_100MS; while((ddr_status & DDR_SETUP_DONE) != DDR_SETUP_DONE) { ddr_status = ddr_state_machine(DDR_SS_MONITOR); next_time = report_status_functions(DDR_BOOT_PROGRESS, next_time); } if ((ddr_status & DDR_SETUP_FAIL) == DDR_SETUP_FAIL) { error |= (0x1U << 2U); } #endif return error; } /** * report_status_functions() * Used to call user boot functions for feedback during boot * @param report_status */ static uint64_t report_status_functions(MSS_REPORT_STATUS report_status, uint64_t next_time) { if (next_time <= rdcycle()) { switch(report_status) { case DDR_BOOT_PROGRESS: ddr_report_progress(); break; default: break; } next_time = rdcycle() + DELAY_CYCLES_100MS; } return next_time; } /** * Application can create own function to show progress */ __attribute__((weak)) void ddr_report_progress(void) { return; } /*-------------------------------------------------------------------------*//** * mtime_delay() * waits x microseconds * Assumption 1 is we have ensured clock is 1MHz * Assumption 2 is we have not setup tick timer when using this function. It is * only used by the startup code * @param microseconds microseconds to delay */ void mtime_delay(uint32_t microseconds) { CLINT->MTIME = 0ULL; volatile uint32_t count = 0ULL; while(CLINT->MTIME < microseconds) { count++; } return; } mss_nwc_init.h000066400000000000000000000167451432224323300375250ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_nwc_init.h * @author Microchip-FPGA Embedded Systems Solutions * @brief defines for mss_nwc_init.c * */ /*=========================================================================*//** @page MPFS MSS NWC configuration ============================================================================== @section intro_sec Introduction ============================================================================== The MPFS microcontroller subsystem (MSS) includes a number of hard core components physically located in the north west corner of the MSS on the die. ============================================================================== @section Items located in the north west corner ============================================================================== MSS PLL SGMII DDR phy MSSIO ============================================================================== @section Flow diagram ============================================================================== todo: remove, added line here as test ***** Simplified flow diagram +-----------------+ | start | | NWC setup | +-------+---------+ v +-----------------+ | set SCB access| | Parameters | +-------+---------+ | +-------v---------+ | Release APB NWC | | Turn on APB clk | +-------+---------+ | +-------v---------+ | Set Dynamic | | enable bits | +-------++--------+ | +-------v---------+ | Setup signals | | DCE,CORE_UP, | | Flash_Valid, | | MSS_IO_EN | +-------+---------+ | +-------v---------+ | Setup SGMII | | | +-------+---------+ | +-------v---------+ | Setup DDR | | | +-------+---------+ | +-------v---------+ | Setup MSSIO | | | +-------+---------+ | +-------v---------+ | Finished | +-----------------+ *//*=========================================================================*/ #ifndef __MSS_NWC_INIT_H_ #define __MSS_NWC_INIT_H_ 1 #include #include #include "../encoding.h" #ifdef __cplusplus extern "C" { #endif #define DELAY_CYCLES_500_NS ((uint32_t)(0.0000005 * LIBERO_SETTING_MSS_COREPLEX_CPU_CLK)) #define DELAY_CYCLES_1_MICRO ((uint32_t)(DELAY_CYCLES_500_NS * 2U)) #define DELAY_CYCLES_5_MICRO ((uint32_t)(DELAY_CYCLES_500_NS * 10U)) #define DELAY_CYCLES_50_MICRO ((uint32_t)(DELAY_CYCLES_500_NS * 100U)) #define DELAY_CYCLES_150_MICRO ((uint32_t)(DELAY_CYCLES_500_NS * 300U)) #define DELAY_CYCLES_250_MICRO ((uint32_t)(DELAY_CYCLES_500_NS * 500U)) #define DELAY_CYCLES_500_MICRO ((uint32_t)(DELAY_CYCLES_500_NS * 1000U)) #define DELAY_CYCLES_2MS ((uint32_t)(DELAY_CYCLES_500_NS * 4000U)) #define DELAY_CYCLES_100MS ((uint32_t)(DELAY_CYCLES_2MS * 50U)) /***************************************************************************//** */ typedef enum { DDR_BOOT_PROGRESS = 0x00 //!< DDR_BOOT_PROGRESS } MSS_REPORT_STATUS; /*-------------------------------------------------------------------------*//** * delay() * Simple wait delay based on mcycles count * @param n Number of mcycles to wait. */ static inline void delay(uint32_t n) { volatile uint64_t cycles_end = rdcycle() + n ; while (rdcycle() < cycles_end) { } } /***************************************************************************//** MSS_SCB_ACCESS_CONFIG_ON_RESET SCB access settings on reset. Bits 23:16 Sets the number of cycles that the bus is held mastered by the MSS after grant removal. During this period the MSS must not start any new SCB cycles. This allows for any active SCB cycles to complete. This must be four greater than the number of pipelines (4) in the SCB ring from the MSS to G5C Bits 15:8 Sets how long SCB request is held active after SCB bus granted. Allows SCB bus master-ship to maintained across multiple SCB access cycles Bits 7:0 Set the timeout for an SCB access in CPU cycles. Note: These settings are used even after we change the MSS clock from SCB 80MHz default setting. Min 143 Hclk cycles for simulation set-up, making 160 */ #ifndef MSS_SCB_ACCESS_CONFIG_TIMEOUT #define MSS_SCB_ACCESS_CONFIG_TIMEOUT ((0x80U)&(0xFFU)) #endif #ifndef MSS_SCB_ACCESS_CONFIG_REQUST_TIME #define MSS_SCB_ACCESS_CONFIG_REQUST_TIME ((160UL<<8U)&(0xFFU<<8U)) #endif #ifndef MSS_SCB_ACCESS_CONFIG_BUSHOLD #define MSS_SCB_ACCESS_CONFIG_BUSHOLD ((8UL<<16U)&(0xFFU<<16U)) #endif #ifndef MSS_SCB_ACCESS_CONFIG #define MSS_SCB_ACCESS_CONFIG (MSS_SCB_ACCESS_CONFIG_BUSHOLD|MSS_SCB_ACCESS_CONFIG_REQUST_TIME|MSS_SCB_ACCESS_CONFIG_TIMEOUT) #endif /***************************************************************************//** mss_nwc_init() Called on start-up, initializes clocks, sgmii, ddr, mssio */ uint8_t mss_nwc_init ( void ); /***************************************************************************//** mss_nwc_init_ddr() Called on start-up, initializes ddr */ uint8_t mss_nwc_init_ddr ( void ); /***************************************************************************//** mtime_delay(x) delay function, passes microseconds waits x microseconds Assumption 1 is we have ensured clock is 1MHz Assumption 2 is we have not setup tick timer when using this function. It is only used by the startup code. Example: @code mtime_delay(100UL); @endcode */ void mtime_delay ( uint32_t microseconds ); /***************************************************************************//** ddr_status() Application can create own function to show progress Example: @code ddr_status(void){ static uint32_ count = 0U; count++; display_progress_banner(count); } @endcode */ void ddr_report_progress ( void ); #ifdef __cplusplus } #endif #endif /* __MSS_DDRC_H_ */ mss_pll.c000066400000000000000000000616721432224323300364740ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_pll.c * @author Microchip-FPGA Embedded Systems Solutions * @brief MPSS PLL setup * */ #include "mpfs_hal/mss_hal.h" #include "mss_pll.h" /** * We do it this way to avoid multiple LDRA warnings * alternate it to * #define MSS_SCB_MSS_PLL (IOSCB_CFM_MSS *) )x7xxxxxxx The actual * address * but above results in error every time we use the function */ PLL_TypeDef * const MSS_SCB_MSS_PLL = ((PLL_TypeDef *) MSS_SCB_MSS_PLL_BASE); PLL_TypeDef * const MSS_SCB_DDR_PLL = ((PLL_TypeDef *) MSS_SCB_DDR_PLL_BASE); PLL_TypeDef * const MSS_SCB_SGMII_PLL = ((PLL_TypeDef *) MSS_SCB_SGMII_PLL_BASE); IOSCB_CFM_MSS * const MSS_SCB_CFM_MSS_MUX =\ ((IOSCB_CFM_MSS *) MSS_SCB_MSS_MUX_BASE); IOSCB_CFM_SGMII * const MSS_SCB_CFM_SGMII_MUX =\ ((IOSCB_CFM_SGMII *) MSS_SCB_SGMII_MUX_BASE); IOSCB_IO_CALIB_STRUCT * const IOSCB_IO_CALIB_SGMII =\ (IOSCB_IO_CALIB_STRUCT *)IOSCB_IO_CALIB_SGMII_BASE; IOSCB_IO_CALIB_STRUCT * const IOSCB_IO_CALIB_DDR =\ (IOSCB_IO_CALIB_STRUCT *)IOSCB_IO_CALIB_DDR_BASE; /*******************************************************************************- * Symbols from the linker script used to locate the text, data and bss * sections. ******************************************************************************/ #ifndef MPFS_HAL_HW_CONFIG uint32_t __sc_load; uint32_t __sc_start; uint32_t __sc_end; #else extern uint32_t __sc_load; extern uint32_t __sc_start; extern uint32_t __sc_end; /******************************************************************************* * Local Defines * ******************************************************************************/ /******************************************************************************* * Local function declarations */ __attribute__((weak)) void copy_switch_code(void); /******************************************************************************* * Instance definitions * ******************************************************************************/ void sgmii_mux_config(uint8_t option); /******************************************************************************* Local functions * *******************************************************************************/ /***************************************************************************//** * set_RTC_divisor() * Set the RTC divisor based on MSS Configurator setting * Note: This will always be calculated so RTC clock is 1MHz. */ void set_RTC_divisor(void) { SYSREG->RTC_CLOCK_CR &= ~(0x01U<<16); /* disable RTC clock */ SYSREG->RTC_CLOCK_CR = (LIBERO_SETTING_MSS_EXT_SGMII_REF_CLK / \ LIBERO_SETTING_MSS_RTC_TOGGLE_CLK); SYSREG->RTC_CLOCK_CR |= (0x01U<<16); /* enable RTC clock */ } /***************************************************************************//** * mss_mux_pre_mss_pll_config() * * Feed through required reference clks to PLL, configure PLL and wait for lock ******************************************************************************/ static void mss_mux_pre_mss_pll_config(void) { /* * PLL RF clk mux selections * [31:15] Reserved * [14:10] pll1_fdr_sel * [9:8] pll1_rfclk1_sel * [7:6] pll1_rfclk0_sel * [5:4] pll0_rfclk1_sel * [3:2] pll0_rfclk0_sel * [1:0] clk_in_mac_tsu_sel * * Each mux uses 2 configuration bits. These are decoded as follows: * 00 vss * 01 refclk_p,refclk_n * 10 scb_clk * 10 serdes_refclk_crn_mss<0>, serdes_refclk_crn_mss<1> * * e.g. * PLL_CKMUX = 0x00000154 * pll0_rfclk0_sel = 1 => refclk_p is used for pll0 ref0 and refclk_n is * fed to MSS PLL ref1 */ /* CFM_MSS 0x3E002000 - 0x08 */ MSS_SCB_CFM_MSS_MUX->PLL_CKMUX = LIBERO_SETTING_MSS_PLL_CKMUX; /* * MSS Clock mux selections * [31:5] Reserved * [4] clk_standby_sel * [3:2] mssclk_mux_md * step 7: 7) MSS Processor writes mssclk_mux_sel_int<0>=1 to select the * MSS PLL clock. * [1:0] mssclk_mux_sel MSS glitchless mux select * 00 - msspll_fdr_0=clk_standby * msspll_fdr_1=clk_standby * 01 - msspll_fdr_0=pllout0 * msspll_fdr_1=clk_standby * 10 - msspll_fdr_0=clk_standby * msspll_fdr_1=pllout1 * 11 - msspll_fdr_0=pllout0 * msspll_fdr_1=pllout1 * * */ /* * We will not set as already set to 0, we feed through after we have setup * clock * MSS_SCB_CFM_MSS_MUX->MSSCLKMUX = LIBERO_SETTING_MSS_MSSCLKMUX; */ /* * Clock_Receiver * [13] en_rdiff * [12] clkbuf_en_pullup * [11:10] en_rxmode_n * [9:8] en_term_n * [7] en_ins_hyst_n * [6] en_udrive_n * [5:4] en_rxmode_p * [3:2] en_term_p * [1] en_ins_hyst_p * [0] en_udrive_p */ MSS_SCB_CFM_SGMII_MUX->CLK_XCVR = LIBERO_SETTING_SGMII_CLK_XCVR; /* * 29:25 bclk5_sel * 24:20 bclk4_sel * 19:15 bclk3_sel * 14:10 bclk2_sel * 9:5 bclk1_sel * 4:0 bclk0_sel * * From SAC spec: * Table 9 1: Each gbim bank clock mux programming in MSS corner * The DDRPHY bank clocks bclk_horz<5:0> and bclk_vert<5:0> are driven * from mux's gbim<5:0> in the MSS corner. Each mux uses 5 configuration * bits. * * BCLK mux selections * bclk0_sel=0x8 (pll0_out_1k<2> selected) * bclk1_sel=0x10 (pll0_out_1k<3> selected) * bclk2_sel=0x1 (vss selected) * bclk3_sel=0x1 (vss selected) * bclk4_sel=0x1 (vss selected) * bclk5_sel=0x1 (vss selected) * */ MSS_SCB_CFM_MSS_MUX->BCLKMUX = LIBERO_SETTING_MSS_BCLKMUX; /* MSS_SCB_CFM_MSS_MUX->SPARE0 = BCLKMUX_USER_CONFIG; */ MSS_SCB_CFM_MSS_MUX->FMETER_ADDR = LIBERO_SETTING_MSS_FMETER_ADDR; MSS_SCB_CFM_MSS_MUX->FMETER_DATAW = LIBERO_SETTING_MSS_FMETER_DATAW; MSS_SCB_CFM_MSS_MUX->FMETER_DATAR = LIBERO_SETTING_MSS_FMETER_DATAR; /* * */ volatile uint32_t i; for(i = 0U; i < 200U; i++) { ; //i++; } } /***************************************************************************//** * mss_mux_post_mss_pll_config(void) * * Once MSS locked, feed through to MSS * We must run this code from RAM, as we need to modify the clock of the eNVM * The first thing we do is change the eNVM clock, to prevent L1 cache accessing * eNVM as it will do as we approach the return instruction * The mb() makes sure order of processing is not changed by the compiler ******************************************************************************/ __attribute__((section(".ram_codetext"))) \ static void mss_mux_post_mss_pll_config(void) { /* * Modify the eNVM clock, so it now matches new MSS clock * * [5:0] * Sets the number of AHB cycles used to generate the PNVM clock,. * Clock period = (Value+1) * (1000/AHBFREQMHZ) * Value must be 1 to 63 (0 defaults to 15) * e.g. * 7 will generate a 40ns period 25MHz clock if the AHB clock is 200MHz * 11 will generate a 40ns period 25MHz clock if the AHB clock is 250MHz * 15 will generate a 40ns period 25MHz clock if the AHB clock is 400MHz * */ SYSREG->ENVM_CR = LIBERO_SETTING_MSS_ENVM_CR; mb(); /* make sure we change clock in eNVM first so ready by the time we leave */ /* * When you're changing the eNVM clock frequency, there is a bit * (ENVM_CR_clock_okay) in the eNVM_CR which can be polled to check that * the frequency change has happened before bumping up the AHB frequency. */ volatile uint32_t wait_for_true = 0U; while ((SYSREG->ENVM_CR & ENVM_CR_CLOCK_OKAY_MASK) !=\ ENVM_CR_CLOCK_OKAY_MASK) { #ifdef RENODE_DEBUG break; #endif wait_for_true++; /* need something here to stop debugger freezing */ } /* * Change the MSS clock as required. * * CLOCK_CONFIG_CR * [5:0] * Sets the master synchronous clock divider * bits [1:0] CPU clock divider * bits [3:2] AXI clock divider * bits [5:4] AHB/APB clock divider * 00=/1 01=/2 10=/4 11=/8 (AHB/APB divider may not be set to /1) * Reset = 0x3F * * SYSREG->CLOCK_CONFIG_CR = (0x0U<<0U) | (0x1U<<2U) | (0x2U<<4U); * MSS clk= 80Mhz, implies CPU = 80Mhz, AXI = 40Mhz, AHB/APB = 20Mhz * Until we switch in MSS PLL clock (MSS_SCB_CFM_MSS_MUX->MSSCLKMUX = 0x01) * e.g. If MSS clk 800Mhz * MSS clk= 800Mhz, implies CPU = 800Mhz, AXI = 400Mhz, AHB/APB = 200Mhz */ SYSREG->CLOCK_CONFIG_CR = LIBERO_SETTING_MSS_CLOCK_CONFIG_CR; /* * Feed clock from MSS PLL to MSS, using glitch-less mux * * MSS Clock mux selections * [31:5] Reserved * [4] clk_standby_sel * [3:2] mssclk_mux_md * step 7: 7) MSS Processor writes mssclk_mux_sel_int<0>=1 to select the * MSS PLL clock. * [1:0] mssclk_mux_sel MSS glitchless mux select * 00 - msspll_fdr_0=clk_standby * msspll_fdr_1=clk_standby * 01 - msspll_fdr_0=pllout0 * msspll_fdr_1=clk_standby * 10 - msspll_fdr_0=clk_standby * msspll_fdr_1=pllout1 * 11 - msspll_fdr_0=pllout0 * msspll_fdr_1=pllout1 * * */ MSS_SCB_CFM_MSS_MUX->MSSCLKMUX = LIBERO_SETTING_MSS_MSSCLKMUX; /* * Change the RTC clock divisor, so RTC clock is 1MHz */ set_RTC_divisor(); } /***************************************************************************//** * sgmii_mux_config(uint8_t option) * @param option 1 => soft reset, load RPC settings * 0 => write values using SCB ******************************************************************************/ void sgmii_mux_config(uint8_t option) { switch(option) { default: case SCB_UPDATE: /* write to SCB register */ /* * SCB address: 0x3E20 0008 * MSS Clock mux selections * * [31:0] SGMII_CLKMUX */ /* CFM_ETH - 0x3E200000 - - 0x08 */ MSS_SCB_CFM_SGMII_MUX->SGMII_CLKMUX =\ LIBERO_SETTING_SGMII_SGMII_CLKMUX; /* * SCB address: 0x3E20 0010 * Clock_Receiver * * [13] en_rdiff * [12] clkbuf_en_pullup * [11:10] en_rxmode_n * [9:8] en_term_n * [7] en_ins_hyst_n * [6] en_udrive_n * [5:4] en_rxmode_p * [3:2] en_term_p * [1] en_ins_hyst_p * [0] en_udrive_p */ MSS_SCB_CFM_SGMII_MUX->CLK_XCVR =\ LIBERO_SETTING_SGMII_CLK_XCVR; /* 0x2011 */ /* * SCB address: 0x3E20 0004 * PLL RF clk mux selections * * [3:2] pll0_rfclk1_sel * 00 => vss * 01 => refclk_p muxed to DDR PLL * and SGMII PLL ( see * 10 => scb_clk * 11 => serdes_refclk_crn_mss<1> * [1:0] pll0_rfclk0_sel * 00 => vss * 01 => refclk_n muxed to DDR PLL * and SGMII PLL * 10 => scb_clk * 11 => serdes_refclk_crn_mss<1> * * */ /* 0x05 => ref to SGMII and DDR */ MSS_SCB_CFM_SGMII_MUX->RFCKMUX =\ LIBERO_SETTING_SGMII_REFCLKMUX; break; case RPC_REG_UPDATE: /* * set the NV map reset * This will load the APB registers, set via SGMII TIP. * */ MSS_SCB_CFM_SGMII_MUX->SOFT_RESET = 1U; break; } } /***************************************************************************//** * * On startup, MSS supplied with 80MHz SCB clock 9.2 Power on procedure for the MSS PLL clock During POR: Keep PLL in power down mode. powerdown_int_b=0 After POR, Power-On steps: 1) mssclk_mux_sel_int<0>=0 & powerdown_int_b=0 & clk_standby_sel=0 MSS PLL is powered down and selects clk_standby=scb_clk 2) PFC Processor writes powerdown_int_b=1 & divq0_int_en=1 MSS PLL powers up, then lock asserts when locked. 3) PFC Processor switches mssclk_mux_sel_int<0>=1 MSS PLL clock is now sent to MSS. 4) When BOOT authentication is complete a. PFC processor writes mssclk_mux_sel_int<0>=0 to select clk_standby. b. PFC Processor writes powerdown_int_b=0 to power down the PLL >>>>>>>> G5 Soc User code >>>>>>>>>>>>>> c. MSS Processor writes new parameters to the MSS PLL 5) MSS Processor writes powerdown_int_b=1 Start up the PLL with NEW parameters. Wait for LOCK 6) MSS Processor enables all 4 PLL outputs. 7) MSS Processor writes mssclk_mux_sel_int<0>=1 to select the MSS PLL clock. * ******************************************************************************/ void mss_pll_config(void) { copy_switch_code(); /* copy switch code to RAM */ MSS_SCB_DDR_PLL->SOFT_RESET = PLL_INIT_AND_OUT_OF_RESET; MSS_SCB_MSS_PLL->SOFT_RESET = PLL_INIT_AND_OUT_OF_RESET; /* Enable the PLL by removing the reset- PERIPH / periph_reset_b - This asserts the functional reset of the block. It is asserted at power up. When written is stays asserted until written to 0. */ /* * 4. c. MSS Processor writes new parameters to the MSS PLL */ /* * [0] REG_BYPASS_GO_B * [0] BYPCK_SEL * [0] RESETONLOCK * [0] REG_RFCLK_SEL * [0] REG_DIVQ3_EN * [0] REG_DIVQ2_EN * [0] REG_DIVQ1_EN * [0] REG_DIVQ0_EN * [0] REG_RFDIV_EN * [0] REG_POWERDOWN_B */ MSS_SCB_MSS_PLL->PLL_CTRL = LIBERO_SETTING_MSS_PLL_CTRL & ~(PLL_CTRL_REG_POWERDOWN_B_MASK); /* * PLL calibration register * This value is factory set, do not overwrite * MSS_SCB_MSS_PLL->PLL_CAL = LIBERO_SETTING_MSS_PLL_CAL; * */ MSS_SCB_MSS_PLL->PLL_REF_FB = LIBERO_SETTING_MSS_PLL_REF_FB; MSS_SCB_MSS_PLL->PLL_DIV_0_1 = LIBERO_SETTING_MSS_PLL_DIV_0_1; MSS_SCB_MSS_PLL->PLL_DIV_2_3 = LIBERO_SETTING_MSS_PLL_DIV_2_3; MSS_SCB_MSS_PLL->PLL_CTRL2 = LIBERO_SETTING_MSS_PLL_CTRL2; MSS_SCB_MSS_PLL->PLL_FRACN = LIBERO_SETTING_MSS_PLL_FRACN; MSS_SCB_MSS_PLL->SSCG_REG_0 = LIBERO_SETTING_MSS_SSCG_REG_0; MSS_SCB_MSS_PLL->SSCG_REG_1 = LIBERO_SETTING_MSS_SSCG_REG_1; MSS_SCB_MSS_PLL->SSCG_REG_2 = LIBERO_SETTING_MSS_SSCG_REG_2; MSS_SCB_MSS_PLL->SSCG_REG_3 = LIBERO_SETTING_MSS_SSCG_REG_3; /* PLL phase registers */ MSS_SCB_MSS_PLL->PLL_PHADJ = LIBERO_SETTING_MSS_PLL_PHADJ; /* * 5) MSS Processor writes powerdown_int_b=1 * Start up the PLL with NEW parameters. Wait for LOCK */ mss_mux_pre_mss_pll_config(); /* feed required inputs */ /* bit 0 == REG_POWERDOWN_B */ MSS_SCB_MSS_PLL->PLL_CTRL = (LIBERO_SETTING_MSS_PLL_CTRL) | 0x01U; /* * Start up the PLL with NEW parameters. * Wait for LOCK * todo: make wait clock based */ volatile uint32_t timer_out=0x00FFFFFFU; while((MSS_SCB_MSS_PLL->PLL_CTRL & PLL_CTRL_LOCK_BIT) == 0U) { #ifdef RENODE_DEBUG break; #endif if (timer_out != 0U) { timer_out--; } else { timer_out=0x00FFFFFFU; flag_mss_pll_lock_error(); } } /* * 6) MSS Processor enables all 4 PLL outputs. * 7) MSS Processor writes mssclk_mux_sel_int<0>=1 to select the MSS PLL * clock. */ mss_mux_post_mss_pll_config(); } /** * flag_mss_pll_lock_error(void) * * Implement platform specific function for lock failure feedback * */ __attribute__((weak)) void flag_mss_pll_lock_error(void) { ASSERT(0U); } /** * * @param option choose between SCB or RPC and soft reset update method. */ void ddr_pll_config(REG_LOAD_METHOD option) { switch(option) { default: case SCB_UPDATE: /* write to SCB register */ /* PERIPH / periph_reset_b - This asserts the functional reset of * the block. It is asserted at power up. When written is stays * asserted until written to 0. * First set periph_reset_b, than remove reset. As may be called * more than one. * */ MSS_SCB_DDR_PLL->SOFT_RESET = PLL_INIT_AND_OUT_OF_RESET; MSS_SCB_DDR_PLL->PLL_CTRL = LIBERO_SETTING_DDR_PLL_CTRL & ~(PLL_CTRL_REG_POWERDOWN_B_MASK); /* PLL calibration register */ /* * PLL calibration register * This value is factory set, do not overwrite * MSS_SCB_DDR_PLL->PLL_CAL = LIBERO_SETTING_MSS_PLL_CAL; * */ MSS_SCB_DDR_PLL->PLL_REF_FB = LIBERO_SETTING_DDR_PLL_REF_FB; MSS_SCB_DDR_PLL->PLL_DIV_0_1 = LIBERO_SETTING_DDR_PLL_DIV_0_1; MSS_SCB_DDR_PLL->PLL_DIV_2_3 = LIBERO_SETTING_DDR_PLL_DIV_2_3; MSS_SCB_DDR_PLL->PLL_CTRL2 = LIBERO_SETTING_DDR_PLL_CTRL2; MSS_SCB_DDR_PLL->PLL_FRACN = LIBERO_SETTING_DDR_PLL_FRACN; MSS_SCB_DDR_PLL->SSCG_REG_0 = LIBERO_SETTING_DDR_SSCG_REG_0; MSS_SCB_DDR_PLL->SSCG_REG_1 = LIBERO_SETTING_DDR_SSCG_REG_1; MSS_SCB_DDR_PLL->SSCG_REG_2 = LIBERO_SETTING_DDR_SSCG_REG_2; MSS_SCB_DDR_PLL->SSCG_REG_3 = LIBERO_SETTING_DDR_SSCG_REG_3; /* PLL phase registers */ MSS_SCB_DDR_PLL->PLL_PHADJ = LIBERO_SETTING_MSS_PLL_PHADJ; MSS_SCB_DDR_PLL->PLL_CTRL = (LIBERO_SETTING_DDR_PLL_CTRL)\ | 0x01U; /* bit 0 == REG_POWERDOWN_B */ break; case RPC_REG_UPDATE: /* CFG_DDR_SGMII_PHY->SOFT_RESET_MAIN_PLL; */ CFG_DDR_SGMII_PHY->PLL_CTRL_MAIN.PLL_CTRL_MAIN =\ LIBERO_SETTING_DDR_PLL_CTRL | 0x01U; CFG_DDR_SGMII_PHY->PLL_REF_FB_MAIN.PLL_REF_FB_MAIN =\ LIBERO_SETTING_DDR_PLL_REF_FB; /* Read only in RPC * CFG_DDR_SGMII_PHY->PLL_FRACN_MAIN.PLL_FRACN_MAIN =\ * LIBERO_SETTING_DDR_PLL_FRACN; */ CFG_DDR_SGMII_PHY->PLL_DIV_0_1_MAIN.PLL_DIV_0_1_MAIN =\ LIBERO_SETTING_DDR_PLL_DIV_0_1; CFG_DDR_SGMII_PHY->PLL_DIV_2_3_MAIN.PLL_DIV_2_3_MAIN =\ LIBERO_SETTING_DDR_PLL_DIV_2_3; CFG_DDR_SGMII_PHY->PLL_CTRL2_MAIN.PLL_CTRL2_MAIN =\ LIBERO_SETTING_DDR_PLL_CTRL2; /* Read only in RPC todo: verify this is correct * CFG_DDR_SGMII_PHY->PLL_CAL_MAIN.PLL_CAL_MAIN =\ * LIBERO_SETTING_DDR_PLL_CAL; */ CFG_DDR_SGMII_PHY->PLL_PHADJ_MAIN.PLL_PHADJ_MAIN =\ LIBERO_SETTING_DDR_PLL_PHADJ; /*__I CFG_DDR_SGMII_PHY_SSCG_REG_0_MAIN_TypeDef SSCG_REG_0_MAIN; */ /*__I CFG_DDR_SGMII_PHY_SSCG_REG_1_MAIN_TypeDef SSCG_REG_1_MAIN; */ CFG_DDR_SGMII_PHY->SSCG_REG_2_MAIN.SSCG_REG_2_MAIN =\ LIBERO_SETTING_DDR_SSCG_REG_2; /*__I CFG_DDR_SGMII_PHY_SSCG_REG_3_MAIN_TypeDef SSCG_REG_3_MAIN; */ /* * set the NV map reset * This will load the APB registers, set via SGMII TIP. * */ /* bit 0 == REG_POWERDOWN_B */ MSS_SCB_DDR_PLL->SOFT_RESET = PLL_INIT_AND_OUT_OF_RESET; break; } } /** * ddr_pll_lock_scb(void) * checks to see if lock has occurred * @return => lock has occurred, 1=> no lock */ uint8_t ddr_pll_lock_scb(void) { uint8_t result = 1U; #ifndef RENODE_DEBUG if((MSS_SCB_DDR_PLL->PLL_CTRL & PLL_CTRL_LOCK_BIT) == PLL_CTRL_LOCK_BIT) { result = 0U; /* PLL lock has occurred */ } #else result = 0U; #endif return (result); } /***************************************************************************//** * ******************************************************************************/ void ddr_pll_config_scb_turn_off(void) { /* PERIPH / periph_reset_b */ MSS_SCB_DDR_PLL->PLL_CTRL &= (uint32_t)~0x00000001UL; } /***************************************************************************//** * sgmii_pll_config_scb(uint8_t option) * @param option 1 => soft reset, load RPC settings * 0 => write values using SCB ******************************************************************************/ void sgmii_pll_config_scb(uint8_t option) { switch(option) { default: case SCB_UPDATE: /* write to SCB register */ /* PERIPH / periph_reset_b - This asserts the functional reset of * the block. It is asserted at power up. When written is stays * asserted until written to 0. * First set periph_reset_b, than remove reset. As may be called * more than one. * */ MSS_SCB_SGMII_PLL->SOFT_RESET = PLL_INIT_AND_OUT_OF_RESET; MSS_SCB_SGMII_PLL->PLL_CTRL = LIBERO_SETTING_SGMII_PLL_CTRL & ~(PLL_CTRL_REG_POWERDOWN_B_MASK); /* PLL calibration register */ /* * PLL calibration register * This value is factory set, do not overwrite * MSS_SCB_SGMII_PLL->PLL_CAL = LIBERO_SETTING_MSS_PLL_CAL; * */ MSS_SCB_SGMII_PLL->PLL_REF_FB = LIBERO_SETTING_SGMII_PLL_REF_FB; MSS_SCB_SGMII_PLL->PLL_DIV_0_1 = LIBERO_SETTING_SGMII_PLL_DIV_0_1; MSS_SCB_SGMII_PLL->PLL_DIV_2_3 = LIBERO_SETTING_SGMII_PLL_DIV_2_3; MSS_SCB_SGMII_PLL->PLL_CTRL2 = LIBERO_SETTING_SGMII_PLL_CTRL2; MSS_SCB_SGMII_PLL->PLL_FRACN = LIBERO_SETTING_SGMII_PLL_FRACN; MSS_SCB_SGMII_PLL->SSCG_REG_0 = LIBERO_SETTING_SGMII_SSCG_REG_0; MSS_SCB_SGMII_PLL->SSCG_REG_1 = LIBERO_SETTING_SGMII_SSCG_REG_1; MSS_SCB_SGMII_PLL->SSCG_REG_2 = LIBERO_SETTING_SGMII_SSCG_REG_2; MSS_SCB_SGMII_PLL->SSCG_REG_3 = LIBERO_SETTING_SGMII_SSCG_REG_3; /* PLL phase registers */ MSS_SCB_SGMII_PLL->PLL_PHADJ = LIBERO_SETTING_SGMII_PLL_PHADJ; MSS_SCB_SGMII_PLL->PLL_CTRL = (LIBERO_SETTING_SGMII_PLL_CTRL)\ | 0x01U; /* bit 0 == REG_POWERDOWN_B */ break; case RPC_REG_UPDATE: /* * set the NV map reset * This will load the APB registers, set via SGMII TIP. * */ /* bit 0 == REG_POWERDOWN_B */ MSS_SCB_SGMII_PLL->SOFT_RESET = 0x01U; break; } } /** * sgmii_pll_lock_scb(void) * checks to see if lock has occurred * @return => lock has occurred, 1=> no lock */ uint8_t sgmii_pll_lock_scb(void) { uint8_t result = 1U; #ifndef RENODE_DEBUG if((MSS_SCB_SGMII_PLL->PLL_CTRL & PLL_CTRL_LOCK_BIT) == PLL_CTRL_LOCK_BIT) { result = 0U; /* PLL lock has occurred */ } #else result = 0U; #endif return (result); } /***************************************************************************//** * Copy switch code routine to RAM. * Copy locations have been defined in the linker script ******************************************************************************/ __attribute__((weak)) void copy_switch_code(void) { uint32_t * sc_lma = &__sc_load; uint32_t * end_sc_vma = &__sc_end; uint32_t * sc_vma = &__sc_start; if ( sc_vma != sc_lma ) { while ( sc_vma < end_sc_vma ) { *sc_vma = *sc_lma; sc_vma++ ; sc_lma++; } } } #endif /* MPFS_HAL_HW_CONFIG */ mss_pll.h000066400000000000000000000320611432224323300364670ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_pll.h * @author Microchip-FPGA Embedded Systems Solutions * @brief PLL defines * */ /*=========================================================================*//** @page PolarFire SoC MSS Clock Setup ============================================================================== Introduction ============================================================================== The PolarFire SoC Microprocessor subsystem (MSS) has three PLL's, the MSS, DDR and MSS SGMII's. Two CFM IP blocks are used to mux the PLL input and outputs. ============================================================================== PLL Inputs ============================================================================== Each of the three PLL's can be configured with the following inputs: - VSS ( default on reset ) - external ref clock in SGMII IO Block - SCB Clock (80MHz) - North West corner clock mux structure ICB There are two bits associated with setting clk source Note on North West corner clock mux structure ICB The Fabric reference clock inputs source come from the clock mux's in the upper left corner (regular FPGA corner) that provided clocks that can be routed in from various places that will include from IOs, from the FPGA fabric, etc. ============================================================================== MSS PLL Outputs ============================================================================== Each PLL has four outputs. These are generally gated through a mux MSS PLL Outputs | Output(0-3) | Detail | Mux | Muxed with | | ------------- |:-------------:|:-------------:| -----------:| | msspll_fdr_0 | clk_in_mss | no | - | | msspll_fdr_1 | clk_in_crypto | no | - | | msspll_fdr_2 | clk_in_emmc | glitch-less | SCB clk | | msspll_fdr_3 | clk_in_can | glitch-less | SCB clk | ============================================================================== SCB bus timing ============================================================================== When the MSS is using the SCB bus, there is a timing relationship. The defaults should be OK here. In necessary, the timing used by the MSS SCB access is adjusted using the MSS system register TIMER. (SCBCFG_REGS->TIMER.TIMER) - Bits 15:8 Sets how long SCB request is held active after SCB bus granted. - Allows SCB bus master-ship to maintained across multiple SCB access cycles - Bits 7:0 Set the timeout for an SCB access in CPU cycles. ============================================================================== eNVM timing ============================================================================== The clk used by the eNVM is adjusted using the following register: SYSREG->ENVM_CR [5:0] Sets the number of AHB cycles used to generate the PNVM clock,. Clock period = (Value+1) * (1000/AHBFREQMHZ) Value must be 1 to 63 (0 defaults to 15) e.g. 11 will generate a 40ns period 25MHz clock if the AHB clock is 250MHz 15 will generate a 40ns period 25MHz clock if the AHB clock is 400MHz ============================================================================== MSS clocks at reset ============================================================================== When the MSS comes out of reset, the MSS will be running on the SCB supplied 80MHz clock. ============================================================================== MSS clock setup - Use case one - using external reference from SGMII I/O Blk ============================================================================== Use case one will be used in the majority of cases. This is where the MSS PLL reference clk will be supplied from an external reference through the external ref clock in SGMII IO Block. scb clk 01=>ext clk ref + +----------+ +--------+ | 0=>SCB crn | | | MSS | | 1=>PLL +--->| | | PLL | | +------+ +-----+ scb | | | | +>| |mss | | +---- | | | | mux +--> | ext + p | mux +-->|ref0 0+--->| |clk | clk +--------->| | | | +------+ | ref | n vss | | | | 0=>SCB | +---+ ->| | | | 1=>PLL | | | | | | | +------+ | | | | | | |scb-| |crypto +-----+ | +----------+ | | | mux +--> | | 1+--->| |clk | 01=>ext clk ref | | +------+ | +----------+ | | | crn| | | | +------+ | +-->| | | | | | | scb| | | 2+--->| eMMC + | +-->| | | | | | | | mux +-->|ref1 | +------+ +----->| | | | vss| | | | +------+ +-->| | | | | | | | | 3+--->| CAN + | | | | | | +----------+ +--------+ +------+ Steps to setup ext clk: 1. The external clock reference is setup- In SGMII setup 2. The input mux is set to take input from ext ref clk 3. MSS PLL clock is setup with required settings 4. PLL is checked until locked 5. MSS PLL output is switched through to MSS ( switch code run from ram ) 6. eNVM clcock is changed as required 7. return from RAM routine and continue ============================================================================== MSS clock dividers ============================================================================== The three dividers generating the MSS master clocks are controllable via the system register (CLOCK_CONFIG_CR). CPU clock dividers are set in the function mss_mux_post_mss_pll_config(void) | Divider | Config bits | Reset | MAX feq. * | | ------------- |:-------------:|:----------:| -----------:| | CPU | 1:0 | 00 | 625 | | AXI | 3:2 | 01 | 312.5 | | AHB/APB | 5:4 | 10 | 156.25 | settings = 00=/1, 01=/2, 01=/4, 01=/8 * verify MAX feq. setting with particular silicon variant data sheet - The CPU clock must not exceed 625MHz - The AXI clock must not exceed 312.5MHz - The AHB clock must not exceed 156.25MHz - The CPU clock must be greater or equal to the AXI clock - The AHB/APB clocks cannot be divided by 1. Divide by 1 will divide the clock by 2. - The clock divider register may be changed from any value to any value in one go. - When the USB block is in-use the AHB clock must be greater than 66 MHz. +---------------------+ +-------------+ | +----------+ | | | | +--> /1/2/4/8 +-->+--------->| CPU cores | +-----------+ | | +----------+ | | | | | | | | +-------------+ | MSS CLK | | | | | | | | | +-------------+ | +---------+---+ +---------+ | | dfi_apb_pclk| | | | +->|/4/8/16 +--->+----------> | | | | | +---------+ | | | | | | | | +-------------+ +-----------+ | | | | | | | | | +-------------+ | | +---------+ | | MSS AXI | | +--> 1/2/4/8 +--->+--------->| Buses and | | | +---------+ | | peripherals | | | | +-------------+ | | | | | | | | | +-------------+ | | +-------+ | | MSS APB/AHB | | +->| 2/4/8 +----->+--------->| Buses and | +-------+ | | peripherals | +---------------------+ +-------------+ *//*=========================================================================*/ #ifndef MSS_DDR_SGMII_MSS_PLL_H_ #define MSS_DDR_SGMII_MSS_PLL_H_ #ifdef __cplusplus extern "C" { #endif #define PLL_CTRL_LOCK_BIT ((0x01U) << 25U) /* * bit0 1: This when asserted resets all the non-volatile register bits * e.g. RW-P bits, the bit self clears i.e. is similar to a W1P bit * bit1 1: This when asserted resets all the register bits apart from the * non-volatile registers, the bit self clears. i.e. is similar to a * W1P bit */ #define PLL_INIT_AND_OUT_OF_RESET 0x00000003UL #define PLL_CTRL_REG_POWERDOWN_B_MASK 0x00000001UL typedef enum RTC_CLK_SOURCE_ { SCB_80M_CLOCK = 0x00, /*!< 0 SCB clock source */ MSS_PLL_CLOCK = 0x01, /*!< 1 MSS PLL clock source */ } RTC_CLK_SOURCE; typedef enum REG_LOAD_METHOD_ { SCB_UPDATE = 0x00, /*!< 0 SCB direct load */ RPC_REG_UPDATE = 0x01, /*!< 1 RPC -> SCB load */ } REG_LOAD_METHOD; /***************************************************************************//** ddr_pll_config() configure DDR PLL Example: @code ddr_pll_config(); @endcode */ void ddr_pll_config(REG_LOAD_METHOD option); /***************************************************************************//** ddr_pll_lock_scb() Checks if PLL locked @return 0U if locked Example: @code if (ddr_pvt_calibration() == 0U) { PLL is locked } @endcode */ uint8_t ddr_pll_lock_scb(void); /***************************************************************************//** sgmii_pll_config_scb() configure sgmii PLL @param option 1 => soft reset, load RPC settings 0 => write values using SCB Example: @code sgmii_pll_config_scb(1U); @endcode */ void sgmii_pll_config_scb(uint8_t option); /***************************************************************************//** sgmii_pll_lock_scb() Checks if PLL is locked @return 0U if locked Example: @code if (ddr_pvt_calibration() == 0U) { PLL is locked } @endcode */ uint8_t sgmii_pll_lock_scb(void); /***************************************************************************//** ddr_pll_config_scb_turn_off() Puts PLL in reset Example: @code ddr_pll_config_scb_turn_off(); @endcode */ void ddr_pll_config_scb_turn_off(void); /***************************************************************************//** set_RTC_divisor() Sets the RTC divisor based on values from Libero It is assumed the RTC clock is set to 1MHz Example: @code set_RTC_divisor(); @endcode */ void set_RTC_divisor(void); /***************************************************************************//** sgmii_mux_config_via_scb() configures mux for SGMii Example: @code sgmii_mux_config_via_scb(); @endcode */ void sgmii_mux_config_via_scb(uint8_t option); /***************************************************************************//** pre_configure_sgmii_and_ddr_pll_via_scb() @param option 1 => soft reset, load RPC settings 0 => write values using SCB Example: @code ddr_pvt_calibration(1U); @endcode */ void pre_configure_sgmii_and_ddr_pll_via_scb(uint8_t option); /***************************************************************************//** mss_pll_config() Setup the MSS PLL feeds in ref clock, set freq based on MSS Configurator settings and once lock achieved, feeds out to the MSS. Example: @code mss_pll_config(); @endcode */ void mss_pll_config(void); /***************************************************************************//** flag_mss_pll_lock_error() Instantiate platform specific function to give error feedback on your platform */ void flag_mss_pll_lock_error(void); #ifdef __cplusplus } #endif #endif /* MSS_DDR_SGMII_MSS_PLL_H_ */ mss_scb_nwc_regs.h000066400000000000000000000120111432224323300403270ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_scb_nwc_regs.h * @author Microchip-FPGA Embedded Systems Solutions * @brief SCB registers and associated structures relating to the NWC * */ #ifndef MSS_DDR_SGMII_MSS_SCB_NWC_REGS_H_ #define MSS_DDR_SGMII_MSS_SCB_NWC_REGS_H_ #include "mpfs_hal/mss_hal.h" #ifdef __cplusplus extern "C" { #endif #ifndef __I #define __I const volatile #endif #ifndef __IO #define __IO volatile #endif #ifndef __O #define __O volatile #endif /*------------ NWC PLL definition -----------*/ typedef struct { __IO uint32_t SOFT_RESET; /*!< Offset: 0x0 */ __IO uint32_t PLL_CTRL; /*!< Offset: 0x4 */ __IO uint32_t PLL_REF_FB; /*!< Offset: 0x8 */ __IO uint32_t PLL_FRACN; /*!< Offset: 0xc */ __IO uint32_t PLL_DIV_0_1; /*!< Offset: 0x10 */ __IO uint32_t PLL_DIV_2_3; /*!< Offset: 0x14 */ __IO uint32_t PLL_CTRL2; /*!< Offset: 0x18 */ __IO uint32_t PLL_CAL; /*!< Offset: 0x1c */ __IO uint32_t PLL_PHADJ; /*!< Offset: 0x20 */ __IO uint32_t SSCG_REG_0; /*!< Offset: 0x24 */ __IO uint32_t SSCG_REG_1; /*!< Offset: 0x28 */ __IO uint32_t SSCG_REG_2; /*!< Offset: 0x2c */ __IO uint32_t SSCG_REG_3; /*!< Offset: 0x30 */ } PLL_TypeDef; /*------------ NWC PLL MUX definition -----------*/ typedef struct { __IO uint32_t SOFT_RESET; /*!< Offset: 0x0 */ __IO uint32_t BCLKMUX; /*!< Offset: 0x4 */ __IO uint32_t PLL_CKMUX; /*!< Offset: 0x8 */ __IO uint32_t MSSCLKMUX; /*!< Offset: 0xc */ __IO uint32_t SPARE0; /*!< Offset: 0x10 */ __IO uint32_t FMETER_ADDR; /*!< Offset: 0x14 */ __IO uint32_t FMETER_DATAW; /*!< Offset: 0x18 */ __IO uint32_t FMETER_DATAR; /*!< Offset: 0x1c */ __IO uint32_t TEST_CTRL; /*!< Offset: 0x20 */ } IOSCB_CFM_MSS; typedef struct { __IO uint32_t SOFT_RESET; /*!< Offset: 0x0 */ __IO uint32_t RFCKMUX; /*!< Offset: 0x4 */ __IO uint32_t SGMII_CLKMUX; /*!< Offset: 0x8 */ __IO uint32_t SPARE0; /*!< Offset: 0xc */ __IO uint32_t CLK_XCVR; /*!< Offset: 0x10 */ __IO uint32_t TEST_CTRL; /*!< Offset: 0x14 */ } IOSCB_CFM_SGMII; typedef struct { __IO uint32_t SOFT_RESET_IOCALIB; /*!< Offset: 0x00 */ __IO uint32_t IOC_REG0; /*!< Offset: 0x04 */ __I uint32_t IOC_REG1; /*!< Offset: 0x08 */ __I uint32_t IOC_REG2; /*!< Offset: 0x0c */ __I uint32_t IOC_REG3; /*!< Offset: 0x10 */ __I uint32_t IOC_REG4; /*!< Offset: 0x14 */ __I uint32_t IOC_REG5; /*!< Offset: 0x18 */ __IO uint32_t IOC_REG6; /*!< Offset: 0x1c */ } IOSCB_IO_CALIB_STRUCT; #define MSS_SCB_MSS_PLL_BASE (0x3E001000U) /*!< ( MSS_SCB_MSS_PLL_BASE ) Base Address */ #define MSS_SCB_DDR_PLL_BASE (0x3E010000U) /*!< ( MSS_SCB_DDR_PLL_BASE ) Base Address */ #define MSS_SCB_SGMII_PLL_BASE (0x3E080000U) /*!< ( MSS_SCB_SGMII_PLL_BASE ) Base Address */ #define MSS_SCB_MSS_MUX_BASE (0x3E002000U) /*!< ( MSS_SCB_MSS_MUX_BASE ) Base Address */ #define MSS_SCB_SGMII_MUX_BASE (0x3E200000U) /*!< ( MSS_SCB_SGMII_PLL_BASE ) Base Address */ #define IOSCB_IO_CALIB_SGMII_BASE (0x3E800000U) /*!< ( IOSCB_IO_CALIB_SGMII_BASE ) Base Address */ #define IOSCB_IO_CALIB_DDR_BASE (0x3E040000U) /*!< ( IOSCB_IO_CALIB_SGMII_BASE ) Base Address */ extern PLL_TypeDef * const MSS_SCB_MSS_PLL; extern PLL_TypeDef * const MSS_SCB_DDR_PLL; extern PLL_TypeDef * const MSS_SCB_SGMII_PLL; extern IOSCB_CFM_MSS * const MSS_SCB_CFM_MSS_MUX; extern IOSCB_CFM_SGMII * const MSS_SCB_CFM_SGMII_MUX; extern IOSCB_IO_CALIB_STRUCT * const IOSCB_IO_CALIB_SGMII; extern IOSCB_IO_CALIB_STRUCT * const IOSCB_IO_CALIB_DDR; #ifdef __cplusplus } #endif #endif /* MSS_DDR_SGMII_MSS_SCB_NWC_REGS_H_ */ mss_sgmii.c000066400000000000000000000540001432224323300370000ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_sgmii.c * @author Microchip-FPGA Embedded Systems Solutions * @brief sgmii related functions * */ #include #include #include "mpfs_hal/mss_hal.h" #include "simulation.h" #ifdef MPFS_HAL_HW_CONFIG static PART_TYPE silicon_variant = PART_NOT_DETERMINED; /* * local functions */ static void setup_sgmii_rpc_per_config(void); #ifdef SGMII_SUPPORT static uint32_t sgmii_channel_setup(void); #endif /* * local variable */ static uint32_t sro_dll_90_code; /* * local functions */ static void set_early_late_thresholds(uint8_t n_late_threshold, uint8_t p_early_threshold); /* * extern functions */ extern void sgmii_mux_config(uint8_t option); uint32_t sgmii_setup(void) { #ifdef SGMII_SUPPORT /* * Check if any tx/Rx channels enabled */ if((LIBERO_SETTING_SGMII_MODE & (TX_RX_CH_EN_MASK<SOFT_RESET_SGMII.SOFT_RESET_SGMII = \ (0x01 << 8U) | 1U; /* PERIPH soft reset */ CFG_DDR_SGMII_PHY->SOFT_RESET_SGMII.SOFT_RESET_SGMII = 1U; setup_sgmii_rpc_per_config(); /* load RPC SGMII_MODE register ext */ /* Enable the Bank controller */ /* * Set soft reset on IP to load RPC to SCB regs (dynamic mode) * Bring the sgmii bank controller out of reset =- ioscb_bank_ctrl_sgmii */ IOSCB_BANK_CNTL_SGMII->soft_reset = 1U; /* DPC_BITS NV_MAP reset */ sgmii_training_state = SGMII_IO_EN; break; case SGMII_IO_EN: /* * Check the IO_EN signal here. * This is an output from the bank controller power detector, which are * turned on using MSS_IO_EN */ /* aro_ioen_bnk - PVT calibrator IOEN */ timer_out++; if((CFG_DDR_SGMII_PHY->PVT_STAT.PVT_STAT & (0x01U<<6U)) != 0U) { timer_out=0U; sgmii_training_state = SGMII_RAMP_TIMER; } break; case SGMII_RAMP_TIMER: /* * IO power ramp wait time * After IOEN is received from power detectors DDR and SGMii, extra time * required for voltage to ramp. * This time will come from the user- Dependent on ramp time of power * supply * Approximately - Bank power timer (from ioen_in to ioen_out = 10uS)? * */ timer_out++; if(timer_out >= 0xFU) { timer_out=0U; sgmii_training_state = SGMII_IO_SETUP; } break; case SGMII_IO_SETUP: /* * fixme- not sure if we should be setting this register * From regmap detail: * bit 8 of MSS_RESET_CR * Asserts a reset the SGMII block containing the MSS reference clock * input. * Warning that setting this bit causes the external reference clock * input to the * MSS PLL to disappear. * It is advisable to use the SGMII channel soft resets in the PHY * instead of this bit. * However if E51 software wants to set this bit, the MSS clock source * should be switched over to the standby source in advance. */ SCB_REGS->MSS_RESET_CR.MSS_RESET_CR = 0; /* * I ran the sim past the place where we set the nvmap_reset in the * SOFT_RESET_SGMII register and it did not result in any * change from the DLL default bits. * But I traced the 'flashing' signal on one of these regs back to * 'dll0_soft_reset_nv_map' (not 'pll0_soft_reset_periph'). * Now the only place I can find 'dll0_soft_reset_nv_map' is in SCB * space...ie 0x3e10_0000 SOFT_RESET register. * */ /* * so we have to use scb register to reset as no APB register available * to soft reset the IP * ioscb_dll_sgmii * */ IOSCB_DLL_SGMII->soft_reset = (0x01U << 0x00U); /* reset sgmii DLL */ /* * I have discovered the problem with the tx channels (soft reset issue) * So we require the: * * sgmiiphy_lane 01 soft-reset register (0x3650_0000) to be written to * with 0x1 (to set the nv_map bit[0] =1 (self clears)) * same for sgmiiphy_lane 23 soft-reset register (0x3651_0000). * * This will result in the rpc bits for the Lane controls to get loaded. * Not happening currently. * * The soft_reset_sgmii occurs in the mss_ddr.c line 436, so I suppose * we put the 2 new soft reset writes after that. * */ { /* sgmiiphy_lane 01 soft-reset register (0x3650_0000) */ SGMIIPHY_LANE01->soft_reset = 0x000000001U; /* sgmiiphy_lane 23 soft-reset register (0x3650_0000) */ SGMIIPHY_LANE23->soft_reset = 0x000000001U; } /* * Kick-off calibration, by taking calibration IP out of reset */ /* * Soft reset */ { /* PVT soft reset - APB*/ /* reg_pvt_soft_reset_periph */ CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (0x01U<< 10U) | (0x7FU<<0U); /* reg_pvt_soft_reset_periph */ CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (0x7FU<<0U); /* PVT soft reset - SCB */ /* make sure out of reset */ IOSCB_IO_CALIB_SGMII->SOFT_RESET_IOCALIB = 0x1U; /* make sure out of reset */ IOSCB_IO_CALIB_SGMII->SOFT_RESET_IOCALIB = 0x0U; } sgmii_training_state = SGMII_WAIT_FOR_CALIB_COMPLETE; break; case SGMII_WAIT_FOR_CALIB_COMPLETE: /* * Verify calibration * Bank 5 PVT calibrator can be controlled by MSS firmware through APB * registers to do initial calibration and re-calibration. During startup, * the initial calibration can be started by default when MSS releases SGMII * reset. Re-calibration is enabled by default with reg_pvt_calib_start/lock * bits being set to 1 before startup, and MSS firmware can start * re-calibration after startup by toggling pvt_calib_start/lock bits per * PVT calibrator spec. * */ if((CFG_DDR_SGMII_PHY->PVT_STAT.PVT_STAT & (1U << 14U)) == (1U << 14U)) { sgmii_training_state = SGMII_ASSERT_CALIB_LOCK; } break; case SGMII_ASSERT_CALIB_LOCK: /* * now assert calib lock * calibrated pcode and ncode will be written. * */ CFG_DDR_SGMII_PHY->PVT_STAT.PVT_STAT |= 0x40000000UL; IOSCB_IO_CALIB_SGMII->IOC_REG0 |= (0x01U<<14U); sgmii_training_state = SGMII_SET_UP_PLL; break; case SGMII_SET_UP_PLL: /* * SGMii Step 3) Wait for PLL and DLL lock * Delay codes generated */ /* 0U => configure using scb, 1U => NVMAP reset */ sgmii_mux_config(RPC_REG_UPDATE); /* 0U => configure using scb, 1U => NVMAP reset */ sgmii_pll_config_scb(RPC_REG_UPDATE); timer_out=0U; sgmii_training_state = SGMII_WAIT_FOR_MSS_LOCK; break; case SGMII_WAIT_FOR_MSS_LOCK: if (CFG_DDR_SGMII_PHY->PLL_CNTL.PLL_CNTL & (1U<<7U)) { sgmii_training_state = SGMII_WAIT_FOR_DLL_LOCK; } break; case SGMII_WAIT_FOR_DLL_LOCK: if (CFG_DDR_SGMII_PHY->RECAL_CNTL.RECAL_CNTL & (1U<<23U)) { sgmii_training_state = SGMII_TURN_ON_MACS; } break; case SGMII_TURN_ON_MACS: /* * Provide mac clocks * The nw_config register for mac0 (0x2011_0004): I am forcing 'gigabit' and * 'tbi' bits = 11. * The same for Mac1. * This starts up the tx_mac_clocks for the 2 macs. * */ /* the mac clocks need to be turned on when setting up the sgmii */ (void)mss_config_clk_rst(MSS_PERIPH_MAC0, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_ON); (void)mss_config_clk_rst(MSS_PERIPH_MAC0, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_ON); GEM_A_LO->network_config |= (0x01U << 10U) | (0x01U << 11U); /* GEM0 */ GEM_B_LO->network_config |= (0x01U << 10U) | (0x01U << 11U); /* GEM1 */ sgmii_training_state = SGMII_DETERMINE_SILICON_VARIANT; break; case SGMII_DETERMINE_SILICON_VARIANT: /* * Determine Silicon variant from generated dll generated sro_dll_90_code */ sro_dll_90_code = ((CFG_DDR_SGMII_PHY->RECAL_CNTL.RECAL_CNTL >> 16U) & 0x7FU); if(CFG_DDR_SGMII_PHY->SPARE_STAT.SPARE_STAT & (01U<<31U)) /* bit31 == 1 => post rev B silicon */ { silicon_variant = PART_REVC_OR_LATER; set_early_late_thresholds(LATE_EYE_WIDTH_PART_REVC_OR_LATER_PRE_TEST, EARLY_EYE_WIDTH_PART_REVC_OR_LATER_PRE_TEST); } else { /* * SS part expect < 13 * typical-typical or FF expect > 13 */ if(sro_dll_90_code < MIN_DLL_90_CODE_VALUE_INDICATING_TT_PART_REVB) /* SS part */ { silicon_variant = SS_PART_REVB; set_early_late_thresholds(LATE_EYE_WIDTH_SS_PART_REVB, EARLY_EYE_WIDTH_SS_PART_REVB); } else { silicon_variant = TT_PART_REVB; set_early_late_thresholds(LATE_TT_PART_REVB, EARLY_TT_PART_REVB); } } sgmii_training_state = SGMII_RESET_CHANNELS; break; case SGMII_RESET_CHANNELS: /* * DLL soft reset - Already configured * PVT soft reset - Already configured * Bank controller soft reset - Already configured * CLKMUX soft reset - Already configured * Lane0 soft reset - must be soft reset here * Lane1 soft reset - must be soft reset here * * __IO uint32_t reg_lane0_soft_reset_periph :1; bit 13 * __IO uint32_t reg_lane1_soft_reset_periph :1; bit 14 */ CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (1U << 14U)|(1U << 13U)|(0x7FU<<0U); CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (0U << 14U)|(0U << 13U)|(0x7FU<<0U); if(silicon_variant == PART_REVC_OR_LATER) { timer_out=0U; sgmii_training_state = SGMII_WAIT_10MS; } else { sgmii_training_state = SGMII_CHANNELS_UP; } break; case SGMII_WAIT_10MS: timer_out++; if(timer_out >= 0xFFFU) { timer_out=0U; sgmii_training_state = SGMII_CHECK_REVC_RESULT; } break; case SGMII_CHECK_REVC_RESULT: if ( (CFG_DDR_SGMII_PHY->SPARE_STAT.SPARE_STAT & ARO_REF_PCODE_MASK) > ARO_REF_PCODE_REVC_THRESHOLD ) { /* OK, we are good */ sgmii_training_state = SGMII_CHANNELS_UP; } else { /* need to adjust eye values */ set_early_late_thresholds(LATE_EYE_WIDTH_PART_REVC_OR_LATER, EARLY_EYE_WIDTH_PART_REVC_OR_LATER); /* * Now reset the channels */ CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (1U << 14U)|(1U << 13U)|(0x7FU<<0U); CFG_DDR_SGMII_PHY->DYN_CNTL.DYN_CNTL = (0U << 14U)|(0U << 13U)|(0x7FU<<0U); /* OK, we are good */ sgmii_training_state = SGMII_CHANNELS_UP; } break; case SGMII_CHANNELS_UP: /* * SGMii Step 4) Monitor the DLL codes for Voltage and Temp variation * MSS E51 software sets the magnitude value of variation to flag. * MSS E51 software can poll this flag. * Re-calibration, if needed, is controlled by E51 software if needed. * ML step 4- This is a monitoring step- to be run constantly in the back * ground */ status = SGMII_FINISHED_SETUP; break; } /* end of switch statement */ return(status); } #endif /** * setup_sgmii_rpc_per_config * Configures SGMII RPC TIP registers */ static void setup_sgmii_rpc_per_config(void) { CFG_DDR_SGMII_PHY->SGMII_MODE.SGMII_MODE = (LIBERO_SETTING_SGMII_MODE & ~REG_CDR_MOVE_STEP); CFG_DDR_SGMII_PHY->CH0_CNTL.CH0_CNTL = LIBERO_SETTING_CH0_CNTL; CFG_DDR_SGMII_PHY->CH1_CNTL.CH1_CNTL = LIBERO_SETTING_CH1_CNTL; CFG_DDR_SGMII_PHY->RECAL_CNTL.RECAL_CNTL = LIBERO_SETTING_RECAL_CNTL; CFG_DDR_SGMII_PHY->CLK_CNTL.CLK_CNTL = LIBERO_SETTING_CLK_CNTL; /* ibuffmx_p and _n rx1, bit 22 and 23 , rx0, bit 20 and 21 */ CFG_DDR_SGMII_PHY->SPARE_CNTL.SPARE_CNTL = LIBERO_SETTING_SPARE_CNTL; CFG_DDR_SGMII_PHY->PLL_CNTL.PLL_CNTL = LIBERO_SETTING_PLL_CNTL; } /** * SGMII Off mode */ void sgmii_off_mode(void) { /* * do soft reset of SGMII TIP */ CFG_DDR_SGMII_PHY->SOFT_RESET_SGMII.SOFT_RESET_SGMII = (0x01 << 8U) | 1U; CFG_DDR_SGMII_PHY->SOFT_RESET_SGMII.SOFT_RESET_SGMII = 1U; /* * */ setup_sgmii_rpc_per_config(); /* * Resetting the SCB register only required in already in dynamic mode. If * not reset, IO will not be configured. */ IOSCB_DLL_SGMII->soft_reset = (0x01U << 0x00U); /* reset sgmii */ } /** * */ void ddr_pvt_calibration(void) { /* * R3.1 * PVT calibration * Wait for IOEN from power detectors DDR and SGMII - IO enable signal from * System Control powers on * * From DDR phy SAC spec: * MSS processor releases dce bus to send RPC bits to IO buffer, * setting each to it's programmed mode and then asserts * ioen high at end of this state. * * * Following verification required for MSS IO Calibration (DDRPHY, * SGMII and MSSIO) * Auto-calibration supply ramp time settings * Calibration in reset until ioen_bnk goes high, timer complete * and setup of bits complete * scbclk divider setting (/1) * calibration clkdiv setting * VS bit settings * Initial non-calibrated codes to IOs (functional max codes) * Calibration signal transitions * pvt_calib_status , r in reg DYN_CNTL * reg_calib_reset, w/r in reg IOC_REG6 * calib_clkdiv, w/r in reg IOC_REG6 * soft_reset_periph_b, * calib_lock, w/r in reg IOC_REG0 * calib_start, w/r in reg IOC_REG0 * calib_intrpt r in reg * Final calibration codes * Lane latching of codes * IO Glitching */ volatile uint32_t timer_out=0U; #ifndef RENODE_DEBUG /* sro_ioen_out */ while((CFG_DDR_SGMII_PHY->IOC_REG1.IOC_REG1 & (1U<<4U)) == 0U) { timer_out++; /*todo: add a fail break */ } #endif /* * R3.2 Trigger timer and wait for completion * PVT calibration * After IOEN is received from power detectors DDR and SGMII, extra time * required for voltage to ramp. * This time will come from the user- Dependent on ramp time of power supply * Approximately - Bank power timer (from ioen_in to ioen_out = 10uS)? * */ /*todo: implement proper timer- user will supply ramp time */ timer_out=0U; while(timer_out < 0xFU) { timer_out++; } /* * R3.2 Initiate calibration: * * IOC_REG6 * bit 2:1 reg_calib_clkdiv * bit 0 reg_calib_reset * * DDRIO: calib_reset: 1 -> 0 * mss_write(0x20007000 + 0x21C,0x00000004); * DDRIO: calib_rst_b: 0 -> 1 * mss_write(0x20007000 + 0x220,0x00000000); * SGMII: calib_rst_b: 0 -> 1 * mss_write(0x20007000 + 0xC1C,0x00000000); * */ /* * Soft reset */ /* PVT soft reset - APB*/ /* DDRIO: calib_reset: 1 -> 0, clk divider changed - from 2 - to 3 */ CFG_DDR_SGMII_PHY->IOC_REG6.IOC_REG6 = 0x00000006U; /* PVT soft nv reset - SCB, should load from RPC */ IOSCB_IO_CALIB_DDR->SOFT_RESET_IOCALIB = 0x1U; /* make sure reset */ IOSCB_IO_CALIB_DDR->SOFT_RESET_IOCALIB = 0x0U; /* make sure reset */ /* * R3.4 Wait for PVT calibration to complete * Check: * bit 2 sro_calib_status * * The G5 Memory controller needs to see that the IO calibration has * completed before kicking off DDR training. * It uses the calib_status signal as a flag for this. */ timer_out=0U; #ifndef RENODE_DEBUG { /* PVT I/O - sro_calib_status - wait for calibration to complete */ while((IOSCB_IO_CALIB_DDR->IOC_REG1 & 0x00000004U) == 0U) { timer_out++; } /* PVT I/O - sro_calib_status - wait for calibration to complete */ while((CFG_DDR_SGMII_PHY->IOC_REG1.IOC_REG1 & 0x00000004U) == 0U) { timer_out++; } } #endif /* * now assert calib lock * * */ { CFG_DDR_SGMII_PHY->IOC_REG0.IOC_REG0 &= ~(0x01U<<14U); IOSCB_IO_CALIB_DDR->IOC_REG0 &= ~(0x01U<<14U); CFG_DDR_SGMII_PHY->IOC_REG0.IOC_REG0 |= (0x01U<<14U); IOSCB_IO_CALIB_DDR->IOC_REG0 |= (0x01U<<14U); } } /** * */ void ddr_pvt_recalibration(void) { volatile uint32_t timer_out=0U; /* * now assert calib start * * */ { CFG_DDR_SGMII_PHY->IOC_REG0.IOC_REG0 &= ~(0x01U<<13U); IOSCB_IO_CALIB_DDR->IOC_REG0 &= ~(0x01U<<13U); CFG_DDR_SGMII_PHY->IOC_REG0.IOC_REG0 |= (0x01U<<13U); IOSCB_IO_CALIB_DDR->IOC_REG0 |= (0x01U<<13U); } /* * R3.4 Wait for PVT calibration to complete * Check: * bit 2 sro_calib_status * * The G5 Memory controller needs to see that the IO calibration has * completed before kicking off DDR training. * It uses the calib_status signal as a flag for this. */ timer_out=0U; #ifndef RENODE_DEBUG { /* PVT I/O - sro_calib_status - wait for calibration to complete */ while((IOSCB_IO_CALIB_DDR->IOC_REG1 & 0x00000004U) == 0U) { timer_out++; } /* PVT I/O - sro_calib_status - wait for calibration to complete */ while((CFG_DDR_SGMII_PHY->IOC_REG1.IOC_REG1 & 0x00000004U) == 0U) { timer_out++; } } #endif /* * now assert calib lock * * */ { #if 0 /* * fixme: this appears to cause wite calibration to fail, investigating */ CFG_DDR_SGMII_PHY->IOC_REG0.IOC_REG0 &= ~(0x01U<<14U); IOSCB_IO_CALIB_DDR->IOC_REG0 &= ~(0x01U<<14U); CFG_DDR_SGMII_PHY->IOC_REG0.IOC_REG0 |= (0x01U<<14U); IOSCB_IO_CALIB_DDR->IOC_REG0 |= (0x01U<<14U); #endif } } /** * Set eye thresholds * @param n_late_threshold * @param p_early_threshold */ static void set_early_late_thresholds(uint8_t n_late_threshold, uint8_t p_early_threshold) { uint32_t n_eye_values; uint32_t p_eye_value; /* * Set the N eye width value * bits 31:29 for CH1, bits 28:26 for CH0 in spare control (N eye width value) */ n_eye_values = (uint32_t)(n_late_threshold << SHIFT_TO_CH0_N_EYE_VALUE); n_eye_values |= (uint32_t)(n_late_threshold << SHIFT_TO_CH1_N_EYE_VALUE); CFG_DDR_SGMII_PHY->SPARE_CNTL.SPARE_CNTL = (LIBERO_SETTING_SPARE_CNTL & N_EYE_MASK) | n_eye_values; /* * Set P values */ p_eye_value = (uint32_t)(p_early_threshold << SHIFT_TO_REG_RX0_EYEWIDTH); CFG_DDR_SGMII_PHY->CH0_CNTL.CH0_CNTL = ((LIBERO_SETTING_CH0_CNTL & REG_RX0_EYEWIDTH_P_MASK) | p_eye_value) | REG_RX0_EN_FLAG_N; CFG_DDR_SGMII_PHY->CH1_CNTL.CH1_CNTL = ((LIBERO_SETTING_CH1_CNTL & REG_RX0_EYEWIDTH_P_MASK) | p_eye_value) | REG_RX1_EN_FLAG_N; } #endif mss_sgmii.h000066400000000000000000000223471432224323300370160ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_sgmii.h * @author Microchip-FPGA Embedded Systems Solutions * @brief SGMII defines * */ #ifndef SRC_PLATFORM_MPFS_HAL_NWC_MSS_SGMII_H_ #define SRC_PLATFORM_MPFS_HAL_NWC_MSS_SGMII_H_ #ifdef __cplusplus extern "C" { #endif #define REG_RX0_EN_OFFSET (1U<<5U) #define REG_RX1_EN_OFFSET (1U<<7U) #define TX_RX_CH_EN_MASK 0xFU #define TX_RX_CH_EN_OFFSET 0x4U #define REG_CDR_MOVE_STEP (1U<<22U) /* delay taps 1 => 3 taps moved, 0 => 2 taps move. */ /* 2 taps best for small PPM values, best results observed. */ #define SHIFT_TO_CH0_N_EYE_VALUE 26U /* 26-28 */ #define SHIFT_TO_CH1_N_EYE_VALUE 29U /* 29-31 */ #define N_EYE_MASK 0x03FFFFFFUL #define SHIFT_TO_REG_RX0_EYEWIDTH 21U #define REG_RX0_EYEWIDTH_P_MASK (~(0x7U<TEMP0 = (uint32_t)x) #define SIM_FEEDBACK1(x) (SYSREG->TEMP1 = (uint32_t)x) #else #define SIM_FEEDBACK0(x) #define SIM_FEEDBACK1(x) #endif #endif /* MSS_DDR_SGMII_SIMULATION_H_ */ mpfs_hal_version.h000066400000000000000000000032761432224323300363030ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal#ifndef MPFS_HAL_VERSION_H #define MPFS_HAL_VERSION_H /******************************************************************************* * Copyright 2019-2022 Microchip Corporation. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * */ /******************************************************************************* * @file mpfs_hal_version.h * @author Microchip-FPGA Embedded Systems Solutions * @brief PolareFire SoC Hardware Abstraction layer - MPFS HAL version. * */ #ifdef __cplusplus extern "C" { #endif #define MPFS_HAL_VERSION_MAJOR 2 #define MPFS_HAL_VERSION_MINOR 0 #define MPFS_HAL_VERSION_PATCH 101 #ifdef __cplusplus } #endif #endif mss_hal.h000066400000000000000000000043721432224323300343710ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file mss_hal.h * @author Microchip-FPGA Embedded Systems Solutions * @brief MPFS HAL include file. This is the file intended for application to * include so that all the other MPFS files are then accessible to it. * */ #ifndef MSS_HAL_H #define MSS_HAL_H #ifndef CONFIG_OPENSBI # include // for size_t # include // for bool, true, false # include #ifndef ssize_t typedef long ssize_t; #endif #endif #include "common/mss_assert.h" #include "common/mss_legacy_defines.h" #include "common/nwc/mss_ddr_defs.h" #include "common/nwc/mss_ddr_sgmii_regs.h" #include "common/nwc/mss_io_config.h" #include "common/nwc/mss_pll.h" #include "common/nwc/mss_scb_nwc_regs.h" #include "common/nwc/mss_scb_nwc_regs.h" /* * mss_sw_config.h may be edited as required and should be located outside the * mpfs_hal folder */ #include "mpfs_hal_config/mss_sw_config.h" /* * The hw_platform.h is included here only. It must be included after * mss_sw_config.h. This allows defines in hw_platform.h be overload from * mss_sw_config.h if necessary. * */ #include "common/atomic.h" #include "common/bits.h" #include "common/encoding.h" #include "fpga_design_config/fpga_design_config.h" #include "common/nwc/mss_ddr.h" #include "common/mss_clint.h" #include "common/mss_h2f.h" #include "common/mss_hart_ints.h" #include "common/mss_mpu.h" #include "common/mss_pmp.h" #include "common/mss_plic.h" #include "common/mss_seg.h" #include "common/mss_sysreg.h" #include "common/mss_util.h" #include "common/mss_mtrap.h" #include "common/mss_l2_cache.h" #include "common/mss_axiswitch.h" #include "common/mss_peripherals.h" #include "common/nwc/mss_cfm.h" #include "common/nwc/mss_ddr.h" #include "common/nwc/mss_sgmii.h" #include "startup_gcc/system_startup.h" #include "common/nwc/mss_ddr_debug.h" #ifdef SIMULATION_TEST_FEEDBACK #include "nwc/simulation.h" #endif #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif /* MSS_HAL_H */ readme.md000066400000000000000000000140441432224323300343460ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal=============================================================================== # mpfs_hal =============================================================================== The PolarFire-SoC MSS HAL provides the initial boot code, interrupt handling, and hardware access methods for the MPFS MSS. The terms PolarFire-SoC HAL and MPFS HAL are used interchangeably but in the main the term PolarFire-SoC MSS HAL is preferred. The PolarFire-SoC MSS hal is a combination of C and assembly source code. The mpfs_hal folder is included in an PolarFire Embedded project under the platform directory. It contains : * Start-up code executing from reset * Interrupt handling support * Exception handling support * Memory protection configuration, PMP and MPU * DDR configuration * SGMII configuration * MSSIO setup ## Inputs to the mss_hal There are two configuration sources. 1. Libero design Libero input through header files located in the config/hardware under the platform directory. These files are generated using the PF SoC embedded software configuration generator. It takes an xml file generated in the Libero design flow and produces header files based on the xml content in a suitable form for consumption by the hal. 2. Software configuration Software configuration settings are located in the mpfs_hal_config folder. ### Example Project directory structure, showing where mpfs_hal folder sits. ~~~~ +---------+ | project | +----+----+ +---------+ +-----------+ +-----+| src |----->|application| +---------+ | +-----------+ | | +-----------+ +-->|boards | + +----+------+ | | +---------------+ | +---------+|icicle-kit-es | | +---+-----------+ | | | | +---------------+ | +->|platform_config| | | +---------------+ | | | | +---------------+ | |---------|drivers_config | | | +---------------+ | | | | +---------------+ | |---------|linker | | | +---------------+ | | | | +---------------+ | |---------|mpfs_hal_config| | | +---------------+ | | | | | | +---------------+ | +>|soc_config | | | +---+-----------+ | | | | | | +---------------+------------------------+ | | +->|multiple folders with fpga config for sw| | | +----------------------------------------+ | | | | | | | | +---------------+ | +>|soc_fpga_design| | +--+------------+ | | | | +---------------+ | +-->|libero_tcl | | | +---------------+ | | | +-----------+ | +---------------+ +--+|middleware + +-->|xml | | +-----------+ +---------------+ | + | +-----------+ +--+|platform | +----+------+ | +---------------+ +---------+|drivers | | +---------------+ | | +---------------+ +---------+|hal | | +---------------+ | | +---------------+ +---------+|mpfs_hal | | +---------------+ | | +-------------------------+ +---------+|platform_config_reference| | +-------------------------+ | | +---------------------+ +---------+|soc_config_generator | +---------------------+ ~~~~ Please see the user guide for further details on use. startup_gcc/000077500000000000000000000000001432224323300351025ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_halmss_entry.S000066400000000000000000000536521432224323300372640ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file entry.S * @author Microchip-FPGA Embedded Systems Solutions * @brief entry functions. * */ #include "../common/bits.h" #include "../common/encoding.h" #include "../common/mss_mtrap.h" #include "system_startup_defs.h" #include "mpfs_hal_config/mss_sw_config.h" .option norvc .section .text.init,"ax", %progbits .globl reset_vector .globl _start reset_vector: _start: #if (IMAGE_LOADED_BY_BOOTLOADER == 0) /* * clear the Return Address Stack */ call .clear_ras /* Setup trap handler */ la a4, trap_vector csrw mtvec, a4 # initalise machine trap vector address /* Make sure that mtvec is updated before continuing */ 1: csrr a5, mtvec bne a4, a5, 1b /* Disable and clear all interrupts */ li a2, MSTATUS_MIE csrc mstatus, a2 # clear interrupt enable bit csrw mie, zero csrw mip, zero # Init delegation registers, mideleg, medeleg, if a U54 # These are not initialised by the hardware and come up in a random state csrr a0, mhartid beqz a0, .skip_e51 csrw mideleg, 0 csrw medeleg, 0 .skip_e51: # mscratch must be init to zero- we are not using scratch memory csrw mscratch, zero csrw mcause, zero csrw mepc, zero /* * clear PMP enables */ csrw pmpcfg0, zero csrw pmpcfg2, zero /* * clear regs */ li x1, 0 li x2, 0 li x3, 0 li x4, 0 li x5, 0 li x6, 0 li x7, 0 li x8, 0 li x9, 0 li x10,0 li x11,0 li x12,0 li x13,0 li x14,0 li x15,0 li x16,0 li x17,0 li x18,0 li x19,0 li x20,0 li x21,0 li x22,0 li x23,0 li x24,0 li x25,0 li x26,0 li x27,0 li x28,0 li x29,0 li x30,0 li x31,0 # enable FPU and accelerator if present, setting ignored on E51 li t0, MSTATUS_FS | MSTATUS_XS csrs mstatus, t0 # Init floating point control register to zero # skip if e51 csrr a0, mhartid beqz a0, .no_float #ifdef __riscv_flen fscsr x0 #endif .no_float: # make sure XLEN agrees with compilation choice, if not will loop here .LxlenCheck: csrr t0, misa #if __riscv_xlen == 64 bltz t0, .LxlenPass #else bgez t0, .LxlenPass #endif j .LxlenCheck .LxlenPass: # initialize global pointer, global data # The __global_pointer is allocated in the linker script. It points to a # location 2k after sdata start as the offsets used in the gp are +/- 2k # See https://www.sifive.com/blog/2017/08/28/all-aboard-part-3-linker-relaxation-in-riscv-toolchain/ # see: http://www.rowleydownload.co.uk/arm/documentation/gnu/as/RISC_002dV_002dDirectives.html .option push .option norelax la gp, __global_pointer$ .option pop # get core id csrr a0, mhartid li a1, 0 beq a0, a1, .hart0 li a1, 1 beq a0, a1, .hart1 li a1, 2 beq a0, a1, .hart2 li a1, 3 beq a0, a1, .hart3 li a1, 4 beq a0, a1, .hart4 .hart0: la a4, __stack_bottom_h0$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h0$ j .continue .hart1: la a4, __stack_bottom_h1$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h1$ j .continue .hart2: la a4, __stack_bottom_h2$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h2$ j .continue .hart3: la a4, __stack_bottom_h3$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h3$ j .continue .hart4: la a4, __stack_bottom_h4$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h4$ .continue: # clear HLS and stack mv a5, sp .init_stack: #csrw mepc, zero STORE x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, .init_stack # Allocate some space at top of stack for the HLS addi sp, sp, -HLS_DEBUG_AREA_SIZE # HLS grows up from new top of stack mv tp, sp # get core id csrr a0, mhartid li a1, MPFS_HAL_FIRST_HART bne a0, a1, .LOtherHartstoWFI # clear the common heap la a4, __heap_start la a5, __heap_end .init_heap: #csrw mepc, zero STORE x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, .init_heap # # clear DTIM - this is required to stop memory errors on initial access by # cache # Also, stops x propagation in simulation, when cache/stack reads unused # area # li a2, MPFS_HAL_CLEAR_MEMORY beq x0, a2, .skip_mem_clear call .clear_dtim call .clear_l2lim .skip_mem_clear: /* * Clear bus error unit accrued register on start-up * This is cleared by the first hart only */ la a4,0x01700020UL sb x0, 0(a4) la a4,0x01701020UL sb x0, 0(a4) la a4,0x01702020UL sb x0, 0(a4) la a4,0x01703020UL sb x0, 0(a4) la a4,0x01704020UL sb x0, 0(a4) # now core MPFS_HAL_FIRST_HART jumps to main_first_hart .main_hart: # pass HLS address mv a0, tp j main_first_hart .LoopForeverMain: #in case of return, loop forever. nop's added so can be seen in debugger nop nop j .LoopForeverMain .LOtherHartstoWFI: li a2, MSTATUS_MIE csrc mstatus, a2 # clear interrupt enable bit csrw mie, zero csrw mip, zero li a2, MIP_MSIP csrw mie, a2 # Set MSIE bit to receive IPI. This needs to be # enabled- otherwise stays in wfi. # Other interrupts appera to bring out of wfi,even if # not enabled. # # Wait here until main hart is up and running # li a3, HLS_MAIN_HART_STARTED la a1, (__stack_top_h0$ - HLS_DEBUG_AREA_SIZE) .wait_main_hart: LWU a2, 0(a1) bne a3, a2, .wait_main_hart # Flag we are here to the main hart li a1, HLS_OTHER_HART_IN_WFI sw a1, 0(tp) /* flush the instruction cache */ fence.i .LwaitOtherHart: # We assume wfi instruction will be run before main hart attampts to take # out of wfi wfi # Only start if MIP_MSIP is set - the wfi will ensure this, but adding # breakpoints in the debugger (halt) # will wakeup wfi, so the following code will make sure we remain here until # we get a software interrupt csrr a2, mip andi a2, a2, MIP_MSIP beqz a2, .LwaitOtherHart /* Disable and clear all interrupts- should be only a sw interrupt */ li a2, MSTATUS_MIE csrc mstatus, a2 # clear interrupt enable bit csrw mie, zero csrw mip, zero # set marker as to where we are li a1, HLS_OTHER_HART_PASSED_WFI sw a1, 0(tp) # pass HLS address mv a0, tp j main_other_hart .LoopForeverOther: #in case of return, loop forever. nop's added so can be seen in debugger nop nop j .LoopForeverOther #else /* IMAGE_LOADED_BY_BOOTLOADER == 1 */ /******************************************************************************* *The program has been loaded by a bootloader * a0 - contains the hart ID * a1 - contains pointer to bootloader -Hart Local Storage, for this hart. */ _start_non_bootloader_amp_image: /* Setup trap handler */ la a4, trap_vector csrw mtvec, a4 # initalise machine trap vector address /* Make sure that mtvec is updated before continuing */ 1: csrr a5, mtvec bne a4, a5, 1b /* assume ints in init state */ /* assume PMP's set as required */ # enable FPU and accelerator if present, setting ignored on E51 li t0, MSTATUS_FS | MSTATUS_XS csrs mstatus, t0 # Init floating point control register to zero # skip if e51 csrr a0, mhartid beqz a0, .no_float #ifdef __riscv_flen fscsr x0 #endif .no_float: # make sure XLEN agrees with compilation choice, if not will loop here .LxlenCheck: csrr t0, misa #if __riscv_xlen == 64 bltz t0, .LxlenPass #else bgez t0, .LxlenPass #endif j .LxlenCheck .LxlenPass: # initialize global pointer, global data # The __global_pointer is allocated in the linker script. It points to a # location 2k after sdata start as the offsets used in the gp are +/- 2k # See https://www.sifive.com/blog/2017/08/28/all-aboard-part-3-linker-relaxation-in-riscv-toolchain/ # see: http://www.rowleydownload.co.uk/arm/documentation/gnu/as/RISC_002dV_002dDirectives.html .option push .option norelax la gp, __global_pointer$ .option pop # get core id csrr a0, mhartid li a1, 0 beq a0, a1, .hart0 li a1, 1 beq a0, a1, .hart1 li a1, 2 beq a0, a1, .hart2 li a1, 3 beq a0, a1, .hart3 li a1, 4 beq a0, a1, .hart4 .hart0: la a4, __stack_bottom_h0$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h0$ j .continue .hart1: la a4, __stack_bottom_h1$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h1$ j .continue .hart2: la a4, __stack_bottom_h2$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h2$ j .continue .hart3: la a4, __stack_bottom_h3$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h3$ j .continue .hart4: la a4, __stack_bottom_h4$ # keep bottom of stack in a5 so we can init later la sp, __stack_top_h4$ .continue: # clear HLS and stack mv a5, sp .init_stack: #csrw mepc, zero STORE x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, .init_stack # Allocate some space at top of stack for the HLS addi sp, sp, -HLS_DEBUG_AREA_SIZE # HLS grows up from new top of stack mv tp, sp # get core id csrr a0, mhartid li a1, MPFS_HAL_FIRST_HART bne a0, a1, .LOtherHartstoWFI # clear the common heap la a4, __heap_start la a5, __heap_end .init_heap: #csrw mepc, zero STORE x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, .init_heap # now core MPFS_HAL_FIRST_HART jumps to main_first_hart .main_hart: # pass HLS address mv a0, tp j main_first_hart_app .LoopForeverMain: #in case of return, loop forever. nop's added so can be seen in debugger nop nop j .LoopForeverMain .LOtherHartstoWFI: li a2, MSTATUS_MIE csrc mstatus, a2 # clear interrupt enable bit csrw mie, zero csrw mip, zero li a2, MIP_MSIP csrw mie, a2 # Set MSIE bit to receive IPI. This needs to be # enabled- otherwise stays in wfi. # Other interrupts appera to bring out of wfi,even if # not enabled. # # Wait here until main hart is up and running # # get core id la a2, MPFS_HAL_FIRST_HART li a3, 0 beq a3, a2, .main_hart0 li a3, 1 beq a3, a2, .main_hart1 li a3, 2 beq a3, a2, .main_hart2 li a3, 3 beq a3, a2, .main_hart3 li a3, 4 beq a3, a2, .main_hart4 .main_hart0: la a4, (__stack_top_h0$ - HLS_DEBUG_AREA_SIZE) j 1f .main_hart1: la a4, (__stack_top_h1$ - HLS_DEBUG_AREA_SIZE) j 1f .main_hart2: la a4, (__stack_top_h2$ - HLS_DEBUG_AREA_SIZE) j 1f .main_hart3: la a4, (__stack_top_h3$ - HLS_DEBUG_AREA_SIZE) j 1f .main_hart4: la a4, (__stack_top_h4$ - HLS_DEBUG_AREA_SIZE) 1: li a3, HLS_MAIN_HART_STARTED .wait_main_hart: LWU a2, 0(a4) bne a3, a2, .wait_main_hart # Flag we are here to the main hart li a1, HLS_OTHER_HART_IN_WFI sw a1, 0(tp) /* flush the instruction cache */ fence.i .LwaitOtherHart: # We assume wfi instruction will be run before main hart attampts to take # out of wfi wfi # Only start if MIP_MSIP is set - the wfi will ensure this, but adding # breakpoints in the debugger (halt) # will wakeup wfi, so the following code will make sure we remain here until # we get a software interrupt csrr a2, mip andi a2, a2, MIP_MSIP beqz a2, .LwaitOtherHart /* Disable and clear all interrupts- should be only a sw interrupt */ li a2, MSTATUS_MIE csrc mstatus, a2 # clear interrupt enable bit csrw mie, zero csrw mip, zero # set marker as to where we are li a1, HLS_OTHER_HART_PASSED_WFI sw a1, 0(tp) # pass HLS address mv a0, tp j main_other_hart .LoopForeverOther: #in case of return, loop forever. nop's added so can be seen in debugger nop nop j .LoopForeverOther #endif /* IMAGE_LOADED_BY_BOOTLOADER == 0 */ /******************************************************************************/ /******************************interrupt handeling below here******************/ /******************************************************************************/ trap_vector: #if defined USING_FREERTOS addi sp, sp, -REGBYTES /* Save t0 for now */ STORE t0, 0x0(sp) csrr t0, mcause bge t0,x0,.Le51_other /* Not an interrupt... */ slli t0,t0,1 srli t0,t0,1 addi t0,t0,-7 bne t0,x0,.Le51_other /* Not Timer interrupt... */ /* Interrupt is timer interrupt so let FreeRTOS handle it */ LOAD t0, 0x0(sp) # Restore t0 for proper context save by FreeRTOS addi sp, sp, REGBYTES j TIMER_CMP_INT mret .Le51_other: # Re-enter mainline here if not timer interrupt LOAD t0, 0x0(sp) # Restore t0 for proper context save by HAL addi sp, sp, REGBYTES #endif # The mscratch register is an XLEN-bit read/write register dedicated for use by machine mode. # Typically, it is used to hold a pointer to a machine-mode hart-local context space and swapped # with a user register upon entry to an M-mode trap handler. # In this implementation, we are noty using HLS # csrrw sp, mscratch, sp #copy sp to mscratch, and mscrath to sp addi sp, sp, -INTEGER_CONTEXT_SIZE # moves sp down stack to make I # INTEGER_CONTEXT_SIZE area # Preserve the registers. STORE sp, 2*REGBYTES(sp) # sp STORE a0, 10*REGBYTES(sp) # save a0,a1 in the created CONTEXT STORE a1, 11*REGBYTES(sp) STORE ra, 1*REGBYTES(sp) STORE gp, 3*REGBYTES(sp) STORE tp, 4*REGBYTES(sp) STORE t0, 5*REGBYTES(sp) STORE t1, 6*REGBYTES(sp) STORE t2, 7*REGBYTES(sp) STORE s0, 8*REGBYTES(sp) STORE s1, 9*REGBYTES(sp) STORE a2,12*REGBYTES(sp) STORE a3,13*REGBYTES(sp) STORE a4,14*REGBYTES(sp) STORE a5,15*REGBYTES(sp) STORE a6,16*REGBYTES(sp) STORE a7,17*REGBYTES(sp) STORE s2,18*REGBYTES(sp) STORE s3,19*REGBYTES(sp) STORE s4,20*REGBYTES(sp) STORE s5,21*REGBYTES(sp) STORE s6,22*REGBYTES(sp) STORE s7,23*REGBYTES(sp) STORE s8,24*REGBYTES(sp) STORE s9,25*REGBYTES(sp) STORE s10,26*REGBYTES(sp) STORE s11,27*REGBYTES(sp) STORE t3,28*REGBYTES(sp) STORE t4,29*REGBYTES(sp) STORE t5,30*REGBYTES(sp) STORE t6,31*REGBYTES(sp) # Invoke the handler. mv a0, sp # a0 <- regs # Please note: mtval is the newer name for register mbadaddr # If you get a compile failure here, use the newer name # At this point (2019), both are supported in latest compiler # older compiler versions only support mbadaddr, so going with this. # See: https://github.com/riscv/riscv-gcc/issues/133 csrr a1, mbadaddr # useful for anaysis when things go wrong csrr a2, mepc jal trap_from_machine_mode restore_regs: # Restore all of the registers. LOAD ra, 1*REGBYTES(sp) LOAD gp, 3*REGBYTES(sp) LOAD tp, 4*REGBYTES(sp) LOAD t0, 5*REGBYTES(sp) LOAD t1, 6*REGBYTES(sp) LOAD t2, 7*REGBYTES(sp) LOAD s0, 8*REGBYTES(sp) LOAD s1, 9*REGBYTES(sp) LOAD a0,10*REGBYTES(sp) LOAD a1,11*REGBYTES(sp) LOAD a2,12*REGBYTES(sp) LOAD a3,13*REGBYTES(sp) LOAD a4,14*REGBYTES(sp) LOAD a5,15*REGBYTES(sp) LOAD a6,16*REGBYTES(sp) LOAD a7,17*REGBYTES(sp) LOAD s2,18*REGBYTES(sp) LOAD s3,19*REGBYTES(sp) LOAD s4,20*REGBYTES(sp) LOAD s5,21*REGBYTES(sp) LOAD s6,22*REGBYTES(sp) LOAD s7,23*REGBYTES(sp) LOAD s8,24*REGBYTES(sp) LOAD s9,25*REGBYTES(sp) LOAD s10,26*REGBYTES(sp) LOAD s11,27*REGBYTES(sp) LOAD t3,28*REGBYTES(sp) LOAD t4,29*REGBYTES(sp) LOAD t5,30*REGBYTES(sp) LOAD t6,31*REGBYTES(sp) LOAD sp, 2*REGBYTES(sp) addi sp, sp, +INTEGER_CONTEXT_SIZE # moves sp up stack to reclaim # INTEGER_CONTEXT_SIZE area mret /*****************************************************************************/ /******************************interrupt handeling above here*****************/ /*****************************************************************************/ .enable_sw_int: li a2, MIP_MSIP csrw mie, a2 # Set MSIE bit to receive IPI li a2, MSTATUS_MIE csrs mstatus, a2 # enable interrupts /* flush the instruction cache */ fence.i ret /*********************************************************************************** * * The following init_memory() symbol overrides the weak symbol in the HAL and does * a safe copy of RW data and clears zero-init memory * */ // zero_section helper function: // a0 = exec_start_addr // a1 = exec_end_addr // .globl zero_section .type zero_section, @function zero_section: bge a0, a1, .zero_section_done sd zero, (a0) addi a0, a0, 8 j zero_section .zero_section_done: ret // zero_section helper function: // a0 = exec_start_addr // a1 = exec_end_addr // a2 = start count // .globl count_section .type count_section, @function count_section: beq a0, a1, .count_section_done sd a2, (a0) addi a0, a0, 8 addi a2, a2, 8 j count_section .count_section_done: ret // copy_section helper function: // a0 = load_addr // a1 = exec_start_addr // a2 = exec_end_addr .globl copy_section .type copy_section, @function copy_section: beq a1, a0, .copy_section_done // if load_addr == exec_start_addr, goto copy_section_done .check_if_copy_section_done: beq a1, a2, .copy_section_done // if offset != length, goto keep_copying .keep_copying: ld a3, 0(a0) // val = *load_addr sd a3, 0(a1) // *exec_start_addr = val; addi a0, a0, 8 // load_addr = load_addr + 8 addi a1, a1, 8 // exec_start_addr = exec_start_addr + 8 j .check_if_copy_section_done .copy_section_done: ret /******************************************************************************* * * The following copy_switch_code() symbol overrides the weak symbol in the HAL and does * a safe copy of HW config data */ .globl copy_switch_code .type copy_switch_code, @function copy_switch_code: la a5, __sc_start // a5 = __sc_start la a4, __sc_load // a4 = __sc_load beq a5,a4,.copy_switch_code_done // if a5 == a4, goto copy_switch_code_done la a3, __sc_end // a3 = __sc_end beq a5,a3,.copy_switch_code_done // if a5 == a3, goto copy_switch_code_done .copy_switch_code_loop: lw a2,0(a4) // a2 = *a4 sw a2,0(a5) // *a5 = a2 addi a5,a5,4 // a5+=4 addi a4,a4,4 // a4+=4 bltu a5,a3,.copy_switch_code_loop // if a5 < a3, goto copy_switch_code_loop .copy_switch_code_done: ret /******************************************************************************* * */ #define START__OF_LIM 0x08000000 #define END__OF_LIM 0x08200000 #define START__OF_DTM 0x01000000 #define END__OF_DTM 0x01002000 .clear_l2lim: // Clear the LIM // // On reset, the first 15 ways are L2 and the last way is cache // We can initialize all, as cache write through to DDR is blocked // until DDR in initialized, so will have no effect other than clear ECC // // NOTE: we need to check if we are debugging from LIM,if so do not // initialize. // la a2, _start la a4, 0x08000000 # start of LIM address and a2, a2, a4 bnez a2, .done_clear la a5, 0x08200000 # end of LIM address j 1f .clear_dtim: // // Clear the E51 DTIM to prevent any ECC memory errors on initial access // la a4, 0x01000000 # DTIM start la a5, 0x01002000 # DTIM end 1: // common loop used by both .clear_l2lim and .clear_dtim sd x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, 1b .done_clear: ret /* * record_ecc_error_counts on reset * These are non-zero in the coreplex. * Can be checked later on to see if values have changed * a0 = mECCDataFailCount save address a1 = mECCDataCorrectionCount save address a2 = mECCDirFixCount save address */ .record_ecc_error_counts: # Store initial ECC errors #define mECCDataFailCount 0x02010168U la a5, mECCDataFailCount mv a4, a0// eg. Use stat of DTIM in not used for anything else 0x01000100 lw t2,0(a5) sw t2,0(a4) #define mECCDataCorrectionCount 0x02010148U la a5, mECCDataCorrectionCount mv a4, a1// eg. Use stat of DTIM in not used for anything else 0x01000110 lw t2,0(a5) sw t2,0(a4) #define mECCDirFixCount 0x02010108u la a5, mECCDirFixCount mv a4, a2// eg. Use stat of DTIM in not used for anything else 0x01000120 lw t2,0(a5) sw t2,0(a4) ret /* * clear_ras , clear_ras_2_deep * Two deep function calls. * Used to clear the interal processor Return Address Stack * This is belt and braces, may not be required */ .clear_ras: mv a5, x1 nop call .clear_ras_2_deep nop nop nop nop nop nop mv x1, a5 ret .clear_ras_2_deep: nop nop nop nop nop nop ret mss_utils.S000066400000000000000000000106071432224323300372540ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*************************************************************************** * @file mss_utils.S * @author Microchip-FPGA Embedded Systems Solutions * @brief utilities used by mpfs-hal startup code * */ .section .text.init,"ax", %progbits .align 3 /*********************************************************************************** * * pdma_transfer * Only used by the mpfs hal. App code uses the provided driver. * * a0 = dest * a1 = src * a2 = length * a3 = PDMA Base Address - 0x3000000 + (0x01000 * PDMA_CHANNEL) */ .globl pdma_transfer .type pdma_transfer, @function pdma_transfer: mv t1,a0 mv t0, a3 // Base address li t1, 1 sw t1, 0(t0) // claim li t1, 0 sw t1, 4(t0) // read[31:28]/write[27:24] size 0=>1byte, 1 =>2 bytes etx mv t1, a2 // SIZE sd t1, 8(t0) // bytes mv t1, a0 // dest address sd t1, 16(t0) // dest mv t1, a1 // source address sd t1, 24(t0) // src li t1, 0xff000000 sw t1, 4(t0) // full speed copy li t1, 3 sw t1, 0(t0) // start transfer fence ret /*********************************************************************************** * * pdma_transfer_complete * Loops until transfer complete * Only used by the mpfs hal. App code uses the provided driver. * * a0 = PDMA Base Address - 0x3000000 + (0x01000 * PDMA_CHANNEL) */ // .globl pdma_transfer_complete .type pdma_transfer_complete, @function pdma_transfer_complete: mv t0, a0 // Base address 1: // wait for completion lw t1, 0(t0) andi t1, t1, 2 bnez t1, 1b // release DMA sw zero, 0(t0) ret /*********************************************************************************** * * memfill() - fills memory, alternate to lib function when not available */ // memfill helper function: // a0 = dest // a1 = value to fill // a2 = length .globl memfill .type memfill, @function memfill: mv t1,a0 mv t2,a1 beqz a2,2f 1: sb t2,0(t1) addi a2,a2,-1 addi t1,t1,1 bnez a2,1b 2: ret /*********************************************************************************** * * The following config_copy() symbol overrides the weak symbol in the HAL and does * a safe copy of HW config data */ // config_copy helper function: // a0 = dest // a1 = src // a2 = length .globl config_copy .type config_copy, @function config_copy: mv t1,a0 beqz a2,2f 1: lb t2,0(a1) sb t2,0(t1) addi a2,a2,-1 addi t1,t1,1 addi a1,a1,1 bnez a2,1b 2: ret /*********************************************************************************** * * config_16_copy () Copies a word at a time, used when copying to contigous registers */ // config_16_copy helper function: // a0 = dest // a1 = src // a2 = length .globl config_16_copy .type config_16_copy, @function config_16_copy: mv t1,a0 beqz a2,2f 1: lh t2,0(a1) sh t2,0(t1) addi a2,a2,-2 addi t1,t1,2 addi a1,a1,2 bnez a2,1b 2: ret /*********************************************************************************** * * config_32_copy () Copies a word at a time, used when copying to contigous registers */ // config_copy helper function: // a0 = dest // a1 = src // a2 = length .globl config_32_copy .type config_32_copy, @function config_32_copy: mv t1,a0 beqz a2,2f 1: lw t2,0(a1) sw t2,0(t1) addi a2,a2,-4 addi t1,t1,4 addi a1,a1,4 bnez a2,1b 2: ret /*********************************************************************************** * * config_64_copy - copying using 64 bit loads, addresses must be on 64 bit boundary */ // config_64_copy helper function: // a0 = dest // a1 = src // a2 = length .globl config_64_copy .type config_64_copy, @function config_64_copy: mv t1,a0 beqz a2,2f 1: ld t2,0(a1) sd t2,0(t1) addi a2,a2,-8 addi t1,t1,8 addi a1,a1,8 bnez a2,1b 2: ret newlib_stubs.c000066400000000000000000000246351432224323300377600ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * @file newlib_stubs.c * @author Microchip-FPGA Embedded Systems Solutions * @brief Stubs for Newlib system calls. * */ #include #include #include #include #include #include "../mss_hal.h" /*============================================================================== * Redirection of standard output to an MSS UART. *------------------------------------------------------------------------------ * A default implementation for the redirection of the output of printf() to a * UART is provided at the bottom of this file. This redirection is enabled by * adding one of the following defines to your project in the project file * boards/your-board/mpfs_hal_config/mss_sw_config.h * * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart0_lo * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart1_lo * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart2_lo * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart3_lo * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart4_lo * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart0_hi * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart1_hi * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart2_hi * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart3_hi * #define MICROCHIP_STDIO_THRU_MMUARTX &g_mss_uart4_hi * The baud rate using the MICROCHIP_STDIO_BAUD_RATE define. * * Note: you must have mss_mmuart driver source code included in the project. * * Also note defaults to 115200 baud if no baud rate is specified using the * MICROCHIP_STDIO_BAUD_RATE #define. */ #ifdef MICROCHIP_STDIO_THRU_MMUARTX #include "drivers/mss/mss_mmuart/mss_uart.h" #ifndef MICROCHIP_STDIO_BAUD_RATE #define MICROCHIP_STDIO_BAUD_RATE MSS_UART_115200_BAUD #endif static mss_uart_instance_t * const gp_my_uart = MICROCHIP_STDIO_THRU_MMUARTX; /*------------------------------------------------------------------------------ * Global flag used to indicate if the UART driver needs to be initialized. */ static int g_stdio_uart_init_done = 0; #endif /* MICROCHIP_STDIO_THRU_MMUARTX */ /*============================================================================== * Environment variables. * A pointer to a list of environment variables and their values. For a minimal * environment, this empty list is adequate: */ char *__env[1] = { 0 }; char **environ = __env; /*============================================================================== * Close a file. */ int _close(int file); int _close(int file) { (void)file; return -1; } /*============================================================================== * Transfer control to a new process. */ int _execve(char *name, char **argv, char **env); int _execve(char *name, char **argv, char **env) { (void)name; (void)argv; (void)env; errno = ENOMEM; return -1; } /*============================================================================== * Exit a program without cleaning up files. */ void _exit( int code ) { (void)code; /* Should we force a system reset? */ while( 1 ) { ; } } /*============================================================================== * Create a new process. */ int _fork(void); int _fork(void) { errno = EAGAIN; return -1; } /*============================================================================== * Status of an open file. */ int _fstat(int file, struct stat *st); int _fstat(int file, struct stat *st) { (void)file; st->st_mode = S_IFCHR; return (0); } /*============================================================================== * Process-ID */ int _getpid(void); int _getpid(void) { return (1); } /*============================================================================== * Query whether output stream is a terminal. */ int _isatty(int file); int _isatty(int file) { (void)file; return (1); } /*============================================================================== * Send a signal. */ int _kill(int pid, int sig); int _kill(int pid, int sig) { (void)pid; (void)sig; errno = EINVAL; return (-1); } /*============================================================================== * Establish a new name for an existing file. */ int _link(char *old, char *new); int _link(char *old, char *new) { (void)old; (void)new; errno = EMLINK; return (-1); } /*============================================================================== * Set position in a file. */ int _lseek(int file, int ptr, int dir); int _lseek(int file, int ptr, int dir) { (void)file; (void)ptr; (void)dir; return (0); } /*============================================================================== * Open a file. */ int _open(const char *name, int flags, int mode); int _open(const char *name, int flags, int mode) { (void)name; (void)flags; (void)mode; return (-1); } /*============================================================================== * Read from a file. */ int _read(int file, char *ptr, int len); int _read(int file, char *ptr, int len) { (void)file; (void)ptr; (void)len; return (0); } /*============================================================================== * Write to a file. libc subroutines will use this system routine for output to * all files, including stdout so if you need to generate any output, for * example to a serial port for debugging, you should make your minimal write * capable of doing this. */ int _write_r( void * reent, int file, char * ptr, int len ); int _write_r( void * reent, int file, char * ptr, int len ) { (void)reent; (void)file; (void)ptr; (void)len; #ifdef MICROCHIP_STDIO_THRU_MMUARTX /*-------------------------------------------------------------------------- * Initialize the UART driver if it is the first time this function is * called. */ if(!g_stdio_uart_init_done) { MSS_UART_init(gp_my_uart, MICROCHIP_STDIO_BAUD_RATE, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY); g_stdio_uart_init_done = 1; } /*-------------------------------------------------------------------------- * Output text to the UART. */ MSS_UART_polled_tx(gp_my_uart, (uint8_t *)ptr, len); return len; #else /* MICROCHIP_STDIO_THRU_MMUARTX */ return (0); #endif /* MICROCHIP_STDIO_THRU_MMUARTX */ } /*============================================================================== * Increase program data space. As malloc and related functions depend on this, * it is useful to have a working implementation. The following suffices for a * standalone system; it exploits the symbol _end automatically defined by the * GNU linker. */ caddr_t _sbrk(int incr); caddr_t _sbrk(int incr) { extern char _end; /* Defined by the linker */ extern char __heap_start; extern char __heap_end; static char *heap_end; char *prev_heap_end; (void)__heap_start; (void)__heap_end; #ifdef DEBUG_HEAP_SIZE char * stack_ptr = NULL; #endif /* * Did we allocated memory for the heap in the linker script? * You need to set HEAP_SIZE to a non-zero value in your linker script if * the following assertion fires. */ ASSERT(&__heap_end > &__heap_start); if (heap_end == NULL) { heap_end = &_end; } prev_heap_end = heap_end; #ifdef DEBUG_HEAP_SIZE /* add this define if you want to debug crash due to overflow of heap */ /* fixme- this test needs to be reworked to take account of multiple harts and TLS */ stack_ptr = read_csr(sp); /* stack_ptr has just been placed on the stack, so its address in currently pointing to the stack end */ if(heap_end < stack_ptr) { /* * Heap is at an address below the stack, growing up toward the stack. * The stack is above the heap, growing down towards the heap. * Make sure the stack and heap do not run into each other. */ if (heap_end + incr > stack_ptr) { _write_r ((void *)0, 1, "Heap and stack collision\n", 25); _exit (1); } } else { /* * If the heap and stack are not growing towards each other then use the * _eheap linker script symbol to figure out if there is room left on * the heap. * Please note that this use case makes sense when the stack is located * in internal eSRAM in the 0x20000000 address range and the heap is * located in the external memory in the 0xA0000000 memory range. * Please note that external memory should not be accessed using the * 0x00000000 memory range to read/write variables/data because of the * SmartFusion2 cache design. */ extern char _heap_end; /* Defined by the linker */ char *top_of_heap; top_of_heap = &_heap_end; if(heap_end + incr > top_of_heap) { _write_r ((void *)0, 1, "Out of heap memory\n", 25); _exit (1); } } #endif heap_end += incr; /* * Did we run out of heap? * You need to increase the heap size in the linker script if the following * assertion fires. * */ ASSERT(heap_end <= &__heap_end); return ((caddr_t) prev_heap_end); } /*============================================================================== * Status of a file (by name). */ int _stat(char *file, struct stat *st); int _stat(char *file, struct stat *st) { (void)file; st->st_mode = S_IFCHR; return 0; } /*============================================================================== * Timing information for current process. */ int _times(struct tms *buf); int _times(struct tms *buf) { (void)buf; return (-1); } /*============================================================================== * Remove a file's directory entry. */ int _unlink(char *name); int _unlink(char *name) { (void)name; errno = ENOENT; return (-1); } /*============================================================================== * Wait for a child process. */ int _wait(int *status); int _wait(int *status) { (void)status; errno = ECHILD; return (-1); } system_startup.c000066400000000000000000000535221432224323300403630ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/****************************************************************************************** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /*************************************************************************** * @file system_startup.c * @author Microchip-FPGA Embedded Systems Solutions * @brief first C code called on startup. Will call user code created outside * the HAL. */ #include #include #include "mpfs_hal/mss_hal.h" #ifdef MPFS_HAL_HW_CONFIG #include "../common/nwc/mss_nwc_init.h" #endif #include "system_startup_defs.h" /*============================================================================== * This function is called by the lowest enabled hart (MPFS_HAL_FIRST_HART) in * the configuration file : * (src/boards/my_hart_id = MPFS_HAL_FIRST_HART; #endif #ifdef MPFS_HAL_HW_CONFIG load_virtual_rom(); (void)init_bus_error_unit(); (void)init_mem_protection_unit(); (void)init_pmp((uint8_t)MPFS_HAL_FIRST_HART); (void)mss_set_apb_bus_cr((uint32_t)LIBERO_SETTING_APBBUS_CR); (void)mss_set_gpio_interrupt_fab_cr((uint32_t)LIBERO_SETTING_GPIO_INTERRUPT_FAB_CR); #endif /* MPFS_HAL_HW_CONFIG */ /* * Initialise NWC * Clocks * SGMII * DDR * IOMUX */ #ifdef MPFS_HAL_HW_CONFIG (void)mss_nwc_init(); (void)mss_nwc_init_ddr(); /* main hart init's the PLIC */ PLIC_init_on_reset(); /* * Start the other harts. They are put in wfi in entry.S * When debugging, harts are released from reset separately, * so we need to make sure hart is in wfi before we try and release. */ stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h0$); hls = (HLS_DATA*)(stack_top - HLS_DEBUG_AREA_SIZE); hls->in_wfi_indicator = HLS_MAIN_HART_STARTED; hls->my_hart_id = MPFS_HAL_FIRST_HART; WFI_SM sm_check_thread = INIT_THREAD_PR; hart_id = MPFS_HAL_FIRST_HART + 1U; while( hart_id <= MPFS_HAL_LAST_HART) { uint32_t wait_count = 0U; switch(sm_check_thread) { default: case INIT_THREAD_PR: switch (hart_id) { case 1: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h1$); break; case 2: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h2$); break; case 3: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h3$); break; case 4: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h4$); break; } hls = (HLS_DATA*)(stack_top - HLS_DEBUG_AREA_SIZE); sm_check_thread = CHECK_WFI; wait_count = 0U; break; case CHECK_WFI: if( hls->in_wfi_indicator == HLS_OTHER_HART_IN_WFI ) { /* Separate state- to add a little delay */ sm_check_thread = SEND_WFI; } break; case SEND_WFI: hls->my_hart_id = hart_id; /* record hartid locally */ raise_soft_interrupt(hart_id); sm_check_thread = CHECK_WAKE; wait_count = 0UL; break; case CHECK_WAKE: if( hls->in_wfi_indicator == HLS_OTHER_HART_PASSED_WFI ) { sm_check_thread = INIT_THREAD_PR; hart_id++; wait_count = 0UL; } else { wait_count++; if(wait_count > 0x10U) { if( hls->in_wfi_indicator == HLS_OTHER_HART_IN_WFI ) { hls->my_hart_id = hart_id; /* record hartid locally */ raise_soft_interrupt(hart_id); wait_count = 0UL; } } } break; } } stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h0$); hls = (HLS_DATA*)(stack_top - HLS_DEBUG_AREA_SIZE); hls->in_wfi_indicator = HLS_MAIN_HART_FIN_INIT; /* * Turn on fic interfaces by default. Drivers will turn on/off other MSS * peripherals as required. */ (void)mss_config_clk_rst(MSS_PERIPH_FIC0, (uint8_t)MPFS_HAL_FIRST_HART, PERIPHERAL_ON); (void)mss_config_clk_rst(MSS_PERIPH_FIC1, (uint8_t)MPFS_HAL_FIRST_HART, PERIPHERAL_ON); (void)mss_config_clk_rst(MSS_PERIPH_FIC2, (uint8_t)MPFS_HAL_FIRST_HART, PERIPHERAL_ON); (void)mss_config_clk_rst(MSS_PERIPH_FIC3, (uint8_t)MPFS_HAL_FIRST_HART, PERIPHERAL_ON); /* enable the fabric */ mss_enable_fabric(); #endif /* MPFS_HAL_HW_CONFIG */ (void)main_other_hart(hls); } __builtin_unreachable(); /* should never get here */ while(true) { static volatile uint64_t counter = 0U; /* Added some code as debugger hangs if in loop doing nothing */ counter = counter + 1U; } return (0); } #endif /*============================================================================== * This function is called by the lowest enabled hart (MPFS_HAL_FIRST_HART) in * the configuration file : * (src/boards/my_hart_id = MPFS_HAL_FIRST_HART; hls->in_wfi_indicator = HLS_MAIN_HART_STARTED; WFI_SM sm_check_thread = INIT_THREAD_PR; hart_id = MPFS_HAL_FIRST_HART + 1U; while( hart_id <= MPFS_HAL_LAST_HART) { uint32_t wait_count = 0U; switch(sm_check_thread) { default: case INIT_THREAD_PR: switch (hart_id) { case 1: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h1$); break; case 2: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h2$); break; case 3: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h3$); break; case 4: stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h4$); break; } hls = (HLS_DATA*)(stack_top - HLS_DEBUG_AREA_SIZE); sm_check_thread = CHECK_WFI; wait_count = 0U; break; case CHECK_WFI: if( hls->in_wfi_indicator == HLS_OTHER_HART_IN_WFI ) { /* Separate state- to add a little delay */ sm_check_thread = SEND_WFI; } break; case SEND_WFI: hls->my_hart_id = hart_id; /* record hartid locally */ raise_soft_interrupt(hart_id); sm_check_thread = CHECK_WAKE; wait_count = 0UL; break; case CHECK_WAKE: if( hls->in_wfi_indicator == HLS_OTHER_HART_PASSED_WFI ) { sm_check_thread = INIT_THREAD_PR; hart_id++; wait_count = 0UL; } else { wait_count++; if(wait_count > 0x10U) { if( hls->in_wfi_indicator == HLS_OTHER_HART_IN_WFI ) { hls->my_hart_id = hart_id; /* record hartid locally */ raise_soft_interrupt(hart_id); wait_count = 0UL; } } } break; } } stack_top = (ptrdiff_t)((uint8_t*)&__stack_top_h1$); hls = (HLS_DATA*)(stack_top - HLS_DEBUG_AREA_SIZE); hls->in_wfi_indicator = HLS_MAIN_HART_FIN_INIT; (void)main_other_hart(hls); } __builtin_unreachable(); /* should never get here */ while(true) { static volatile uint64_t counter = 0U; /* Added some code as debugger hangs if in loop doing nothing */ counter = counter + 1U; } return (0); } #endif /*============================================================================== * U54s startup. * This is called from entry.S * If you need to modify this function, create your own one in a user directory * space. * * Please note: harts MPFS_HAL_FIRST_FIRST + 1 to MPFS_HAL_FIRST_LAST will wait * in startup code in entry.S as they run the wfi (wait for interrupt) * instruction. * They are woken up as required by the the MPFS_HAL_FIRST_HART, in the function * main_first_hart(). * ( It triggers a software interrupt on the particular hart to be woken up ) */ __attribute__((weak)) int main_other_hart(HLS_DATA* hls) { #if (IMAGE_LOADED_BY_BOOTLOADER == 0) // This also means no hardware init is required extern char __app_stack_top_h0; extern char __app_stack_top_h1; extern char __app_stack_top_h2; extern char __app_stack_top_h3; extern char __app_stack_top_h4; const uint64_t app_stack_top_h0 = (const uint64_t)&__app_stack_top_h0 - (HLS_DEBUG_AREA_SIZE); const uint64_t app_stack_top_h1 = (const uint64_t)&__app_stack_top_h1 - (HLS_DEBUG_AREA_SIZE); const uint64_t app_stack_top_h2 = (const uint64_t)&__app_stack_top_h2 - (HLS_DEBUG_AREA_SIZE); const uint64_t app_stack_top_h3 = (const uint64_t)&__app_stack_top_h3 - (HLS_DEBUG_AREA_SIZE); const uint64_t app_stack_top_h4 = (const uint64_t)&__app_stack_top_h4 - (HLS_DEBUG_AREA_SIZE); #ifdef MPFS_HAL_HW_CONFIG #ifdef MPFS_HAL_SHARED_MEM_ENABLED /* * If we are a boot-loader, and shared memory enabled (MPFS_HAL_SHARED_MEM_ENABLED) * sets the pointer in each harts HLS to the shared memory. * This allows access to this shared memory across all harts. */ const uint64_t app_hart_common_start = (const uint64_t)&__app_hart_common_start; hls->shared_mem = (uint64_t *)app_hart_common_start; hls->shared_mem_marker = SHARED_MEM_INITALISED_MARKER; hls->shared_mem_status = SHARED_MEM_DEFAULT_STATUS; #endif #else #ifdef MPFS_HAL_SHARED_MEM_ENABLED /* make sure each harts Harts Local Storage has pointer to common memory if enabled */ /* store the value here received from boot-loader */ /* a1 will contain pointer to the start of shared memory */ //hls->shared_mem = (uint64_t *)__uninit_bottom$; #else /* * We are not using shared memory */ hls->shared_mem = (uint64_t *)NULL; #endif #endif volatile uint64_t dummy; switch(hls->my_hart_id) { case 0U: __asm volatile ("add sp, x0, %1" : "=r"(dummy) : "r"(app_stack_top_h0)); e51(); break; case 1U: (void)init_pmp((uint8_t)1); __asm volatile ("add sp, x0, %1" : "=r"(dummy) : "r"(app_stack_top_h1)); u54_1(); break; case 2U: (void)init_pmp((uint8_t)2); __asm volatile ("add sp, x0, %1" : "=r"(dummy) : "r"(app_stack_top_h2)); u54_2(); break; case 3U: (void)init_pmp((uint8_t)3); __asm volatile ("add sp, x0, %1" : "=r"(dummy) : "r"(app_stack_top_h3)); u54_3(); break; case 4U: (void)init_pmp((uint8_t)4); __asm volatile ("add sp, x0, %1" : "=r"(dummy) : "r"(app_stack_top_h4)); u54_4(); break; default: /* no more harts */ break; } /* should never get here */ while(true) { static volatile uint64_t counter = 0U; /* Added some code as debugger hangs if in loop doing nothing */ counter = counter + 1U; } #else /* (IMAGE_LOADED_BY_BOOTLOADER == 0) */ uint64_t hartid = read_csr(mhartid); switch(hartid) { case 0U: e51(); break; case 1U: u54_1(); break; case 2U: u54_2(); break; case 3U: u54_3(); break; case 4U: u54_4(); break; default: /* no more harts */ break; } #endif return (0); } /*============================================================================== * Load the virtual ROM located at address 0x20003120 within the SCB system * registers with an executable allowing to park a hart in an infinite loop. */ #ifdef MPFS_HAL_HW_CONFIG #define VIRTUAL_BOOTROM_BASE_ADDR 0x20003120UL #define NB_BOOT_ROM_WORDS 8U const uint32_t rom[NB_BOOT_ROM_WORDS] = { 0x00000513U, /* li a0, 0 */ 0x34451073U, /* csrw mip, a0 */ 0x10500073U, /* wfi */ 0xFF5FF06FU, /* j 0x20003120 */ 0xFF1FF06FU, /* j 0x20003120 */ 0xFEDFF06FU, /* j 0x20003120 */ 0xFE9FF06FU, /* j 0x20003120 */ 0xFE5FF06FU /* j 0x20003120 */ }; void load_virtual_rom(void) { volatile uint32_t * p_virtual_bootrom = (uint32_t *)VIRTUAL_BOOTROM_BASE_ADDR; config_copy( (void *)p_virtual_bootrom, (void *)rom,sizeof(rom[NB_BOOT_ROM_WORDS])); } #endif /* MPFS_HAL_HW_CONFIG */ /*============================================================================== * Put the hart executing this code into an infinite loop executing from the * SCB system register memory space. * This allows preventing a hart from accessing memory regardless of memory * hierarchy configuration or compiler/linker settings. * This function relies on load_virtual_rom() having been called previously to * populate the virtual ROM with a suitable executable. */ static void park_hart(void) { clear_csr(mstatus, MSTATUS_MIE); __asm volatile("fence.i"); __asm volatile("li ra,0x20003120"); __asm volatile("ret"); } /*============================================================================== * E51 code executing after system startup. * In absence of an application function of this name with strong linkage, this * function will get linked. * This default implementation is for illustration purpose only. If you need to * modify this function, create your own one in an application directory space. */ __attribute__((weak)) void e51(void) { /* Put hart in safe infinite WFI loop. */ park_hart(); } /*============================================================================== * First U54. * In absence of an application function of this name with strong linkage, this * function will get linked. * This default implementation is for illustration purpose only. If you need to * modify this function, create your own one in an application directory space. */ __attribute__((weak)) void u54_1(void) { /* Put hart in safe infinite WFI loop. */ park_hart(); } /*============================================================================== * Second U54. * In absence of an application function of this name with strong linkage, this * function will get linked. * This default implementation is for illustration purpose only. If you need to * modify this function, create your own one in an application directory space. */ __attribute__((weak)) void u54_2(void) { /* Put hart in safe infinite WFI loop. */ park_hart(); } /*============================================================================== * Third U54. * In absence of an application function of this name with strong linkage, this * function will get linked. * This default implementation is for illustration purpose only. If you need to * modify this function, create your own one in an application directory space. */ __attribute__((weak)) void u54_3(void) { /* Put hart in safe infinite WFI loop. */ park_hart(); } /*============================================================================== * Fourth U54. * In absence of an application function of this name with strong linkage, this * function will get linked. * This default implementation is for illustration purpose only. If you need to * modify this function, create your own one in an application directory space. */ __attribute__((weak)) void u54_4(void) { /* Put hart in safe infinite WFI loop. */ park_hart(); } /*----------------------------------------------------------------------------- * _start() function called invoked * This function is called on power up and warm reset. */ __attribute__((weak)) void init_memory( void) { copy_section(&__text_load, &__text_start, &__text_end); copy_section(&__sdata_load, &__sdata_start, &__sdata_end); copy_section(&__data_load, &__data_start, &__data_end); zero_section(&__sbss_start, &__sbss_end); zero_section(&__bss_start, &__bss_end); __disable_all_irqs(); /* disables local and global interrupt enable */ } /*----------------------------------------------------------------------------- * _start() function called invoked * This function is called on power up and warm reset. */ __attribute__((weak)) void init_ddr(void) { if ((LIBERO_SETTING_DDRPHY_MODE & DDRPHY_MODE_MASK) != DDR_OFF_MODE) { #ifdef DDR_SUPPORT uint64_t end_address; #if 0 /* enable to init cache to zero using 64 bit writes */ end_address = LIBERO_SETTING_DDR_64_NON_CACHE + LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI2_0 + LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI2_1; zero_section((uint64_t *)LIBERO_SETTING_DDR_64_NON_CACHE, (uint64_t *)end_address); #endif end_address = LIBERO_SETTING_DDR_64_CACHE + LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI1_0 + LIBERO_SETTING_CFG_AXI_END_ADDRESS_AXI1_1; zero_section((uint64_t *)LIBERO_SETTING_DDR_64_CACHE, (uint64_t *)end_address); #endif } } /** * This function is configured by editing parameters in * mss_sw_config.h as required. * @return */ __attribute__((weak)) uint8_t init_bus_error_unit(void) { uint8_t hart_id; /* Init BEU in all harts - enable local interrupt */ for(hart_id = MPFS_HAL_FIRST_HART; hart_id <= MPFS_HAL_LAST_HART; hart_id++) { BEU->regs[hart_id].ENABLE = (uint64_t)BEU_ENABLE; BEU->regs[hart_id].PLIC_INT = (uint64_t)BEU_PLIC_INT; BEU->regs[hart_id].LOCAL_INT = (uint64_t)BEU_LOCAL_INT; BEU->regs[hart_id].CAUSE = 0ULL; BEU->regs[hart_id].ACCRUED = 0ULL; BEU->regs[hart_id].VALUE = 0ULL; } return (0U); } /** * init_mem_protection_unit(void) * add this function to you code and configure as required * @return */ __attribute__((weak)) uint8_t init_mem_protection_unit(void) { mpu_configure(); return (0U); } /** * init_pmp(void) * add this function to you code and configure as required * @return */ __attribute__((weak)) uint8_t init_pmp(uint8_t hart_id) { pmp_configure(hart_id); return (0U); } system_startup.h000066400000000000000000000106301432224323300403610ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /****************************************************************************** * @file system_startup.h * @author Microchip-FPGA Embedded Systems Solutions * @brief Macros and APIs for the system_startup.c */ #ifndef SYSTEM_STARTUP_H #define SYSTEM_STARTUP_H #ifdef __cplusplus extern "C" { #endif typedef enum WFI_SM_ { INIT_THREAD_PR = 0x00, /*!< 0 init pointer */ CHECK_WFI = 0x01, /*!< is hart in wfi? */ SEND_WFI = 0x02, /*!< separate state to add a little delay*/ CHECK_WAKE = 0x03, /*!< has hart left wfi*/ } WFI_SM; /*------------------------------------------------------------------------------ * Markers used to indicate startup status of hart */ #ifndef HLS_DATA_IN_WFI #define HLS_DATA_IN_WFI 0x12345678U #endif #ifndef HLS_DATA_PASSED_WFI #define HLS_DATA_PASSED_WFI 0x87654321U #endif #ifndef SHARED_MEM_INITALISED_MARKER #define SHARED_MEM_INITALISED_MARKER 0xA1A2A3A4UL #endif #ifndef SHARED_MEM_DEFAULT_STATUS #define SHARED_MEM_DEFAULT_STATUS 0x00000000UL #endif typedef struct HLS_DATA_ { volatile uint32_t in_wfi_indicator; volatile uint32_t my_hart_id; volatile uint32_t shared_mem_marker; volatile uint32_t shared_mem_status; volatile uint64_t * shared_mem; } HLS_DATA; /*------------------------------------------------------------------------------ * Symbols from the linker script used to locate the text, data and bss sections. */ extern unsigned long __stack_top_h0$; extern unsigned long __stack_bottom_h0$; extern unsigned long __stack_top_h1$; extern unsigned long __stack_bottom_h1$; extern unsigned long __stack_top_h2$; extern unsigned long __stack_bottom_h2$; extern unsigned long __stack_top_h3$; extern unsigned long __stack_bottom_h3$; extern unsigned long __stack_top_h4$; extern unsigned long __stack_bottom_h4$; extern unsigned long __app_hart_common_start; extern unsigned long __app_hart_common_end; extern unsigned long __data_load; extern unsigned long __data_start; extern unsigned long __data_end; extern unsigned long __sbss_start; extern unsigned long __sbss_end; extern unsigned long __bss_start; extern unsigned long __bss_end; extern unsigned long __sdata_load; extern unsigned long __sdata_start; extern unsigned long __sdata_end; extern unsigned long __text_load; extern unsigned long __text_start; extern unsigned long __text_end; extern unsigned long __l2lim_start; extern unsigned long __l2lim_end; extern unsigned long __e51itim_start; extern unsigned long __e51itim_end; extern unsigned long __u54_1_itim_start; extern unsigned long __u54_1_itim_end; extern unsigned long __u54_2_itim_start; extern unsigned long __u54_2_itim_end; extern unsigned long __u54_3_itim_start; extern unsigned long __u54_3_itim_end; extern unsigned long __u54_4_itim_start; extern unsigned long __u54_4_itim_end; #ifndef MPFS_HAL_HW_CONFIG extern unsigned long __uninit_bottom$; extern unsigned long __uninit_top$; #endif /* * Function Declarations */ int main_first_hart(HLS_DATA* hls); int main_first_hart_app(HLS_DATA* hls); int main_other_hart(HLS_DATA* hls); int u54_single_hart(HLS_DATA* hls); void e51(void); void u54_1(void); void u54_2(void); void u54_3(void); void u54_4(void); void init_memory( void); void init_ddr( void); uint8_t init_mem_protection_unit(void); uint8_t init_pmp(uint8_t hart_id); uint8_t init_bus_error_unit( void); char * memfill(void *dest, const void * src, size_t len); char * config_copy(void *dest, const void * src, size_t len); char * config_16_copy(void *dest, const void * src, size_t len); char * config_32_copy(void *dest, const void * src, size_t len); char * config_64_copy(void *dest, const void * src, size_t len); void copy_section ( uint64_t * p_load, uint64_t * p_vma, uint64_t * p_vma_end ); void zero_section ( uint64_t *__sbss_start, uint64_t * __sbss_end ); void load_virtual_rom(void); void count_section ( uint64_t * start_address, uint64_t * end_address, uint64_t * start_value ); #ifdef __cplusplus } #endif #endif /* SYSTEM_STARTUP_H */ system_startup_defs.h000066400000000000000000000025141432224323300413640ustar00rootroot00000000000000hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /****************************************************************************** * @file system_startup_defs.h * @author Microchip-FPGA Embedded Systems Solutions * @brief Defines for the system_startup_defs.c */ #ifndef SYSTEM_STARTUP_DEFS_H #define SYSTEM_STARTUP_DEFS_H #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------------ * Markers used to indicate startup status of hart */ #define HLS_MAIN_HART_STARTED 0x12344321U #define HLS_MAIN_HART_FIN_INIT 0x55555555U #define HLS_OTHER_HART_IN_WFI 0x12345678U #define HLS_OTHER_HART_PASSED_WFI 0x87654321U /*------------------------------------------------------------------------------ * Define the size of the HLS used * In our HAL, we are using Hart Local storage for debug data storage only * as well as flags for wfi instruction management. * The TLS will take memory from top of the stack if allocated * */ #if !defined (HLS_DEBUG_AREA_SIZE) #define HLS_DEBUG_AREA_SIZE 64 #endif #ifdef __cplusplus } #endif #endif /* SYSTEM_STARTUP_DEFS_H */ hart-software-services-2022.10/boards/000077500000000000000000000000001432224323300175375ustar00rootroot00000000000000hart-software-services-2022.10/boards/Kconfig000066400000000000000000000001771432224323300210470ustar00rootroot00000000000000menu "Board/Design Configuration Options" config BOARD string option env="BOARD" source "boards/$(BOARD)/Kconfig" endmenu hart-software-services-2022.10/boards/aries-m100pfsevp/000077500000000000000000000000001432224323300225415ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/Kconfig000066400000000000000000000004011432224323300240370ustar00rootroot00000000000000menu "aries-m100pfsevp Design Configuration Options" config SOC_FPGA_DESIGN_XML string "Enter path to Libero XML file" default "boards/$(BOARD)/soc_fpga_design/xml/m100pfs_reference.xml" help This option specifies the design XML file to use. endmenu hart-software-services-2022.10/boards/aries-m100pfsevp/Makefile000066400000000000000000000125401432224323300242030ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Defines target-specific build-rules variables, extra sources and include paths # # # The ARIES Embedded module M100PFS on the board M100PFSEVP # $(info aries-m100pfsevp selected) BINDIR=Default TARGET-l2scratch=hss-l2scratch.elf TARGET-envm-wrapper=hss-envm-wrapper.elf RISCV_TARGET=$(TARGET-l2scratch) $(TARGET-envm-wrapper) TARGET:=$(RISCV_TARGET) LINKER_SCRIPT-l2scratch=boards/${BOARD}/hss-l2scratch.ld CONFIG_PLATFORM_MPFS=y PLATFORM_CFLAGS += -DCONFIG_PLATFORM_MPFS=1 -DCONFIG_MODULE_M100PFS=1 -DCONFIG_BOARD_M100PFSEVP=1 BOARD_DIR=boards/aries-m100pfsevp INCLUDES += \ -I$(BOARD_DIR)/mpfs_hal_config/\ -I$(BOARD_DIR)/fpga_design_config/\ -I$(BOARD_DIR)/ \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform \ EXTRA_SRCS-y += \ $(BOARD_DIR)/hss_uart_init.c \ $(BOARD_DIR)/uart_helper.c \ $(BOARD_DIR)/hss_board_init.c \ EXTRA_SRCS-$(CONFIG_USE_LOGO) += \ $(BOARD_DIR)/hss_logo_init.c $(BOARD_DIR)/hss_uart_init.o: CFLAGS=$(CFLAGS_GCCEXT) EXTRA_OBJS-$(CONFIG_SERVICE_BOOT_USE_PAYLOAD) += $(BOARD_DIR)/payload.o $(BOARD_DIR)/payload.o: $(BOARD_DIR)/payload.bin $(LD) -r -b binary $< -o $@ ################################################################################################ # # Extra hardware dependency rules for YMODEM # INCLUDES += \ -Ibaremetal/ \ -Ibaremetal/drivers/winbond_w25n01gv \ EXTRA_SRCS-$(CONFIG_SERVICE_QSPI) += \ baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.c baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.o: CFLAGS=$(CFLAGS_GCCEXT) ################################################################################################ # # Linker Scripts # $(BOARD_DIR)/hss-l2scratch.ld: $(BOARD_DIR)/hss-l2scratch.lds config.h ################################################################################################ # # Extra dependency rules for auto-generated configuration files (from Libero XML) # SOC_CONFIG_FILES = \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_ddr_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sysreg.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_mss_clks.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_io_bank.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_off_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_options.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_segs.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddrc.h \ $(BOARD_DIR)/fpga_design_config/general/hw_gen_peripherals.h \ $(BOARD_DIR)/fpga_design_config/fpga_design_config.h \ $(BOARD_DIR)/fpga_design_config/io/hw_hsio_mux.h \ $(BOARD_DIR)/fpga_design_config/io/hw_mssio_mux.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_apb_split.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_cache.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_memory.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_crypto.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_mmc.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_scb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_trace.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_usb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart3.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart4.h \ $(BOARD_DIR)/fpga_design_config/sgmii/hw_sgmii_tip.h \ config.h: $(SOC_CONFIG_FILES) $(SOC_CONFIG_FILES): $(subst $\",,$(CONFIG_SOC_FPGA_DESIGN_XML)) @$(ECHO) " MPFSCFGGEN $<"; $(PYTHON) tools/polarfire-soc-configuration-generator/mpfs_configuration_generator.py $< $(BOARD_DIR) $(RISCV_TARGET): $(SOC_CONFIG_FILES) hart-software-services-2022.10/boards/aries-m100pfsevp/def_config000066400000000000000000000063231432224323300245530ustar00rootroot00000000000000 # # Board/Design Configuration Options # # # aries-m100pfsevp Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/aries-m100pfsevp/soc_fpga_design/xml/m100pfs_reference.xml" # end of aries-m100pfsevp Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # CONFIG_SERVICE_BOOT_SETS_SUPPORT=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET=0x400 # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service # CONFIG_SERVICE_CRYPTO is not set CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT is not set # end of SDIO Control CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_OPENSBI_IHC is not set # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y # CONFIG_USE_IHC is not set # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # CONFIG_MEMTEST=y CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/aries-m100pfsevp/def_config_custom000066400000000000000000000043621432224323300261460ustar00rootroot00000000000000# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) # # Services # CONFIG_SERVICE_BOOT=y # # Boot Service # CONFIG_SERVICE_BOOT_SETS_SUPPORT=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set CONFIG_SERVICE_BOOT_CUSTOM_FLOW=y CONFIG_SERVICE_BOOT_MMC_USE_GPT=y CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y # CONFIG_SERVICE_CRYPTO is not set # CONFIG_SERVICE_FLASHFREEZE is not set # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_MMC=y # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # CONFIG_SERVICE_MMC_BUS_VOLTAGE_3V3 is not set # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set # CONFIG_SERVICE_UART is not set # CONFIG_SERVICE_WDOG is not set CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_YMODEM is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y CONFIG_SERVICE_TINYCLI=y # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=5 # CONFIG_SERVICE_TINYCLI_REGISTER is not set # # Compression # # CONFIG_COMPRESSION is not set # # General Configuration Options # CONFIG_OPENSBI=y # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # CONFIG_SUPERLOOP_IN_U_MODE is not set # # Memory Options # CONFIG_MEMTEST=y CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=16 # CONFIG_IPI_FIXED_BASE is not set CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set CONFIG_USE_PCIE=y # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y # CONFIG_DEBUG_LOOP_TIMES is not set CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set hart-software-services-2022.10/boards/aries-m100pfsevp/def_config_examples/000077500000000000000000000000001432224323300265225ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/def_config_examples/def_config_no_banner000066400000000000000000000051551432224323300325570ustar00rootroot00000000000000# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) # # Services # CONFIG_SERVICE_BOOT=y # # Boot Service # CONFIG_SERVICE_BOOT_SETS_SUPPORT=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET=0x400 # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y # CONFIG_SERVICE_CRYPTO is not set # CONFIG_SERVICE_FLASHFREEZE is not set # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_MMC=y # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y CONFIG_SERVICE_SPI=y # CONFIG_SERVICE_UART is not set # CONFIG_SERVICE_WDOG is not set # # Watchdog Service # # end of Watchdog Service CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_YMODEM is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=0 CONFIG_SERVICE_TINYCLI_REGISTER=y # end of Tiny Command Line Interface # end of Services # # Compression # # CONFIG_COMPRESSION is not set # end of Compression # # General Configuration Options # CONFIG_OPENSBI=y # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # CONFIG_SUPERLOOP_IN_U_MODE is not set # # Memory Options # CONFIG_MEMTEST=y CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=16 # CONFIG_IPI_FIXED_BASE is not set CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set CONFIG_USE_PCIE=y # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y # CONFIG_USE_LOGO is not set # # Logo # # CONFIG_LOGO_INVERT_COLORS is not set # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y # CONFIG_DEBUG_LOOP_TIMES is not set # CONFIG_DEBUG_LOOP_TIMES_THRESHOLD is not set # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # end of Debug Options def_config_no_banner_no_tinycli_emmc_only000066400000000000000000000052461432224323300367720ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/def_config_examples# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) # # Services # CONFIG_SERVICE_BOOT=y # # Boot Service # CONFIG_SERVICE_BOOT_SETS_SUPPORT=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET=0x400 # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y # CONFIG_SERVICE_CRYPTO is not set # CONFIG_SERVICE_FLASHFREEZE is not set # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_MMC=y # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y # CONFIG_SERVICE_MMC_MODE_SDCARD is not set # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set # CONFIG_SERVICE_UART is not set # CONFIG_SERVICE_WDOG is not set # # Watchdog Service # # end of Watchdog Service CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_YMODEM is not set # CONFIG_SERVICE_USBDMSC is not set # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class # CONFIG_SERVICE_TINYCLI is not set # # Tiny Command Line Interface # # CONFIG_SERVICE_TINYCLI_TIMEOUT=0 # CONFIG_SERVICE_TINYCLI_REGISTER is not set # end of Tiny Command Line Interface # end of Services # # Compression # # CONFIG_COMPRESSION is not set # end of Compression # # General Configuration Options # CONFIG_OPENSBI=y # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # CONFIG_SUPERLOOP_IN_U_MODE is not set # # Memory Options # CONFIG_MEMTEST=y CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=16 # CONFIG_IPI_FIXED_BASE is not set CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set CONFIG_USE_PCIE=y # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y # CONFIG_USE_LOGO is not set # # Logo # # CONFIG_LOGO_INVERT_COLORS is not set # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y # CONFIG_DEBUG_LOOP_TIMES is not set # CONFIG_DEBUG_LOOP_TIMES_THRESHOLD is not set # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # end of Debug Options def_config_no_banner_no_tinycli_emmc_only_quiet000066400000000000000000000052611432224323300401760ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/def_config_examples# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) # # Services # CONFIG_SERVICE_BOOT=y # # Boot Service # CONFIG_SERVICE_BOOT_SETS_SUPPORT=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET=0x400 # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y # CONFIG_SERVICE_CRYPTO is not set # CONFIG_SERVICE_FLASHFREEZE is not set # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_MMC=y # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y # CONFIG_SERVICE_MMC_MODE_SDCARD is not set # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set # CONFIG_SERVICE_UART is not set # CONFIG_SERVICE_WDOG is not set # # Watchdog Service # # end of Watchdog Service CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_YMODEM is not set # CONFIG_SERVICE_USBDMSC is not set # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class # CONFIG_SERVICE_TINYCLI is not set # # Tiny Command Line Interface # # CONFIG_SERVICE_TINYCLI_TIMEOUT=0 # CONFIG_SERVICE_TINYCLI_REGISTER is not set # end of Tiny Command Line Interface # end of Services # # Compression # # CONFIG_COMPRESSION is not set # end of Compression # # General Configuration Options # CONFIG_OPENSBI=y # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # CONFIG_SUPERLOOP_IN_U_MODE is not set # # Memory Options # CONFIG_MEMTEST=y CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=16 # CONFIG_IPI_FIXED_BASE is not set CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set CONFIG_USE_PCIE=y # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y # CONFIG_USE_LOGO is not set # # Logo # # CONFIG_LOGO_INVERT_COLORS is not set # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Debug Options # # CONFIG_DEBUG_LOG_STATE_TRANSITIONS is not set # CONFIG_DEBUG_LOOP_TIMES is not set # CONFIG_DEBUG_LOOP_TIMES_THRESHOLD is not set # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # end of Debug Options def_config_no_tinycli_emmc_only000066400000000000000000000051631432224323300347470ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/def_config_examples# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) # # Services # CONFIG_SERVICE_BOOT=y # # Boot Service # CONFIG_SERVICE_BOOT_SETS_SUPPORT=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET=0x400 # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y # CONFIG_SERVICE_CRYPTO is not set # CONFIG_SERVICE_FLASHFREEZE is not set # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_MMC=y # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y # CONFIG_SERVICE_MMC_MODE_SDCARD is not set # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y CONFIG_SERVICE_SPI=y # CONFIG_SERVICE_UART is not set # CONFIG_SERVICE_WDOG is not set # # Watchdog Service # # end of Watchdog Service CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_YMODEM is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class # CONFIG_SERVICE_TINYCLI is not set # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=0 CONFIG_SERVICE_TINYCLI_REGISTER=y # end of Tiny Command Line Interface # end of Services # # Compression # # CONFIG_COMPRESSION is not set # end of Compression # # General Configuration Options # CONFIG_OPENSBI=y # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # CONFIG_SUPERLOOP_IN_U_MODE is not set # # Memory Options # CONFIG_MEMTEST=y CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=16 # CONFIG_IPI_FIXED_BASE is not set CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set CONFIG_USE_PCIE=y # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # # CONFIG_LOGO_INVERT_COLORS is not set # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y # CONFIG_DEBUG_LOOP_TIMES is not set CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # end of Debug Options hart-software-services-2022.10/boards/aries-m100pfsevp/drivers_config/000077500000000000000000000000001432224323300255445ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/drivers_config/fpga_ip/000077500000000000000000000000001432224323300271515ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/drivers_config/fpga_ip/miv_ihc/000077500000000000000000000000001432224323300305675ustar00rootroot00000000000000miv_ihc_add_mapping.h000066400000000000000000000105461432224323300346300ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IHC driver @section intro_sec Introduction Used to configure the driver with base addresses from your Libero Projext. These addresses will not change unless you change the Libero design IHC subsytem design. This file is used for reference only. When usiing in a project copy to src/boards/your-board/platform-config/drivers_config/fpga-ip/miv_ihc and rename dropping the _reference. @section *//*==========================================================================*/ #ifndef MIV_IHC_ADD_MAPPING_H_ #define MIV_IHC_ADD_MAPPING_H_ #ifndef COMMON_AHB_BASE_ADD #define COMMON_AHB_BASE_ADD 0x50000000UL #endif #ifndef IHC_HO_BASE_OFFSET #define IHC_HO_BASE_OFFSET 0x00000000UL #endif #ifndef IHC_H1_BASE_OFFSET #define IHC_H1_BASE_OFFSET 0x00000500UL #endif #ifndef IHC_H2_BASE_OFFSET #define IHC_H2_BASE_OFFSET 0x00000A00UL #endif #ifndef IHC_H3_BASE_OFFSET #define IHC_H3_BASE_OFFSET 0x00000F00UL #endif #ifndef IHC_H4_BASE_OFFSET #define IHC_H4_BASE_OFFSET 0x00001400UL #endif /************** My Hart 0 ************/ #ifndef IHC_LOCAL_H0_REMOTE_H1 #define IHC_LOCAL_H0_REMOTE_H1 0x50000000 #endif #ifndef IHC_LOCAL_H0_REMOTE_H2 #define IHC_LOCAL_H0_REMOTE_H2 0x50000100 #endif #ifndef IHC_LOCAL_H0_REMOTE_H3 #define IHC_LOCAL_H0_REMOTE_H3 0x50000200 #endif #ifndef IHC_LOCAL_H0_REMOTE_H4 #define IHC_LOCAL_H0_REMOTE_H4 0x50000300 #endif #ifndef IHCIA_LOCAL_H0 #define IHCIA_LOCAL_H0 0x50000400 #endif /************** My Hart 1 ************/ #ifndef IHC_LOCAL_H1_REMOTE_H0 #define IHC_LOCAL_H1_REMOTE_H0 0x50000500 #endif #ifndef IHC_LOCAL_H1_REMOTE_H2 #define IHC_LOCAL_H1_REMOTE_H2 0x50000600 #endif #ifndef IHC_LOCAL_H1_REMOTE_H3 #define IHC_LOCAL_H1_REMOTE_H3 0x50000700 #endif #ifndef IHC_LOCAL_H1_REMOTE_H4 #define IHC_LOCAL_H1_REMOTE_H4 0x50000800 #endif #ifndef IHCIA_LOCAL_H1 #define IHCIA_LOCAL_H1 0x50000900 #endif /************** My Hart 2 ************/ #ifndef IHC_LOCAL_H2_REMOTE_H0 #define IHC_LOCAL_H2_REMOTE_H0 0x50000A00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H1 #define IHC_LOCAL_H2_REMOTE_H1 0x50000B00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H3 #define IHC_LOCAL_H2_REMOTE_H3 0x50000C00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H4 #define IHC_LOCAL_H2_REMOTE_H4 0x50000D00 #endif #ifndef IHCIA_LOCAL_H2 #define IHCIA_LOCAL_H2 0x50000E00 #endif /************** My Hart 3 ************/ #ifndef IHC_LOCAL_H3_REMOTE_H0 #define IHC_LOCAL_H3_REMOTE_H0 0x50000F00 #endif #ifndef IHC_LOCAL_H3_REMOTE_H1 #define IHC_LOCAL_H3_REMOTE_H1 0x50001000 #endif #ifndef IHC_LOCAL_H3_REMOTE_H2 #define IHC_LOCAL_H3_REMOTE_H2 0x50001100 #endif #ifndef IHC_LOCAL_H3_REMOTE_H4 #define IHC_LOCAL_H3_REMOTE_H4 0x50001200 #endif #ifndef IHCIA_LOCAL_H3 #define IHCIA_LOCAL_H3 0x50001300 #endif /************** My Hart 4 ************/ #ifndef IHC_LOCAL_H4_REMOTE_H0 #define IHC_LOCAL_H4_REMOTE_H0 0x50001400 #endif #ifndef IHC_LOCAL_H4_REMOTE_H1 #define IHC_LOCAL_H4_REMOTE_H1 0x50001500 #endif #ifndef IHC_LOCAL_H4_REMOTE_H2 #define IHC_LOCAL_H4_REMOTE_H2 0x50001600 #endif #ifndef IHC_LOCAL_H4_REMOTE_H3 #define IHC_LOCAL_H4_REMOTE_H3 0x50001700 #endif #ifndef IHCIA_LOCAL_H4 #define IHCIA_LOCAL_H4 0x50001800 #endif /*------------------------------------------------------------------------------ * choose the interrupt mapping used in our system * Please see miv_ihc_regs.h for the defaults */ #define IHCIA_hart0_IRQHandler fabric_f2h_63_plic_IRQHandler #define IHCIA_hart1_IRQHandler fabric_f2h_62_plic_IRQHandler #define IHCIA_hart2_IRQHandler fabric_f2h_61_plic_IRQHandler #define IHCIA_hart3_IRQHandler fabric_f2h_60_plic_IRQHandler #define IHCIA_hart4_IRQHandler fabric_f2h_59_plic_IRQHandler #define IHCIA_hart0_INT FABRIC_F2H_63_PLIC #define IHCIA_hart1_INT FABRIC_F2H_62_PLIC #define IHCIA_hart2_INT FABRIC_F2H_61_PLIC #define IHCIA_hart3_INT FABRIC_F2H_60_PLIC #define IHCIA_hart4_INT FABRIC_F2H_59_PLIC #endif /* MIV_IHC_ADD_MAPPING_H_ */ miv_ihc_config.h000066400000000000000000000045401432224323300336270ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IhC driver @section intro_sec Introduction Used to configure the driver @section *//*==========================================================================*/ #ifndef MIV_IHC_CONFIG_H_ #define MIV_IHC_CONFIG_H_ #include "miv_ihc_add_mapping.h" /*------------------------------------------------------------------------------ * define the monitor hart (HSS hart) used in our system */ #define HSS_HART_MASK HART0_MASK #define HSS_HART_ID HART0_ID /*------------------------------------------------------------------------------ * HSS_REMOTE_HARTS_MASK * This is used to define the harts the HSS is communicating with */ #define HSS_REMOTE_HARTS_MASK (HART1_MASK | HART2_MASK |HART3_MASK | HART4_MASK) /*------------------------------------------------------------------------------ * Define which harts are connected via comms channels to a particular hart * user defined */ #define IHCIA_H0_REMOTE_HARTS (HSS_REMOTE_HARTS_MASK) /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS (HSS_HART_MASK | HART4_MASK) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H3_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H4_REMOTE_HARTS (HSS_HART_MASK | HART1_MASK) /* HSS and Context A connected */ /*------------------------------------------------------------------------------ * interrupts enabled in this system design for a particular hart * User defined */ #define IHCIA_H0_REMOTE_HARTS_INTS HSS_HART_DEFAULT_INT_EN /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART4_MP_INT_EN | HART4_ACK_INT_EN) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H3_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H4_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART1_MP_INT_EN | HART1_ACK_INT_EN) /* HSS and Context A connected */ #endif /* MIV_IHC_CONFIG_H_ */ hart-software-services-2022.10/boards/aries-m100pfsevp/fpga_design_config/000077500000000000000000000000001432224323300263345ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/fpga_design_config/README.md000066400000000000000000000000451432224323300276120ustar00rootroot00000000000000Placeholder for auto-generated code. hart-software-services-2022.10/boards/aries-m100pfsevp/hss-l2scratch.lds000066400000000000000000000271141432224323300257320ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip Corporation. * * SPDX-License-Identifier: MIT * * GNU linker script for Hart Software Services (HSS) * */ #include "config.h" OUTPUT_ARCH( "riscv" ) /* PolarFire SoC Memory map (ditaa diagram) ---------------------------------------- +-------------+ +-----------+ | non-cache | | non-cache | | WCB (SEG1) | +---------------------+ | (SEG1) | 0x18_0000_0000 +-------------+ | DDR cached | 0x14_0000_0000 +-----------+ | non-cache | | (SEG0) | | non-cache | | WCB (SEG1) | 0x10_0000_0000 +---------------------+ | (SEG1) | 0xD000_0000 +-------------+ | DDR cached | 0xC000_0000 +-----------+ | (SEG0) | 0x8000_0000 +---------------------+ | envm (128KiB) | | | 0x2022_0100 +---------------------+ | Zero Device | | | 0x0A00_0000 +---------------------+ | | 0x0820_0000 +---------------------+ | LIM (up to 1920KiB) | | | 0x0800_0000 +---------------------+ | U54_4 ITIM (28KiB) | | | 0x0182_0000 +---------------------+ | U54_3 ITIM (28KiB) | | | 0x0181_8000 +---------------------+ | U54_2 ITIM (28KiB) | | | 0x0181_0000 +---------------------+ | U54_1 ITIM (28KiB) | | | 0x0180_8000 +---------------------+ | E51 ITIM (28KiB) | | | 0x0180_0000 +---------------------+ | DTIM (8KiB) | | | 0x0100_0000 +---------------------+ | Debug | 0x0000_0000 +---------------------+ */ /******************************************************************************* * * -- MSS hart Reset vector * * The MSS reset vector for each hart is configured by Libero and stored securely * in the MPFS. * * The most common usage will be where the reset vector for each hart will be set * to the start of the envm at address 0x2022_0100, giving (128KiB-256bytes) * of contiguous non-volatile storage. Normally this is where the initial * boot-loader will reside. * * Libero outputs the configured reset vector address to the xml file, see * LIBERO_SETTING_RESET_VECTOR_HART0 etc in * * When debugging a bare metal program that is run out of reset from envm, a linker * script will be used whereby the progdtim will run from LIM instead of envm. * In this case, set the reset vector in the linker script to 0x0800_0000. * This means you are not continually programming the envm each time you load a * program and there is no limitation with hardware break points whn debugging. */ ENTRY(_start) /******************************************************************************* * * Memory Segments * * must be on 4k boundary (0x1000) - corresponds to page size, when using memory mem */ MEMORY { envm (rx) : ORIGIN = 0x20220100, LENGTH = (128k-256) dtim (rwx) : ORIGIN = 0x01000000, LENGTH = 7k /* DTIM */ switch_code (rx) : ORIGIN = 0x01001c00, LENGTH = 1k /* This 1K of DTIM is used to run code * when switching the envm clock */ e51_itim (rwx) : ORIGIN = 0x01800000, LENGTH = 28k u54_1_itim (rwx) : ORIGIN = 0x01808000, LENGTH = 28k u54_2_itim (rwx) : ORIGIN = 0x01810000, LENGTH = 28k u54_3_itim (rwx) : ORIGIN = 0x01818000, LENGTH = 28k u54_4_itim (rwx) : ORIGIN = 0x01820000, LENGTH = 28k l2lim (rwx) : ORIGIN = 0x08000000, LENGTH = 512k l2zerodevice (rwx) : ORIGIN = 0x0A000000, LENGTH = 512k ddr (rwx) : ORIGIN = 0x80000000, LENGTH = 32m ddrhi (rwx) : ORIGIN = 0x1000000000, LENGTH = 1888m ncddrhi (rwx) : ORIGIN = 0x1400000000, LENGTH = 2048m } PROVIDE(HEAP_SIZE = 0k); PROVIDE(STACK_SIZE_PER_HART = 16k); /******************************************************************************* * * Memory Sections and Placement */ SECTIONS { PROVIDE(__envm_start = ORIGIN(envm)); PROVIDE(__envm_end = ORIGIN(envm) + LENGTH(envm)); PROVIDE(__l2lim_start = ORIGIN(l2lim)); PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); PROVIDE(__l2_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); PROVIDE(__ddr_start = ORIGIN(ddr)); PROVIDE(__ddr_end = ORIGIN(ddr) + LENGTH(ddr)); PROVIDE(__ddrhi_start = ORIGIN(ddrhi)); PROVIDE(__ddrhi_end = ORIGIN(ddrhi) + LENGTH(ddrhi)); PROVIDE(__ncddrhi_start = ORIGIN(ncddrhi)); PROVIDE(__ncddrhi_end = ORIGIN(ncddrhi) + LENGTH(ncddrhi)); PROVIDE(__dtim_start = ORIGIN(dtim)); PROVIDE(__dtim_end = ORIGIN(dtim) + LENGTH(dtim)); PROVIDE(__e51itim_start = ORIGIN(e51_itim)); PROVIDE(__e51itim_end = ORIGIN(e51_itim) + LENGTH(e51_itim)); PROVIDE(__u54_1_itim_start = ORIGIN(u54_1_itim)); PROVIDE(__u54_1_itim_end = ORIGIN(u54_1_itim) + LENGTH(u54_1_itim)); PROVIDE(__u54_2_itim_start = ORIGIN(u54_2_itim)); PROVIDE(__u54_2_itim_end = ORIGIN(u54_2_itim) + LENGTH(u54_2_itim)); PROVIDE(__u54_3_itim_start = ORIGIN(u54_3_itim)); PROVIDE(__u54_3_itim_end = ORIGIN(u54_3_itim) + LENGTH(u54_3_itim)); PROVIDE(__u54_4_itim_start = ORIGIN(u54_4_itim)); PROVIDE(__u54_4_itim_end = ORIGIN(u54_4_itim) + LENGTH(u54_4_itim)); /* * Code and RO data lives in l2lim */ . = __l2_start; PROVIDE(_hss_start = .); PROVIDE(__l2_scratchpad_vma_start = .); .text : ALIGN(0x10) { *(.entry) . = ALIGN(0x10); *(.text .text.* .gnu.linkonce.t.*) *(.plt) . = ALIGN(0x10); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) *(.sdata2*) *(.gcc_except_table) *(.eh_frame_hdr) *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(0x10); } >l2zerodevice .gnu_build_id : ALIGN(8) { PROVIDE(gnu_build_id = .); *(.note.gnu.build-id) } >l2zerodevice PROVIDE(_hss_end = .); /******************************************************************************* * * The .ram_code section will contain the code That is run from RAM. * We are using this code to switch the clocks including envm clock. * This can not be done when running from envm * This will need to be copied to ram, before any of this code is run. * */ .ram_code : ALIGN(0x10) { __sc_load = LOADADDR (.ram_code); __sc_start = .; *(.ram_codetext) /* .ram_codetext sections (code) */ *(.ram_codetext*) /* .ram_codetext* sections (code) */ *(.ram_coderodata) /* read-only data (constants) */ *(.ram_coderodata*) . = ALIGN (0x10); __sc_end = .; } >switch_code /******************************************************************************* * * Short/global data section * */ .sdata : ALIGN(0x40) /* short/global data section */ { __sdata_load = LOADADDR(.sdata); __sdata_start = .; /* * offset used with gp(gloabl pointer) are +/- 12 bits, so set * point to middle of expected sdata range * * If sdata more than 4K, linker used direct addressing. * Perhaps we should add check/warning to linker script if sdata is > 4k */ __global_pointer$ = . + 0x800; *(.sdata .sdata.* .gnu.linkonce.s.*) . = ALIGN(0x10); __sdata_end = .; } >l2zerodevice /******************************************************************************* * * (Explicitly) Initialized data section * */ #ifdef CONFIG_SERVICE_BOOT_USE_PAYLOAD .data.payload : ALIGN(16) { _payload_start = .; KEEP(boards/mpfs-icicle-kit-es/payload.o(.*)) _payload_end = .; } #endif .data : ALIGN(0x40) { __data_load = LOADADDR(.data); __data_start = .; *(.got.plt) *(.got) *(.shdata) *(.data .data.* .gnu.linkonce.d.*) . = ALIGN(0x10); __data_end = .; } >l2zerodevice /******************************************************************************* * * Uninitialized (zero-initialized) section */ /* * Short zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. * */ .sbss : ALIGN(0x40) { __sbss_start = .; *(.sbss .sbss.* .gnu.linkonce.sb.*) *(.scommon) . = ALIGN(0x10); __sbss_end = .; } >l2zerodevice /* * General Zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. */ .bss : ALIGN(0x40) { __bss_start = .; *(.shbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(0x10); __bss_end = .; } >l2zerodevice /* * Reserved space for Hart stacks */ .stack : ALIGN(0x40) { __stack_bottom = .; __stack_bottom_h0$ = .; . += STACK_SIZE_PER_HART; __stack_top_h0$ = . - 8; __stack_bottom_h1$ = .; . += STACK_SIZE_PER_HART; __stack_top_h1$ = . - 8; __stack_bottom_h2$ = .; . += STACK_SIZE_PER_HART; __stack_top_h2$ = . - 8; __stack_bottom_h3$ = .; . += STACK_SIZE_PER_HART; __stack_top_h3$ = . - 8; __stack_bottom_h4$ = .; . += STACK_SIZE_PER_HART; __stack_top_h4$ = . - 8; __stack_top = .; } >l2zerodevice _end = .; PROVIDE(__l2_scratchpad_vma_end = .); /* * End of uninitialized data segment * *******************************************************************************/ /* .heap : ALIGN(0x10) { __heap_start = .; . += HEAP_SIZE; __heap_end = .; . = ALIGN(0x10); _heap_end = __heap_end; } >dtim */ } hart-software-services-2022.10/boards/aries-m100pfsevp/hss_board_init.c000066400000000000000000000040321432224323300256730ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Board Initalization * \brief Board Initialization */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "hss_init.h" #include "hss_state_machine.h" #include "ssmb_ipi.h" #include "hss_registry.h" /******************************************************************************************************/ /*! * \brief Board Init Function Registration Table * * The following structure is used to connect in new board init functions. */ #include "hss_init.h" #include "hss_boot_pmp.h" #include "hss_sys_setup.h" #include "hss_board_init.h" const struct InitFunction /*@null@*/ boardInitFunctions[] = { // Name FunctionPointer Halt Restart { "HSS_ZeroTIMs", HSS_ZeroTIMs, false, false }, { "HSS_Setup_PLIC", HSS_Setup_PLIC, false, false }, { "HSS_Setup_BusErrorUnit", HSS_Setup_BusErrorUnit, false, false }, { "HSS_Setup_MPU", HSS_Setup_MPU, false, false }, { "HSS_DDRInit", HSS_DDRInit, false, false }, { "HSS_ZeroDDR", HSS_ZeroDDR, false, false }, #ifdef CONFIG_USE_PCIE { "HSS_PCIeInit", HSS_PCIeInit, false, false }, #endif //{ "HSS_USBInit", HSS_USBInit, false, false }, }; /******************************************************************************************************/ /** * \brief Board Initialization Function * * All other initialization routines to be chained off this... */ /****************************************************************************/ #include "mss_sysreg.h" bool HSS_BoardInit(void) { RunInitFunctions(ARRAY_SIZE(boardInitFunctions), boardInitFunctions); return true; } bool HSS_BoardLateInit(void) { return true; } hart-software-services-2022.10/boards/aries-m100pfsevp/hss_logo_init.c000066400000000000000000000243011432224323300255450ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Software Initalization * \brief Full System Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "hss_debug.h" #if IS_ENABLED(CONFIG_COLOR_OUTPUT) const char g0_str[] = "\033[48;5;102m "; const char g1_str[] = "\033[48;5;103m "; const char g2_str[] = "\033[48;5;109m "; const char g3_str[] = "\033[48;5;110m "; const char g4_str[] = "\033[48;5;145m "; const char g5_str[] = "\033[48;5;146m "; const char g6_str[] = "\033[48;5;152m "; const char g7_str[] = "\033[48;5;153m "; const char g8_str[] = "\033[48;5;249m "; const char g9_str[] = "\033[48;5;189m "; const char gA_str[] = "\033[48;5;195m "; const char W1_str[] = "\033[48;5;231m "; const char b0_str[] = "\033[48;5;32m "; const char b1_str[] = "\033[48;5;66m "; const char b2_str[] = "\033[48;5;68m "; const char b3_str[] = "\033[48;5;74m "; const char RST_str[] = "\033[0m "; enum Color { b0 = 0, b1, b2, b3, W1, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, gA, RST, CRLF_token, }; const char* tokenStringTable[] = { b0_str, b1_str, b2_str, b3_str, W1_str, g0_str, g1_str, g2_str, g3_str, g4_str, g5_str, g6_str, g7_str, g8_str, g9_str, gA_str, RST_str, "\n", }; static const struct __attribute__((packed)) { uint8_t const count; enum Color const tokenIndex; } rleLogoElements[] = { { 1, RST }, { 1, CRLF_token }, { 46, W1 }, { 3, b1 }, { 1, g4 }, { 25, W1 }, { 1, RST }, { 1, CRLF_token }, { 46, W1 }, { 3, g4 }, { 26, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, W1 }, { 1, g9 }, { 15, g7 }, { 5, W1 }, { 3, g8 }, { 1, g8 }, { 3, g6 }, { 1, g8 }, { 1, g9 }, { 6, W1 }, { 1, g8 }, { 3, W1 }, { 3, g8 }, {1, W1 }, { 3, g8 }, { 6, W1 }, { 1, g8 }, { 2, g5 }, { 1, g8 }, { 1, gA }, { 11, W1 }, { 5, g8 }, { 1, RST }, { 1, CRLF_token }, { 1, gA}, { 16, b0 }, { 1, g9 }, { 3, W1 }, { 1, g8 }, { 9, b1 }, { 1, g4 }, { 3, W1 }, { 1, g8 }, { 2, g1 }, { 1, W1 }, { 2, g8 }, { 2, b1 }, { 1, g1 }, { 1, W1 }, { 1, g4 }, { 1, b1 }, { 1, g4 }, { 4, W1 }, { 1, g4 }, { 6, b1 }, { 1, g4 }, { 6, W1 }, { 1, g8 }, { 1, g4 }, { 1, g0 }, { 5, b1 }, { 1, g2 }, { 1, RST }, { 1, CRLF_token }, { 3, W1 }, { 1, g7 }, { 1, b2 }, { 10, b0 }, { 1, b2 }, { 1, g6 }, { 6, W1 }, { 1, g8 }, { 1, g4 }, { 1, g6 }, { 2, g8 }, { 3, W1 }, { 2, g8 }, { 1, b1 }, { 1, g2 }, { 2, W1 }, { 1, g2 }, { 1, b1 }, { 1, g4 }, { 1, g8 }, { 2, b1 }, { 1, g0 }, { 1, g1 }, { 1, g8 }, { 1, W1 }, { 1, g0 }, { 1, b1 }, { 1, g8 }, { 2, W1 }, { 1, g8 }, { 1, g0 }, { 1, b1 }, { 1, g4 }, { 1, g8 }, { 2, W1 }, { 1, g8 }, { 1, g2 }, { 1, b1 }, { 1, g0 }, { 4, W1 }, { 1, g4 }, { 3, b1 }, { 1, g0 }, { 1, g1 }, { 1, g4 }, { 1, g8 }, { 1, RST }, { 1, CRLF_token }, { 1, gA }, { 1, g3 }, { 1, g9 }, { 1, W1 }, { 1, gA }, { 1, b2 }, { 6, b0 }, { 1, b2 }, { 1, gA }, { 1, W1 }, { 1, g6 }, { 1, g3 }, { 1, gA }, { 8, W1 }, { 4, W1 }, { 1, g8 }, { 1, b1 }, { 1, b1 }, { 1, g9 }, { 1, W1 }, { 1, g8 }, { 1, b1 }, { 1, g0 }, { 1, b1 }, { 1, g4 }, { 1, g8 }, { 4, W1 }, { 1, b1 }, { 1, g0 }, { 2, W1 }, { 1, g8 }, { 2, g0 }, { 1, g8 }, { 6, W1 }, { 1, g4 }, { 1, b1 }, { 1, g4 }, { 2, W1 }, { 1, g1 }, { 1, b1 }, { 1, g0 }, { 1, g8 }, { 1, g9 }, { 6, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g9 }, { 2, b0 }, { 1, g5 }, { 1, W1 }, { 1, g9 }, { 5, b0 }, { 1, b2 }, { 1, gA }, { 1, W1 }, { 1, b3 }, { 2, b0 }, { 1, g9 }, { 13, W1 }, { 2, b1 }, { 1, g8 }, { 1, W1 }, { 1, g8 }, { 2, b1 }, { 1, g8 }, { 5, W1 }, { 1, g8 }, { 1, b1 }, { 1, g2 }, { 2, W1 }, { 1, g1 }, { 1, b1 }, { 1, g8 }, { 8, W1 }, { 2, b1 }, { 1, W1 }, { 1, g8 }, { 1, b1 }, { 1, g0 }, { 9, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g9 }, { 3, b0 }, { 1, g9 }, { 1, W1 }, { 1, g3 }, { 4, b0 }, { 1, g9 }, { 1, W1 }, { 1, g3 }, { 3, b0 }, { 4, W1 }, { 2, W1 }, { 1, g8 }, { 1, g5 }, { 1, g4 }, { 1, g2 }, { 2, g4 }, { 1, g8 }, { 1, W1 }, { 2, b1 }, { 1, g8 }, { 1, W1 }, { 1, g8 }, { 1, b1 }, { 1, g4 }, { 6, W1 }, { 1, g6 }, { 1, b1 }, { 1, g4 }, { 1, W1 }, { 1, g8 }, { 1, b1 }, { 1, g0 }, { 9, W1 }, { 1, g4 }, { 1, b1 }, { 1, g8 }, { 1, W1 }, { 2, b1 }, { 1, g8 }, { 8, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g6 }, { 3, b0 }, { 1, b2 }, { 1, W1 }, { 1, g9 }, { 3, b0 }, { 1, g3 }, { 1, W1 }, { 1, g9 }, { 4, b0 }, { 4, W1 }, { 1, g8 }, { 1, g1 }, { 7, b1 }, { 1, g2 }, { 2, b1 }, { 1, g8 }, { 1, W1 }, { 1, g8 }, { 1, b1 }, { 1, g8 }, { 6, W1 }, { 1, g4 }, { 1, b1 }, { 1, g8 }, { 1, W1 }, { 1, g4 }, { 1, b1 }, { 11, g0 }, { 1, b1 }, { 1, g4 }, { 1, W1 }, { 1, g8 }, { 1, b1 }, { 1, g0 }, { 1, g5 }, { 7, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g6 }, { 4, b0 }, { 1, g9 }, { 1, W1 }, { 1, b3 }, { 2, b0 }, { 1, g9 }, { 1, W1 }, { 1, b2 }, { 4, b0 }, { 2, W1 }, { 1, W1 }, { 2, g8 }, { 1, b1 }, { 1, g0 }, { 1, g8 }, { 2, W1 }, { 1, W1 }, { 1, g8 }, { 1, g1 }, { 3, b1 }, { 2, W1 }, { 2, b1 }, { 4, W1 }, { 3, W1 }, { 1, g0 }, { 1, b1 }, { 1, g8 }, { 1, W1 }, { 1, g4 }, { 1, b1 }, { 12, g0 }, { 1, g5 }, { 2, W1 }, { 1, g8 }, { 1, g1 }, { 2, b1 }, { 1, g4 }, { 1, g8 }, { 4, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g5 }, { 4, b0 }, { 1, g3 }, { 1, W1 }, { 1, g6 }, { 1, b0 }, { 1, b2 }, { 1, W1 }, { 1, g9 }, { 4, b0 }, { 1, b2 }, { 3, W1 }, { 1, g8 }, { 1, b1 }, { 1, g1 }, { 7, W1 }, { 1, g2 }, { 2, b1 }, { 2, W1 }, { 1, b1 }, { 1, g0 }, { 7, W1 }, { 2, b1 }, { 1, g8 }, { 1, W1 }, { 1, g1 }, { 1, b1 }, { 1, g6 }, { 16, W1 }, { 1, g8 }, { 1, g4 }, { 1, g0 }, { 1, b1 }, { 1, g0 }, { 1, g8 }, { 2, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g5 }, { 5, b0 }, { 1, W1 }, { 1, g9 }, { 1, b0 }, { 1, g6 }, { 1, W1 }, { 1, g3 }, { 4, b0 }, { 1, b2 }, { 3, W1 }, { 2, g4 }, { 1, g8 }, { 7, W1 }, { 1, g8 }, { 1, g4 }, { 1, g5 }, { 2, W1 }, { 1, g4 }, { 1, g5 }, { 7, W1 }, { 2, g4 }, { 1, g8 }, { 1, W1 }, { 1, g8 }, { 1, g4 }, { 1, g8 }, { 19, W1 }, { 2, g8 }, { 1, b1 }, { 1, g6 }, { 1, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g3 }, { 5, b0 }, { 1, g9 }, { 1, W1 }, { 1, b0 }, { 1, g9 }, { 1, gA }, { 5, b0 }, { 1, b2 }, { 54, W1 }, { 1, gA }, { 2, b1 }, { 1, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, g3 }, { 5, b0 }, { 1, g6 }, { 1, W1 }, { 1, b2 }, { 1, W1 }, { 1, g6 }, { 5, b0 }, { 1, b3 }, { 16, W1 }, { 1, g4 }, { 12, W1 }, { 1, g4 }, { 4, W1 }, { 2, g8 }, { 9, W1 }, { 1, g8 }, { 8, W1 }, { 1, g8 }, { 2, b1 }, { 1, g8 }, { 1, RST }, { 1, CRLF_token }, { 1, g3 }, { 5, b0 }, { 1, g3 }, { 1, W1 }, { 1, g3 }, { 1, W1 }, { 1, g3 }, { 2, b0 }, { 3, b0 }, { 1, g3 }, { 3, W1 }, { 3, g8 }, { 2, W1 }, { 3, g8 }, { 1, W1 }, { 2, g8 }, { 2, W1 }, { 1, g4 }, { 2, g8 }, { 2, W1 }, { 1, W1 }, { 2, g8 }, { 3, W1 }, { 2, g8 }, { 1, g4 }, { 2, W1 }, { 2, g8 }, { 1, g5 }, { 2, W1 }, { 3, g8 }, { 2, W1 }, { 4, g8 }, { 5, W1 }, { 2, g8 }, { 1, g4 }, { 1, b1 }, { 1, b1 }, { 1, g8 }, { 1, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, b3 }, { 5, b0 }, { 1, b2 }, { 1, W1 }, { 1, g7 }, { 1, W1 }, { 6, b0 }, { 1, g3 }, { 2, W1 }, { 2, g8 }, { 3, g8 }, { 1, g8 }, { 1, W1 }, { 1, g8 }, { 1, g6 }, { 1, W1 }, { 2, g8 }, { 1, W1 }, { 1, g4 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 2, g8 }, { 1, W1 }, { 3, g8 }, { 1, g8 }, { 1, W1 }, { 3, g8 }, { 1, g8 }, { 2, g0 }, { 1, b1 }, { 1, b1 }, { 1, b1 }, { 1, b1 }, { 1, b1 }, { 1, g4 }, { 3, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, b2 }, { 6, b0 }, { 2, W1 }, { 1, g9 }, { 6, b0 }, { 1, g3 }, { 2, W1 }, { 1, g5 }, { 8, g8 }, { 1, W1 }, { 2, g8 }, { 1, W1 }, { 1, g8 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 2, g8 }, { 1, g6 }, { 1, W1 }, { 1, g8 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 2, W1 }, { 1, g8 }, { 1, W1 }, { 1, g4 }, { 4, g8 }, { 1, g4 }, { 2, W1 }, { 3, g8 }, { 4, b1 }, { 1, g8 }, { 1, g2 }, { 1, g6 }, { 1, gA }, { 4, W1 }, { 1, RST }, { 1, CRLF_token }, { 7, b0 }, { 2, W1 }, { 1, g7 }, { 6, b0 }, { 1, g5 }, { 2, W1 }, { 1, g6 }, { 4, W1 }, { 1, g8 }, { 2, W1 }, { 2, g8 }, { 1, W1 }, { 2, g8 }, { 1, W1 }, { 1, g8 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g8 }, { 4, W1 }, { 1, g8 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 2, W1 }, { 1, g4 }, { 1, W1 }, { 1, g4 }, { 4, W1 }, { 1, g5 }, { 2, W1 }, { 2, g8 }, { 1, W1 }, { 3, g8 }, { 8, W1 }, { 1, RST }, { 1, CRLF_token }, { 1, b3 }, { 6, b2 }, { 1, gA }, { 1, W1 }, { 1, g6 }, { 6, b2 }, { 1, g9 }, { 3, W1 }, { 1, g6 }, { 2, g8 }, { 1, W1 }, { 1, g8 }, { 2, W1 }, { 1, g8 }, { 2, W1 }, { 2, g8 }, { 1, W1 }, { 1, g5 }, { 1, g8 }, { 1, g6 }, { 2, W1 }, { 3, g8 }, { 1, g8 }, { 1, W1 }, { 4, g8 }, { 1, W1 }, { 3, g8 }, { 1, g4 }, { 2, W1 }, { 1, g6 }, { 2, g8 }, { 2, W1 }, { 1, g5 }, { 1, g8 }, { 1, g5 }, { 13, W1 }, { 1, RST }, { 1, CRLF_token }, }; #endif bool HSS_LogoInit(void) { #if IS_ENABLED(CONFIG_COLOR_OUTPUT) int i; // decode and output our RLE Logo for (i = 0; i < ARRAY_SIZE(rleLogoElements); i++) { uint8_t j; for (j = 0u; j < rleLogoElements[i].count; j++) { mHSS_PUTS(tokenStringTable[rleLogoElements[i].tokenIndex]); } } #endif mHSS_PUTS("\n" "-------------------------\n" "-- M100PFS --\n" "-- PolarFire SoC FPGA --\n" "-- --\n" "-- Copyright (c) 2021 --\n" "-- ARIES Embedded GmbH --\n" "-------------------------\n" "\n"); return true; } hart-software-services-2022.10/boards/aries-m100pfsevp/hss_uart_init.c000066400000000000000000000025501432224323300255620ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Debug UART Initalization * \brief Debug UART Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" bool HSS_UARTInit(void) { // initialise debug UART #if IS_ENABLED(CONFIG_PLATFORM_MPFS) MSS_UART_init(&g_mss_uart0_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); // default all UARTs to 115200 for now // subsequent OS loads can change these if needed... MSS_UART_init(&g_mss_uart1_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart2_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart3_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart4_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); #else # error Unknown PLATFORM #endif return true; } hart-software-services-2022.10/boards/aries-m100pfsevp/mpfs_hal_config/000077500000000000000000000000001432224323300256575ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/mpfs_hal_config/mss_sw_config.h000066400000000000000000000166561432224323300307060ustar00rootroot00000000000000#ifndef MSS_SW_CONFIG_H_ #define MSS_SW_CONFIG_H_ /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * Platform definitions * Version based on requirements of MPFS MSS * */ /*========================================================================*//** @mainpage Sample file detailing how mss_sw_config.h should be constructed for the MPFS MSS @section intro_sec Introduction The mss_sw_config.h has the default software configuration settings for the MPFS HAL and will be located at /src/platform/platform_config_reference folder of the bare metal SoftConsole project. The platform_config_reference is provided as a default reference configuration. When you want to configure the MPFS HAL with required configuration for your project, the mss_sw_config.h must be edited and be placed in the following project directory: /src/boards//platform_config/mpfs_hal_config/ @section *//*==========================================================================*/ /* * Include any driver setup/over-rides you may require. */ #include "drivers/fpga_ip/miv_ihc/miv_ihc_defines.h" #include "drivers_config/fpga_ip/miv_ihc/miv_ihc_config.h" /* * MPFS_HAL_FIRST_HART and MPFS_HAL_LAST_HART defines are used to specify which * harts to actually start. The value and the actual hart it represents are * listed below: * value hart * 0 E51 * 1 U54_1 * 2 U54_2 * 3 U54_3 * 4 U54_4 * Set MPFS_HAL_FIRST_HART to a value greater than 0 if you do not want your * application to start and execute code on the harts represented by smaller * value numbers. * Set MPFS_HAL_LAST_HART to a value smaller than 4 if you do not wish to use * all U54_x harts. * Harts that are not started will remain in an infinite WFI loop unless used * through some other method. * The value of MPFS_HAL_FIRST_HART must always be less than MPFS_HAL_LAST_HART. * The value of MPFS_HAL_LAST_HART must never be greater than 4. * A typical use-case where you set MPFS_HAL_FIRST_HART = 1 and * MPFS_HAL_LAST_HART = 1 is when * your application is running on U54_1 and a bootloader running on E51 loads * your application to the target memory and kicks-off U54_1 to run it. */ #ifndef MPFS_HAL_FIRST_HART #define MPFS_HAL_FIRST_HART 1 #endif #ifndef MPFS_HAL_LAST_HART #define MPFS_HAL_LAST_HART 4 #endif /* * IMAGE_LOADED_BY_BOOTLOADER * We set IMAGE_LOADED_BY_BOOTLOADER = 0 if the application image runs from * non-volatile memory after reset. (No previous stage bootloader is used.) * Set IMAGE_LOADED_BY_BOOTLOADER = 1 if the application image is loaded by a * previous stage bootloader. * * MPFS_HAL_HW_CONFIG is defined if we are a boot-loader. This is a * conditional compile switch is used to determine if MPFS HAL will perform the * hardware configurations or not. * Defined => This program acts as a First stage bootloader and performs * hardware configurations. * Not defined => This program assumes that the hardware configurations are * already performed (Typically by a previous boot stage) * * List of items initialised when MPFS_HAL_HW_CONFIG is enabled * - load virtual rom (see load_virtual_rom(void) in system_startup.c) * - l2 cache config * - Bus error unit config * - MPU config * - pmp config * - I/O, clock and clock mux's, DDR and SGMII * - will start other harts, see text describing MPFS_HAL_FIRST_HART, * MPFS_HAL_LAST_HART above * */ #define IMAGE_LOADED_BY_BOOTLOADER 0 #if (IMAGE_LOADED_BY_BOOTLOADER == 0) #define MPFS_HAL_HW_CONFIG #endif /*------------------------------------------------------------------------------ * Markers used to indicate startup status of hart */ #define HLS_DATA_IN_WFI 0x12345678U #define HLS_DATA_PASSED_WFI 0x87654321U /* * If you are using common memory for sharing across harts, * uncomment #define MPFS_HAL_SHARED_MEM_ENABLED * make sure common memory is allocated in the linker script * See app_hart_common mem section in the example platform * linker scripts. */ //#define MPFS_HAL_SHARED_MEM_ENABLED /* define the required tick rate in Milliseconds */ /* if this program is running on one hart only, only that particular hart value * will be used */ #define HART0_TICK_RATE_MS 5UL #define HART1_TICK_RATE_MS 5UL #define HART2_TICK_RATE_MS 5UL #define HART3_TICK_RATE_MS 5UL #define HART4_TICK_RATE_MS 5UL /* * Define the size of the Hart Local Storage (HLS). * In the MPFS HAL, we are using HLS for debug data storage during the initial * boot phase. * This includes the flags which indicate the hart state regarding boot state. * The HLS will take memory from top of each stack allocated at boot time. * */ #define HLS_DEBUG_AREA_SIZE 64 /* * Bus Error Unit (BEU) configurations * BEU_ENABLE => Configures the events that the BEU can report. bit value * 1= enabled, 0 = disabled. * BEU_PLIC_INT => Configures which accrued events should generate an * interrupt to the PLIC. * BEU_LOCAL_INT => Configures which accrued events should generate a * local interrupt to the hart on which the event accrued. */ #define BEU_ENABLE 0x0ULL #define BEU_PLIC_INT 0x0ULL #define BEU_LOCAL_INT 0x0ULL /* * Clear memory on startup * 0 => do not clear DTIM and L2 * 1 => Clears memory * Note: If you are the zero stage bootloader, set this to one. */ #ifndef MPFS_HAL_CLEAR_MEMORY #define MPFS_HAL_CLEAR_MEMORY 0 #endif /* * Comment out the lines to disable the corresponding hardware support not required * in your application. * This is not necessary from an operational point of view as operation dictated * by MSS configurator settings, and items are enabled/disabled by this method. * The reason you may want to use below is to save code space. */ #define SGMII_SUPPORT #define DDR_SUPPORT #define MSSIO_SUPPORT /* * Debugging IHC. This placed memory map in volatile memory and uses software * state machine */ #define LIBERO_SETTING_CONTEXT_A_HART_EN 0x0000000EUL /* harts 1 to 3 */ #define LIBERO_SETTING_CONTEXT_B_HART_EN 0x00000010UL /* hart 4 */ /* * DDR software options */ /* * Debug DDR startup through a UART * Comment out in normal operation. May be useful for debug purposes in bring-up * of a new board design. * See the weakly linked function setup_ddr_debug_port(mss_uart_instance_t * uart) * If you need to edit this function, make another copy of the function in your * application without the weak linking attribute. This copy will then get linked. * */ //#define DEBUG_DDR_INIT //#define DEBUG_DDR_RD_RW_FAIL //#define DEBUG_DDR_RD_RW_PASS //#define DEBUG_DDR_CFG_DDR_SGMII_PHY //#define DEBUG_DDR_DDRCFG /* * The hardware configuration settings imported from Libero project get generated * into /src/boards// folder. * If you need to overwrite them for testing purposes, you can do so here. * e.g. If you want change the default SEG registers configuration defined by * LIBERO_SETTING_SEG0_0, define it here and it will take precedence. * #define LIBERO_SETTING_SEG0_0 0x80007F80UL * */ #endif /* USER_CONFIG_MSS_USER_CONFIG_H_ */ hart-software-services-2022.10/boards/aries-m100pfsevp/mpfs_hal_config/readme.txt000066400000000000000000000001261432224323300276540ustar00rootroot00000000000000contains user configuration of the platform e.g. division of memory between harts etc.hart-software-services-2022.10/boards/aries-m100pfsevp/soc_fpga_design/000077500000000000000000000000001432224323300256535ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/soc_fpga_design/xml/000077500000000000000000000000001432224323300264535ustar00rootroot00000000000000hart-software-services-2022.10/boards/aries-m100pfsevp/soc_fpga_design/xml/m100pfs_reference.xml000066400000000000000000011553001432224323300324060ustar00rootroot00000000000000 2021.2 mss_exp MPFS250T_ES FCVG484 09-28-2021_12:24:29 0.5.6 0x20220000 0x20220000 0x20220000 0x20220000 0x20220000 0x80000000 0xC0000000 0x1000000000 0x1400000000 0xD0000000 0x1800000000 0x00000000 0x00000000 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x4 0x00 0x0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0 220 0 511 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0xB 0xB 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0xC 0xC 0x7 0x7 0xF 0x7 0x7 0xF 0xF 0x5 0x5 0xF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xD 0x00 0xA 0x0 0x4 0x0 0x0920 0x0920 0x0920 0x0920 0x0920 0x0928 0x0928 0x0920 0x0920 0x0920 0x0920 0x0920 0x0520 0x09A8 0x7 0x00 0x9 0x0 0x8 0x0 0x0029 0x0029 0x0029 0x0029 0x0129 0x0129 0x0929 0x0929 0x0929 0x0929 0x0929 0x0929 0x0939 0x0939 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xF 0xF 0xF 0xF 0xF 0xB 0xB 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0xC 0xC 0x7 0x7 0xF 0x7 0x7 0xF 0xF 0x5 0x5 0xF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xD 0x00 0xA 0x0 0x4 0x0 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0520 0x09A8 0x7 0x00 0x9 0x0 0x8 0x0 0x0029 0x0029 0x0029 0x0029 0x0129 0x0129 0x0929 0x0929 0x0929 0x0929 0x0929 0x0929 0x0939 0x0939 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x2 0x9 0x1 0x1 0x0 0x1 0x1 0x8 0x0 0x0 0x0 0x0 0x01 0x01 0x0 0x0 0x014 0x0 0x2 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x7 0x7 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x7 0x7 0x0 0x0 0x0 0x8 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x3 0x0 0x3 0x0 0x0 0x1 0x1 0xf000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x7F 0x1F 0x02 0x3 0x16 0x1 0x0 0xE 0x1 0x0 0x0 0x2 0x2 0x2 0x2 0x6 0x6 0x7 0x7 0x7 0x3 0x4 0x3 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x2 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F80 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F70 0x0 0x1 0x0 0x0 0x1 0x7F60 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00000000 0x00000000 0x00000004 0x0000000A 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000140 0x000000A0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0xB 0xB 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x0 0x0 0x00000000 0x0 0x00000000 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x0 0x1 0x0 0x00000000 0x0 0x4 0x5 0x1 0x1 0x1E 0x5 0x6 0x2 0x6 0x7 0xB 0x11 0x118 0x0 0x0 0x0 0x81881881 0x00008818 0xa92a92a9 0x00002a92 0xc28c28c2 0x00008c28 0xea2ea2ea 0x00002ea2 0x03903903 0x00009039 0x2b32b32b 0x000032b3 0x44944944 0x00009449 0x6c36c36c 0x000036c3 0x85985985 0x00009859 0xad3ad3ad 0x00003ad3 0xc69c69c6 0x00009c69 0xee3ee3ee 0x00003ee3 0x07a07a07 0x0000a07a 0x2f42f42f 0x000042f4 0x48a48a48 0x0000a48a 0x70470470 0x00004704 0x00000000 0x0 0x0 0x0 0x0 0x0 0x00000000 0x1 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x1C 0xB 0x00000007 0xB 0x27 0x1C 0x00000076 0x6 0xC 0x00000008 0x00000000 0x00000003 0x00000024 0xB 0x2 0x2 0x2 0x1 0x4 0x2 0x2 0x1 0x7 0x00000010 0x0 0x1 0x0 0x2 0x0 0x1860 0x27100 0xA 0x10 0x3 0x00 0x00 0x0 0x0 0x0 0x0 0x0 0x0 0x00 0x00 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00000000 0x0 0x1 0x0 0x18 0x120 0x00000200 0x120 0x0 0xB 0x0 0x0 0x0 0x3 0x00000000 0x00000000 0x0 0x0 0x27100 0x0 0x80 0x0 0x1 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x000029B0 0x400 0x200 0x80 0x0000000b 0x00000002 0x00000010 0x00000000 0x00000009 0x0000000C 0x0 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x0 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000030 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x00000640 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000008 0x0000000b 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x00000000 0x00000001 0x000000FF 0x00000000 0x00000000 0x00000000 0x1 0x1 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x14 0x6 0x1 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x7FFFFFFF 0x0 0x7FFFFFFF 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x8001 0x1 0x1 0x00000000 0x00000000 0x00000000 0x2F 0x3F 0x00000000 0x00000000 0x00000000 0x18 0x00000000 0x1 0x00000000 0x00000000 0x1 125000000 600000000 600000000 1000000 300000000 150000000 1600000000 0x1 0x0 0x1 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x7D 0x6 0x0 0x0 0x1 0x0 0x1 0x40 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0x0 0xF 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xC0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x2 0x4 0x6 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x19 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 DDR3 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x80 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x10 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x5 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x3 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3 0x0 0x7 0x0 0xF 0x0 0x0 0x0 0x0 0x0 hart-software-services-2022.10/boards/aries-m100pfsevp/uart_helper.c000066400000000000000000000123001432224323300252130ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Implementation of uart_putstring/g(). * This is function is intended to be used from ee_printf(). */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include #include #include "uart_helper.h" static inline mss_uart_instance_t *get_uart_instance(int hartid) { mss_uart_instance_t *pUart; switch (hartid) { default: pUart = &g_mss_uart0_lo; break; case HSS_HART_E51: pUart = &g_mss_uart0_lo; break; case HSS_HART_U54_1: pUart = &g_mss_uart1_lo; break; case HSS_HART_U54_2: pUart = &g_mss_uart2_lo; break; case HSS_HART_U54_3: pUart = &g_mss_uart3_lo; break; case HSS_HART_U54_4: pUart = &g_mss_uart4_lo; break; } return pUart; } int uart_putstring(int hartid, char *p) { const uint32_t len = (uint32_t)strlen(p); mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)p); // TODO: if hartId is zero (i.e., E51), replace this with non-blocking // queue implementation, with HSS_UART state machine consuming from queues... return len; } void uart_putc(int hartid, const char ch) { uint8_t string[2]; string[0] = (uint8_t)ch; string[1] = 0u; mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)string); } ssize_t uart_getline(char **pBuffer, size_t *pBufLen) { ssize_t result = 0; bool finished = false; static char myBuffer[HSS_UART_HELPER_MAX_GETLINE]; // static to be stack friendly const size_t bufferLen = ARRAY_SIZE(myBuffer); memset(myBuffer, 0, bufferLen); uint8_t cBuf[1]; while (!finished) { while (0 == MSS_UART_get_rx(&g_mss_uart0_lo, cBuf, 1)); switch (cBuf[0]) { case '\r': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case '\n': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case 0x7Fu: // delete if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[D \033[D", 7u); myBuffer[result] = 0; } break; case 0x08u: // backspace - ^H if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)" \033[D", 4u); myBuffer[result] = 0; } break; case 0x03u: // intr - ^C result = -1; myBuffer[0] = 0; finished = true; break; case 0x1Bu: // ESC result = -1; myBuffer[0] = 0; finished = true; break; case 0x04u: // ^D if (result == 0) { result = -1; myBuffer[0] = 0; finished = true; } break; default: if (result < bufferLen) { MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); myBuffer[result] = cBuf[0]; result++; } break; } } const char crlf[] = "\n"; MSS_UART_polled_tx_string(&g_mss_uart0_lo, (const uint8_t *)crlf); if (result > 0) { *pBuffer = myBuffer; *pBufLen = (size_t)result; } else { *pBuffer = NULL; *pBufLen = 0u; } return result; } bool uart_getchar(uint8_t *pbuf, int32_t timeout_sec, bool do_sec_tick) { bool result = false; bool done = false; uint8_t rx_buff[1]; HSSTicks_t start_time = 0u; HSSTicks_t last_sec_time = 0u; start_time = last_sec_time = HSS_GetTime(); const HSSTicks_t timeout_ticks = timeout_sec * TICKS_PER_SEC; while (!done) { size_t received = MSS_UART_get_rx(&g_mss_uart0_lo, rx_buff, 1u); if (0u != received) { done = true; if (MSS_UART_NO_ERROR == MSS_UART_get_rx_status(&g_mss_uart0_lo)) { *pbuf = rx_buff[0]; result = true; break; } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "UART error\n"); } } if (do_sec_tick && HSS_Timer_IsElapsed(last_sec_time, TICKS_PER_SEC)) { const uint8_t dot='.'; MSS_UART_polled_tx(&g_mss_uart0_lo, &dot, 1); last_sec_time = HSS_GetTime(); } if (timeout_sec < 0) { ; // blocking until UART data received, so nothing extra to do here... } else if (timeout_sec > 0) { // time limited done = HSS_Timer_IsElapsed(start_time, timeout_ticks); } else /* timeout == 0 */ { // one-shot break; } } return result; } hart-software-services-2022.10/boards/custom-board-design/000077500000000000000000000000001432224323300234055ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/Kconfig000066400000000000000000000003511432224323300247070ustar00rootroot00000000000000menu "Design Configuration Options" config SOC_FPGA_DESIGN_XML string "Enter path to Libero XML file" default "boards/$(BOARD)/soc_fpga_design/xml/design_cfg.xml" help This option specifies the design XML file to use. endmenu hart-software-services-2022.10/boards/custom-board-design/Makefile000066400000000000000000000122171432224323300250500ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Defines target-specific build-rules variables, extra sources and include paths # $(info custom-board-design selected) BINDIR=Default TARGET-l2scratch=hss-l2scratch.elf TARGET-envm-wrapper=hss-envm-wrapper.elf RISCV_TARGET=$(TARGET-l2scratch) $(TARGET-envm-wrapper) TARGET:=$(RISCV_TARGET) LINKER_SCRIPT-l2scratch=boards/${BOARD}/hss-l2scratch.ld CONFIG_PLATFORM_MPFS=y PLATFORM_CFLAGS += -DCONFIG_PLATFORM_MPFS=1 BOARD_DIR=boards/custom-board-design INCLUDES += \ -I$(BOARD_DIR)/mpfs_hal_config/\ -I$(BOARD_DIR)/fpga_design_config/\ -I$(BOARD_DIR)/ \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform \ EXTRA_SRCS-y += \ $(BOARD_DIR)/hss_uart_init.c \ $(BOARD_DIR)/uart_helper.c \ $(BOARD_DIR)/hss_board_init.c \ EXTRA_SRCS-$(CONFIG_USE_LOGO) += \ $(BOARD_DIR)/hss_logo_init.c $(BOARD_DIR)/hss_uart_init.o: CFLAGS=$(CFLAGS_GCCEXT) EXTRA_OBJS-$(CONFIG_SERVICE_BOOT_USE_PAYLOAD) += $(BOARD_DIR)/payload.o $(BOARD_DIR)/payload.o: $(BOARD_DIR)/payload.bin $(LD) -r -b binary $< -o $@ ################################################################################################ # # Extra hardware dependency rules for QSPI # INCLUDES += \ -Ibaremetal/ \ -Ibaremetal/drivers/winbond_w25n01gv \ baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.o: CFLAGS=$(CFLAGS_GCCEXT) ################################################################################################ # # Linker Scripts # $(BOARD_DIR)/hss-l2scratch.ld: $(BOARD_DIR)/hss-l2scratch.lds config.h ################################################################################################ # # Extra dependency rules for auto-generated configuration files (from Libero XML) # SOC_CONFIG_FILES = \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_ddr_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sysreg.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_mss_clks.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_io_bank.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_off_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_options.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_segs.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddrc.h \ $(BOARD_DIR)/fpga_design_config/general/hw_gen_peripherals.h \ $(BOARD_DIR)/fpga_design_config/fpga_design_config.h \ $(BOARD_DIR)/fpga_design_config/io/hw_hsio_mux.h \ $(BOARD_DIR)/fpga_design_config/io/hw_mssio_mux.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_apb_split.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_cache.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_memory.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_crypto.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_mmc.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_scb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_trace.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_usb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart3.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart4.h \ $(BOARD_DIR)/fpga_design_config/sgmii/hw_sgmii_tip.h \ config.h: $(SOC_CONFIG_FILES) $(SOC_CONFIG_FILES): $(subst $\",,$(CONFIG_SOC_FPGA_DESIGN_XML)) @$(ECHO) " MPFSCFGGEN $<"; $(PYTHON) tools/polarfire-soc-configuration-generator/mpfs_configuration_generator.py $< $(BOARD_DIR) $(RISCV_TARGET): $(SOC_CONFIG_FILES) hart-software-services-2022.10/boards/custom-board-design/def_config000066400000000000000000000062111432224323300254130ustar00rootroot00000000000000 # # Board/Design Configuration Options # # # Custom Board Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/custom-board-design/soc_fpga_design/xml/custom_design_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # CONFIG_MEMTEST=y CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # end of Debug Options # # SSMB Options # CONFIG_HSS_USE_IHC=y CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/custom-board-design/drivers_config/000077500000000000000000000000001432224323300264105ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/drivers_config/fpga_ip/000077500000000000000000000000001432224323300300155ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/drivers_config/fpga_ip/miv_ihc/000077500000000000000000000000001432224323300314335ustar00rootroot00000000000000miv_ihc_add_mapping.h000066400000000000000000000105461432224323300354740ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IHC driver @section intro_sec Introduction Used to configure the driver with base addresses from your Libero Projext. These addresses will not change unless you change the Libero design IHC subsytem design. This file is used for reference only. When usiing in a project copy to src/boards/your-board/platform-config/drivers_config/fpga-ip/miv_ihc and rename dropping the _reference. @section *//*==========================================================================*/ #ifndef MIV_IHC_ADD_MAPPING_H_ #define MIV_IHC_ADD_MAPPING_H_ #ifndef COMMON_AHB_BASE_ADD #define COMMON_AHB_BASE_ADD 0x50000000UL #endif #ifndef IHC_HO_BASE_OFFSET #define IHC_HO_BASE_OFFSET 0x00000000UL #endif #ifndef IHC_H1_BASE_OFFSET #define IHC_H1_BASE_OFFSET 0x00000500UL #endif #ifndef IHC_H2_BASE_OFFSET #define IHC_H2_BASE_OFFSET 0x00000A00UL #endif #ifndef IHC_H3_BASE_OFFSET #define IHC_H3_BASE_OFFSET 0x00000F00UL #endif #ifndef IHC_H4_BASE_OFFSET #define IHC_H4_BASE_OFFSET 0x00001400UL #endif /************** My Hart 0 ************/ #ifndef IHC_LOCAL_H0_REMOTE_H1 #define IHC_LOCAL_H0_REMOTE_H1 0x50000000 #endif #ifndef IHC_LOCAL_H0_REMOTE_H2 #define IHC_LOCAL_H0_REMOTE_H2 0x50000100 #endif #ifndef IHC_LOCAL_H0_REMOTE_H3 #define IHC_LOCAL_H0_REMOTE_H3 0x50000200 #endif #ifndef IHC_LOCAL_H0_REMOTE_H4 #define IHC_LOCAL_H0_REMOTE_H4 0x50000300 #endif #ifndef IHCIA_LOCAL_H0 #define IHCIA_LOCAL_H0 0x50000400 #endif /************** My Hart 1 ************/ #ifndef IHC_LOCAL_H1_REMOTE_H0 #define IHC_LOCAL_H1_REMOTE_H0 0x50000500 #endif #ifndef IHC_LOCAL_H1_REMOTE_H2 #define IHC_LOCAL_H1_REMOTE_H2 0x50000600 #endif #ifndef IHC_LOCAL_H1_REMOTE_H3 #define IHC_LOCAL_H1_REMOTE_H3 0x50000700 #endif #ifndef IHC_LOCAL_H1_REMOTE_H4 #define IHC_LOCAL_H1_REMOTE_H4 0x50000800 #endif #ifndef IHCIA_LOCAL_H1 #define IHCIA_LOCAL_H1 0x50000900 #endif /************** My Hart 2 ************/ #ifndef IHC_LOCAL_H2_REMOTE_H0 #define IHC_LOCAL_H2_REMOTE_H0 0x50000A00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H1 #define IHC_LOCAL_H2_REMOTE_H1 0x50000B00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H3 #define IHC_LOCAL_H2_REMOTE_H3 0x50000C00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H4 #define IHC_LOCAL_H2_REMOTE_H4 0x50000D00 #endif #ifndef IHCIA_LOCAL_H2 #define IHCIA_LOCAL_H2 0x50000E00 #endif /************** My Hart 3 ************/ #ifndef IHC_LOCAL_H3_REMOTE_H0 #define IHC_LOCAL_H3_REMOTE_H0 0x50000F00 #endif #ifndef IHC_LOCAL_H3_REMOTE_H1 #define IHC_LOCAL_H3_REMOTE_H1 0x50001000 #endif #ifndef IHC_LOCAL_H3_REMOTE_H2 #define IHC_LOCAL_H3_REMOTE_H2 0x50001100 #endif #ifndef IHC_LOCAL_H3_REMOTE_H4 #define IHC_LOCAL_H3_REMOTE_H4 0x50001200 #endif #ifndef IHCIA_LOCAL_H3 #define IHCIA_LOCAL_H3 0x50001300 #endif /************** My Hart 4 ************/ #ifndef IHC_LOCAL_H4_REMOTE_H0 #define IHC_LOCAL_H4_REMOTE_H0 0x50001400 #endif #ifndef IHC_LOCAL_H4_REMOTE_H1 #define IHC_LOCAL_H4_REMOTE_H1 0x50001500 #endif #ifndef IHC_LOCAL_H4_REMOTE_H2 #define IHC_LOCAL_H4_REMOTE_H2 0x50001600 #endif #ifndef IHC_LOCAL_H4_REMOTE_H3 #define IHC_LOCAL_H4_REMOTE_H3 0x50001700 #endif #ifndef IHCIA_LOCAL_H4 #define IHCIA_LOCAL_H4 0x50001800 #endif /*------------------------------------------------------------------------------ * choose the interrupt mapping used in our system * Please see miv_ihc_regs.h for the defaults */ #define IHCIA_hart0_IRQHandler fabric_f2h_63_plic_IRQHandler #define IHCIA_hart1_IRQHandler fabric_f2h_62_plic_IRQHandler #define IHCIA_hart2_IRQHandler fabric_f2h_61_plic_IRQHandler #define IHCIA_hart3_IRQHandler fabric_f2h_60_plic_IRQHandler #define IHCIA_hart4_IRQHandler fabric_f2h_59_plic_IRQHandler #define IHCIA_hart0_INT FABRIC_F2H_63_PLIC #define IHCIA_hart1_INT FABRIC_F2H_62_PLIC #define IHCIA_hart2_INT FABRIC_F2H_61_PLIC #define IHCIA_hart3_INT FABRIC_F2H_60_PLIC #define IHCIA_hart4_INT FABRIC_F2H_59_PLIC #endif /* MIV_IHC_ADD_MAPPING_H_ */ miv_ihc_config.h000066400000000000000000000045401432224323300344730ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IhC driver @section intro_sec Introduction Used to configure the driver @section *//*==========================================================================*/ #ifndef MIV_IHC_CONFIG_H_ #define MIV_IHC_CONFIG_H_ #include "miv_ihc_add_mapping.h" /*------------------------------------------------------------------------------ * define the monitor hart (HSS hart) used in our system */ #define HSS_HART_MASK HART0_MASK #define HSS_HART_ID HART0_ID /*------------------------------------------------------------------------------ * HSS_REMOTE_HARTS_MASK * This is used to define the harts the HSS is communicating with */ #define HSS_REMOTE_HARTS_MASK (HART1_MASK | HART2_MASK |HART3_MASK | HART4_MASK) /*------------------------------------------------------------------------------ * Define which harts are connected via comms channels to a particular hart * user defined */ #define IHCIA_H0_REMOTE_HARTS (HSS_REMOTE_HARTS_MASK) /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS (HSS_HART_MASK | HART4_MASK) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H3_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H4_REMOTE_HARTS (HSS_HART_MASK | HART1_MASK) /* HSS and Context A connected */ /*------------------------------------------------------------------------------ * interrupts enabled in this system design for a particular hart * User defined */ #define IHCIA_H0_REMOTE_HARTS_INTS HSS_HART_DEFAULT_INT_EN /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART4_MP_INT_EN | HART4_ACK_INT_EN) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H3_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H4_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART1_MP_INT_EN | HART1_ACK_INT_EN) /* HSS and Context A connected */ #endif /* MIV_IHC_CONFIG_H_ */ hart-software-services-2022.10/boards/custom-board-design/hss-l2scratch.lds000066400000000000000000000271141432224323300265760ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip Corporation. * * SPDX-License-Identifier: MIT * * GNU linker script for Hart Software Services (HSS) * */ #include "config.h" OUTPUT_ARCH( "riscv" ) /* PolarFire SoC Memory map (ditaa diagram) ---------------------------------------- +-------------+ +-----------+ | non-cache | | non-cache | | WCB (SEG1) | +---------------------+ | (SEG1) | 0x18_0000_0000 +-------------+ | DDR cached | 0x14_0000_0000 +-----------+ | non-cache | | (SEG0) | | non-cache | | WCB (SEG1) | 0x10_0000_0000 +---------------------+ | (SEG1) | 0xD000_0000 +-------------+ | DDR cached | 0xC000_0000 +-----------+ | (SEG0) | 0x8000_0000 +---------------------+ | envm (128KiB) | | | 0x2022_0100 +---------------------+ | Zero Device | | | 0x0A00_0000 +---------------------+ | | 0x0820_0000 +---------------------+ | LIM (up to 1920KiB) | | | 0x0800_0000 +---------------------+ | U54_4 ITIM (28KiB) | | | 0x0182_0000 +---------------------+ | U54_3 ITIM (28KiB) | | | 0x0181_8000 +---------------------+ | U54_2 ITIM (28KiB) | | | 0x0181_0000 +---------------------+ | U54_1 ITIM (28KiB) | | | 0x0180_8000 +---------------------+ | E51 ITIM (28KiB) | | | 0x0180_0000 +---------------------+ | DTIM (8KiB) | | | 0x0100_0000 +---------------------+ | Debug | 0x0000_0000 +---------------------+ */ /******************************************************************************* * * -- MSS hart Reset vector * * The MSS reset vector for each hart is configured by Libero and stored securely * in the MPFS. * * The most common usage will be where the reset vector for each hart will be set * to the start of the envm at address 0x2022_0100, giving (128KiB-256bytes) * of contiguous non-volatile storage. Normally this is where the initial * boot-loader will reside. * * Libero outputs the configured reset vector address to the xml file, see * LIBERO_SETTING_RESET_VECTOR_HART0 etc in * * When debugging a bare metal program that is run out of reset from envm, a linker * script will be used whereby the progdtim will run from LIM instead of envm. * In this case, set the reset vector in the linker script to 0x0800_0000. * This means you are not continually programming the envm each time you load a * program and there is no limitation with hardware break points whn debugging. */ ENTRY(_start) /******************************************************************************* * * Memory Segments * * must be on 4k boundary (0x1000) - corresponds to page size, when using memory mem */ MEMORY { envm (rx) : ORIGIN = 0x20220100, LENGTH = (128k-256) dtim (rwx) : ORIGIN = 0x01000000, LENGTH = 7k /* DTIM */ switch_code (rx) : ORIGIN = 0x01001c00, LENGTH = 1k /* This 1K of DTIM is used to run code * when switching the envm clock */ e51_itim (rwx) : ORIGIN = 0x01800000, LENGTH = 28k u54_1_itim (rwx) : ORIGIN = 0x01808000, LENGTH = 28k u54_2_itim (rwx) : ORIGIN = 0x01810000, LENGTH = 28k u54_3_itim (rwx) : ORIGIN = 0x01818000, LENGTH = 28k u54_4_itim (rwx) : ORIGIN = 0x01820000, LENGTH = 28k l2lim (rwx) : ORIGIN = 0x08000000, LENGTH = 512k l2zerodevice (rwx) : ORIGIN = 0x0A000000, LENGTH = 512k ddr (rwx) : ORIGIN = 0x80000000, LENGTH = 32m ddrhi (rwx) : ORIGIN = 0x1000000000, LENGTH = 1888m ncddrhi (rwx) : ORIGIN = 0x1400000000, LENGTH = 2048m } PROVIDE(HEAP_SIZE = 0k); PROVIDE(STACK_SIZE_PER_HART = 16k); /******************************************************************************* * * Memory Sections and Placement */ SECTIONS { PROVIDE(__envm_start = ORIGIN(envm)); PROVIDE(__envm_end = ORIGIN(envm) + LENGTH(envm)); PROVIDE(__l2lim_start = ORIGIN(l2lim)); PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); PROVIDE(__l2_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); PROVIDE(__ddr_start = ORIGIN(ddr)); PROVIDE(__ddr_end = ORIGIN(ddr) + LENGTH(ddr)); PROVIDE(__ddrhi_start = ORIGIN(ddrhi)); PROVIDE(__ddrhi_end = ORIGIN(ddrhi) + LENGTH(ddrhi)); PROVIDE(__ncddrhi_start = ORIGIN(ncddrhi)); PROVIDE(__ncddrhi_end = ORIGIN(ncddrhi) + LENGTH(ncddrhi)); PROVIDE(__dtim_start = ORIGIN(dtim)); PROVIDE(__dtim_end = ORIGIN(dtim) + LENGTH(dtim)); PROVIDE(__e51itim_start = ORIGIN(e51_itim)); PROVIDE(__e51itim_end = ORIGIN(e51_itim) + LENGTH(e51_itim)); PROVIDE(__u54_1_itim_start = ORIGIN(u54_1_itim)); PROVIDE(__u54_1_itim_end = ORIGIN(u54_1_itim) + LENGTH(u54_1_itim)); PROVIDE(__u54_2_itim_start = ORIGIN(u54_2_itim)); PROVIDE(__u54_2_itim_end = ORIGIN(u54_2_itim) + LENGTH(u54_2_itim)); PROVIDE(__u54_3_itim_start = ORIGIN(u54_3_itim)); PROVIDE(__u54_3_itim_end = ORIGIN(u54_3_itim) + LENGTH(u54_3_itim)); PROVIDE(__u54_4_itim_start = ORIGIN(u54_4_itim)); PROVIDE(__u54_4_itim_end = ORIGIN(u54_4_itim) + LENGTH(u54_4_itim)); /* * Code and RO data lives in l2lim */ . = __l2_start; PROVIDE(_hss_start = .); PROVIDE(__l2_scratchpad_vma_start = .); .text : ALIGN(0x10) { *(.entry) . = ALIGN(0x10); *(.text .text.* .gnu.linkonce.t.*) *(.plt) . = ALIGN(0x10); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) *(.sdata2*) *(.gcc_except_table) *(.eh_frame_hdr) *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(0x10); } >l2zerodevice .gnu_build_id : ALIGN(8) { PROVIDE(gnu_build_id = .); *(.note.gnu.build-id) } >l2zerodevice PROVIDE(_hss_end = .); /******************************************************************************* * * The .ram_code section will contain the code That is run from RAM. * We are using this code to switch the clocks including envm clock. * This can not be done when running from envm * This will need to be copied to ram, before any of this code is run. * */ .ram_code : ALIGN(0x10) { __sc_load = LOADADDR (.ram_code); __sc_start = .; *(.ram_codetext) /* .ram_codetext sections (code) */ *(.ram_codetext*) /* .ram_codetext* sections (code) */ *(.ram_coderodata) /* read-only data (constants) */ *(.ram_coderodata*) . = ALIGN (0x10); __sc_end = .; } >switch_code /******************************************************************************* * * Short/global data section * */ .sdata : ALIGN(0x40) /* short/global data section */ { __sdata_load = LOADADDR(.sdata); __sdata_start = .; /* * offset used with gp(gloabl pointer) are +/- 12 bits, so set * point to middle of expected sdata range * * If sdata more than 4K, linker used direct addressing. * Perhaps we should add check/warning to linker script if sdata is > 4k */ __global_pointer$ = . + 0x800; *(.sdata .sdata.* .gnu.linkonce.s.*) . = ALIGN(0x10); __sdata_end = .; } >l2zerodevice /******************************************************************************* * * (Explicitly) Initialized data section * */ #ifdef CONFIG_SERVICE_BOOT_USE_PAYLOAD .data.payload : ALIGN(16) { _payload_start = .; KEEP(boards/mpfs-icicle-kit-es/payload.o(.*)) _payload_end = .; } #endif .data : ALIGN(0x40) { __data_load = LOADADDR(.data); __data_start = .; *(.got.plt) *(.got) *(.shdata) *(.data .data.* .gnu.linkonce.d.*) . = ALIGN(0x10); __data_end = .; } >l2zerodevice /******************************************************************************* * * Uninitialized (zero-initialized) section */ /* * Short zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. * */ .sbss : ALIGN(0x40) { __sbss_start = .; *(.sbss .sbss.* .gnu.linkonce.sb.*) *(.scommon) . = ALIGN(0x10); __sbss_end = .; } >l2zerodevice /* * General Zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. */ .bss : ALIGN(0x40) { __bss_start = .; *(.shbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(0x10); __bss_end = .; } >l2zerodevice /* * Reserved space for Hart stacks */ .stack : ALIGN(0x40) { __stack_bottom = .; __stack_bottom_h0$ = .; . += STACK_SIZE_PER_HART; __stack_top_h0$ = . - 8; __stack_bottom_h1$ = .; . += STACK_SIZE_PER_HART; __stack_top_h1$ = . - 8; __stack_bottom_h2$ = .; . += STACK_SIZE_PER_HART; __stack_top_h2$ = . - 8; __stack_bottom_h3$ = .; . += STACK_SIZE_PER_HART; __stack_top_h3$ = . - 8; __stack_bottom_h4$ = .; . += STACK_SIZE_PER_HART; __stack_top_h4$ = . - 8; __stack_top = .; } >l2zerodevice _end = .; PROVIDE(__l2_scratchpad_vma_end = .); /* * End of uninitialized data segment * *******************************************************************************/ /* .heap : ALIGN(0x10) { __heap_start = .; . += HEAP_SIZE; __heap_end = .; . = ALIGN(0x10); _heap_end = __heap_end; } >dtim */ } hart-software-services-2022.10/boards/custom-board-design/hss_board_init.c000066400000000000000000000040071432224323300265410ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Board Initalization * \brief Board Initialization */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "hss_init.h" #include "hss_state_machine.h" #include "ssmb_ipi.h" #include "hss_registry.h" /******************************************************************************************************/ /*! * \brief Board Init Function Registration Table * * The following structure is used to connect in new board init functions. */ #include "hss_init.h" #include "hss_boot_pmp.h" #include "hss_sys_setup.h" #include "hss_board_init.h" const struct InitFunction /*@null@*/ boardInitFunctions[] = { // Name FunctionPointer Halt Restart { "HSS_ZeroTIMs", HSS_ZeroTIMs, false, false }, { "HSS_Setup_BusErrorUnit", HSS_Setup_BusErrorUnit, false, false }, { "HSS_Setup_MPU", HSS_Setup_MPU, false, false }, { "HSS_DDRInit", HSS_DDRInit, false, false }, { "HSS_ZeroDDR", HSS_ZeroDDR, false, false }, #ifdef CONFIG_USE_PCIE { "HSS_PCIeInit", HSS_PCIeInit, false, false }, #endif //{ "HSS_USBInit", HSS_USBInit, false, false }, // if using 64-bit upper memory only, uncomment this }; /******************************************************************************************************/ /** * \brief Board Initialization Function * * All other initialization routines to be chained off this... */ /****************************************************************************/ #include "mss_sysreg.h" bool HSS_BoardInit(void) { RunInitFunctions(ARRAY_SIZE(boardInitFunctions), boardInitFunctions); return true; } bool HSS_BoardLateInit(void) { return true; } hart-software-services-2022.10/boards/custom-board-design/hss_logo_init.c000066400000000000000000000177321432224323300264230ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Software Initalization * \brief Full System Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "hss_debug.h" // // A variety of colored pixels are needed - red, white, black // define these as ASCII characters if color output is not enabled // #if IS_ENABLED(CONFIG_COLOR_OUTPUT) # if IS_ENABLED(CONFIG_LOGO_INVERT_COLORS) const char B0_str[] ="\033[48;5;188m "; const char W0_str[] ="\033[0m "; const char r1_str[] ="\033[48;5;217m "; const char r2_str[] ="\033[48;5;210m "; const char r3_str[] ="\033[48;5;203m "; const char r4_str[] ="\033[48;5;196m "; const char b1_str[] ="\033[48;5;188m "; const char b2_str[] ="\033[48;5;145m "; const char b3_str[] ="\033[48;5;102m "; const char b4_str[] ="\033[48;5;59m "; # else const char B0_str[] = "\033[48;5;188m "; const char W0_str[] = "\033[48;5;188m "; const char r1_str[] ="\033[48;5;217m "; const char r2_str[] ="\033[48;5;210m "; const char r3_str[] ="\033[48;5;203m "; const char r4_str[] ="\033[48;5;196m "; const char b1_str[] ="\033[48;5;16m "; const char b2_str[] ="\033[48;5;59m "; const char b3_str[] ="\033[48;5;102m "; const char b4_str[] ="\033[48;5;145m "; # endif const char RST_str[] ="\033[0m"; #else const char B0_str[] =" "; const char W0_str[] =" "; const char r1_str[] ="."; const char r2_str[] ="-"; const char r3_str[] ="x"; const char r4_str[] ="X"; const char b1_str[] =":"; const char b2_str[] ="o"; const char b3_str[] ="0"; const char b4_str[] ="O"; const char RST_str[] =""; #endif enum Color { B0 = 0, W0, r1, r2, r3, r4, b1, b2, b3, b4, RST, CRLF_token, }; const char* tokenStringTable[] = { B0_str, W0_str, r1_str, r2_str, r3_str, r4_str, b1_str, b2_str, b3_str, b4_str, RST_str, "\n", }; // RLE Microchip Logo, built up from our color pixel primitives above... // RLE shrinks the size of this const struct __attribute__((packed)) { uint8_t const count; enum Color const tokenIndex; } rleLogoElements[] = { { 4, W0 }, { 1, r1 }, { 1, r3 }, { 7, r4 }, { 62, W0 }, { 1, RST }, { 1, CRLF_token }, { 3, W0 }, { 1, r2 }, { 9, r4 }, { 1, r3 }, { 61, W0 }, { 1, RST }, { 1, CRLF_token }, { 2, W0 }, { 1, r3 }, { 2, r4 }, { 1, r3 }, { 1, r2 }, { 5, r4 }, { 1, r2 }, { 1, r4 }, { 1, r1 }, { 7, W0 }, { 1, b3 }, { 5, W0 }, { 1, b3 }, { 46, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, { 1, r1 }, { 3, r4 }, { 2, B0 }, { 1, r2 }, { 3, r4 }, { 1, r1 }, { 1, B0 }, { 1, r1 }, { 1, r4 }, { 6, W0 }, { 1, b4 }, { 1, b1 }, { 1, b2 }, { 3, W0 }, { 1, b3 }, { 1, b1 }, { 1, b4 }, { 45, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, { 3, r4 }, { 1, r1 }, { 3, B0 }, { 2, r4 }, { 1, r2 }, { 3, B0 }, { 2, r3 }, { 5, W0 }, { 1, b4 }, { 2, b1 }, { 3, W0 }, { 2, b1 }, { 1, b4 }, { 1, W0 }, { 1, b4 }, { 2, W0 }, { 1, b4 }, { 3, b3 }, { 1, b4 }, { 1, W0 }, { 5, b4 }, { 2, W0 }, { 1, b4 }, { 3, b3 }, { 1, b4 }, { 2, W0 }, { 1, b4 }, { 3, b3 }, { 1, b4 }, { 1, W0 }, { 1, b4 }, { 3, W0 }, { 1, b4 }, { 2, W0 }, { 1, b4 }, { 1, W0 }, { 5, b4 }, { 1, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, r1 }, { 3, r4 }, { 4, B0 }, { 1, r1 }, { 1, r4 }, { 5, B0 }, { 1, r4 }, { 1, r1 }, { 4, W0 }, { 1, b3 }, { 2, b1 }, { 1, b4 }, { 1, W0 }, { 1, b4 }, { 2, b1 }, { 1, b3 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 1, W0 }, { 5, b1 }, { 1, W0 }, { 5, b1 }, { 1, b3 }, { 1, W0 }, { 5, b1 }, { 1, b4 }, { 1, W0 }, { 5, b1 }, { 1, W0 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 5, b1 }, { 1, b3 }, { 1, RST }, { 1, CRLF_token }, { 1, r2 }, { 2, r4 }, { 1, r3 }, { 1, r2 }, { 4, B0 }, { 1, r3 }, { 1, r2 }, { 4, B0 }, { 1, r2 }, { 1, r4 }, { 4, W0 }, { 1, b3 }, { 3, b2 }, { 1, W0 }, { 2, b2 }, { 1, b3 }, { 1, b2 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b1 }, { 5, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 1, b2 }, { 1, b4 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, b4 }, { 1, b1 }, { 5, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 1, b2 }, { 1, RST }, { 1, CRLF_token }, { 1, r3 }, { 1, r4 }, { 1, r1 }, { 1, B0 }, { 1, r4 }, { 5, B0 }, { 1, r4 }, { 5, B0 }, { 1, r4 }, { 1, r2 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 1, b1 }, { 1, b4 }, { 1, b3 }, { 1, b2 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b2 }, { 5, W0 }, { 1, b1 }, { 1, b3 }, { 2, W0 }, { 2, b3 }, { 1, b4 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, b4 }, { 1, b2 }, { 5, W0 }, { 5, b1 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 1, b2 }, { 1, RST }, { 1, CRLF_token }, { 1, r3 }, { 1, r2 }, { 2, B0 }, { 1, r2 }, { 1, r3 }, { 4, B0 }, { 1, r1 }, { 1, r3 }, { 4, B0 }, { 1, r1 }, { 1, r4 }, { 3, W0 }, { 1, b1 }, { 1, b3 }, { 1, W0 }, { 3, b1 }, { 1, W0 }, { 1, b4 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b2 }, { 5, W0 }, { 5, b1 }, { 1, W0 }, { 1, b4 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, b4 }, { 1, b2 }, { 5, W0 }, { 1, b1 }, { 1, b3 }, { 2, b4 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 5, b1 }, { 1, b3 }, { 1, RST }, { 1, CRLF_token }, { 1, r1 }, { 4, B0 }, { 1, r4 }, { 1, r1 }, { 4, B0 }, { 1, r3 }, { 1, r2 }, { 4, B0 }, { 1, r3 }, { 3, W0 }, { 1, b1 }, { 1, b4 }, { 1, W0 }, { 1, b3 }, { 1, b1 }, { 1, b3 }, { 1, W0 }, { 1, b4 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b1 }, { 4, b4 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 2, W0 }, { 1, b2 }, { 1, b3 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 2, b4 }, { 1, b1 }, { 1, b3 }, { 1, b4 }, { 1, b1 }, { 4, b4 }, { 1, W0 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 2, b4 }, { 2, W0 }, { 1, RST }, { 1, CRLF_token }, { 5, B0 }, { 1, r3 }, { 1, r4 }, { 4, B0 }, { 1, r1 }, { 1, r4 }, { 5, B0 }, { 3, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 3, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 1, W0 }, { 5, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 2, b3 }, { 1, W0 }, { 1, b2 }, { 4, b1 }, { 2, W0 }, { 5, b1 }, { 1, W0 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 5, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, { 3, B0 }, { 1, r2 }, { 2, r4 }, { 1, r2 }, { 3, B0 }, { 1, r3 }, { 1, r4 }, { 1, r3 }, {2, B0 }, {1, B0}, { 58, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, {1, r1}, { 2, B0 }, { 4, r4 }, { 2, B0 }, { 1, r1 }, { 3, r4 }, { 1, r1 }, {1, B0 }, {1, r1}, { 58, W0 }, { 1, RST }, { 1, CRLF_token }, { 2, W0 }, {1, r2}, { 5, r4 }, { 1, r3 }, { 1, r1 }, { 5, r4 }, {1, r3}, { 59, W0 }, { 1, RST }, { 1, CRLF_token }, { 3, W0 }, { 1, r2 }, { 11, r4 }, { 60, W0 }, { 1, RST }, { 1, CRLF_token }, { 4, W0 }, { 1, r1 }, { 1, r3 }, { 7, r4 }, { 1, r3 }, { 61, W0 }, { 1, RST }, {1, CRLF_token} }; bool HSS_LogoInit(void) { mHSS_PUTS("\n"); int i; // decode and output our RLE Logo for (i = 0; i < ARRAY_SIZE(rleLogoElements); i++) { uint8_t j; for (j = 0u; j < rleLogoElements[i].count; j++) { mHSS_PUTS(tokenStringTable[rleLogoElements[i].tokenIndex]); } } mHSS_PUTS("\n" "-------------------------\n" "-- Custom Board Design --\n" "-- PolarFire SoC FPGA --\n" "-------------------------\n" "\n"); return true; } hart-software-services-2022.10/boards/custom-board-design/hss_uart_init.c000066400000000000000000000025501432224323300264260ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Debug UART Initalization * \brief Debug UART Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" bool HSS_UARTInit(void) { // initialise debug UART #if IS_ENABLED(CONFIG_PLATFORM_MPFS) MSS_UART_init(&g_mss_uart0_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); // default all UARTs to 115200 for now // subsequent OS loads can change these if needed... MSS_UART_init(&g_mss_uart1_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart2_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart3_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart4_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); #else # error Unknown PLATFORM #endif return true; } hart-software-services-2022.10/boards/custom-board-design/mpfs_hal_config/000077500000000000000000000000001432224323300265235ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/mpfs_hal_config/mss_sw_config.h000066400000000000000000000172261432224323300315440ustar00rootroot00000000000000#ifndef MSS_SW_CONFIG_H_ #define MSS_SW_CONFIG_H_ /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * Platform definitions * Version based on requirements of MPFS MSS * */ /*========================================================================*//** @mainpage Sample file detailing how mss_sw_config.h should be constructed for the MPFS MSS @section intro_sec Introduction The mss_sw_config.h has the default software configuration settings for the MPFS HAL and will be located at /src/platform/platform_config_reference folder of the bare metal SoftConsole project. The platform_config_reference is provided as a default reference configuration. When you want to configure the MPFS HAL with required configuration for your project, the mss_sw_config.h must be edited and be placed in the following project directory: /src/boards//platform_config/mpfs_hal_config/ @section *//*==========================================================================*/ /* * Include any driver setup/over-rides you may require. */ #include "drivers/fpga_ip/miv_ihc/miv_ihc_defines.h" #include "drivers_config/fpga_ip/miv_ihc/miv_ihc_config.h" /* * MPFS_HAL_FIRST_HART and MPFS_HAL_LAST_HART defines are used to specify which * harts to actually start. The value and the actual hart it represents are * listed below: * value hart * 0 E51 * 1 U54_1 * 2 U54_2 * 3 U54_3 * 4 U54_4 * Set MPFS_HAL_FIRST_HART to a value greater than 0 if you do not want your * application to start and execute code on the harts represented by smaller * value numbers. * Set MPFS_HAL_LAST_HART to a value smaller than 4 if you do not wish to use * all U54_x harts. * Harts that are not started will remain in an infinite WFI loop unless used * through some other method. * The value of MPFS_HAL_FIRST_HART must always be less than MPFS_HAL_LAST_HART. * The value of MPFS_HAL_LAST_HART must never be greater than 4. * A typical use-case where you set MPFS_HAL_FIRST_HART = 1 and * MPFS_HAL_LAST_HART = 1 is when * your application is running on U54_1 and a bootloader running on E51 loads * your application to the target memory and kicks-off U54_1 to run it. */ #ifndef MPFS_HAL_FIRST_HART #define MPFS_HAL_FIRST_HART 1 #endif #ifndef MPFS_HAL_LAST_HART #define MPFS_HAL_LAST_HART 4 #endif /* * IMAGE_LOADED_BY_BOOTLOADER * We set IMAGE_LOADED_BY_BOOTLOADER = 0 if the application image runs from * non-volatile memory after reset. (No previous stage bootloader is used.) * Set IMAGE_LOADED_BY_BOOTLOADER = 1 if the application image is loaded by a * previous stage bootloader. * * MPFS_HAL_HW_CONFIG is defined if we are a boot-loader. This is a * conditional compile switch is used to determine if MPFS HAL will perform the * hardware configurations or not. * Defined => This program acts as a First stage bootloader and performs * hardware configurations. * Not defined => This program assumes that the hardware configurations are * already performed (Typically by a previous boot stage) * * List of items initialised when MPFS_HAL_HW_CONFIG is enabled * - load virtual rom (see load_virtual_rom(void) in system_startup.c) * - l2 cache config * - Bus error unit config * - MPU config * - pmp config * - I/O, clock and clock mux's, DDR and SGMII * - will start other harts, see text describing MPFS_HAL_FIRST_HART, * MPFS_HAL_LAST_HART above * */ #define IMAGE_LOADED_BY_BOOTLOADER 0 #if (IMAGE_LOADED_BY_BOOTLOADER == 0) #define MPFS_HAL_HW_CONFIG #endif /*------------------------------------------------------------------------------ * Markers used to indicate startup status of hart */ #define HLS_DATA_IN_WFI 0x12345678U #define HLS_DATA_PASSED_WFI 0x87654321U /* * If you are using common memory for sharing across harts, * uncomment #define MPFS_HAL_SHARED_MEM_ENABLED * make sure common memory is allocated in the linker script * See app_hart_common mem section in the example platform * linker scripts. */ //#define MPFS_HAL_SHARED_MEM_ENABLED /* define the required tick rate in Milliseconds */ /* if this program is running on one hart only, only that particular hart value * will be used */ #define HART0_TICK_RATE_MS 5UL #define HART1_TICK_RATE_MS 5UL #define HART2_TICK_RATE_MS 5UL #define HART3_TICK_RATE_MS 5UL #define HART4_TICK_RATE_MS 5UL /* * Define the size of the Hart Local Storage (HLS). * In the MPFS HAL, we are using HLS for debug data storage during the initial * boot phase. * This includes the flags which indicate the hart state regarding boot state. * The HLS will take memory from top of each stack allocated at boot time. * */ #define HLS_DEBUG_AREA_SIZE 64 /* * Bus Error Unit (BEU) configurations * BEU_ENABLE => Configures the events that the BEU can report. bit value * 1= enabled, 0 = disabled. * BEU_PLIC_INT => Configures which accrued events should generate an * interrupt to the PLIC. * BEU_LOCAL_INT => Configures which accrued events should generate a * local interrupt to the hart on which the event accrued. */ #define BEU_ENABLE 0x0ULL #define BEU_PLIC_INT 0x0ULL #define BEU_LOCAL_INT 0x0ULL /* * Clear memory on startup * 0 => do not clear DTIM and L2 * 1 => Clears memory * Note: If you are the zero stage bootloader, set this to one. */ #ifndef MPFS_HAL_CLEAR_MEMORY #define MPFS_HAL_CLEAR_MEMORY 0 #endif /* * Comment out the lines to disable the corresponding hardware support not required * in your application. * This is not necessary from an operational point of view as operation dictated * by MSS configurator settings, and items are enabled/disabled by this method. * The reason you may want to use below is to save code space. */ #define SGMII_SUPPORT #define DDR_SUPPORT #define MSSIO_SUPPORT /* * Debugging IHC. This placed memory map in volatile memory and uses software * state machine */ #define LIBERO_SETTING_CONTEXT_A_HART_EN 0x0000000EUL /* harts 1 to 3 */ #define LIBERO_SETTING_CONTEXT_B_HART_EN 0x00000010UL /* hart 4 */ /* * DDR software options */ /* * Debug DDR startup through a UART * Comment out in normal operation. May be useful for debug purposes in bring-up * of a new board design. * See the weakly linked function setup_ddr_debug_port(mss_uart_instance_t * uart) * If you need to edit this function, make another copy of the function in your * application without the weak linking attribute. This copy will then get linked. * */ //#define DEBUG_DDR_INIT //#define DEBUG_DDR_RD_RW_FAIL //#define DEBUG_DDR_RD_RW_PASS //#define DEBUG_DDR_CFG_DDR_SGMII_PHY //#define DEBUG_DDR_DDRCFG /* * SDIO register address location in fabric */ /* * We want the Kconfig-generated config.h file to get the SDIO Register Address, * but it defines CONFIG_OPENSBI... * * OpenSBI type definitions conflict with mpfs_hal * so we need to undefine CONFIG_OPENSBI after including config.h */ #include "config.h" #undef CONFIG_OPENSBI #ifdef CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS # undef LIBERO_SETTING_FPGA_SWITCH_ADDRESS # define LIBERO_SETTING_FPGA_SWITCH_ADDRESS CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS #else # ifndef LIBERO_SETTING_FPGA_SWITCH_ADDRESS # define LIBERO_SETTING_FPGA_SWITCH_ADDRESS 0x4fffff00 # endif #endif #endif /* USER_CONFIG_MSS_USER_CONFIG_H_ */ hart-software-services-2022.10/boards/custom-board-design/mpfs_hal_config/readme.txt000066400000000000000000000001261432224323300305200ustar00rootroot00000000000000contains user configuration of the platform e.g. division of memory between harts etc.hart-software-services-2022.10/boards/custom-board-design/soc_fpga_design/000077500000000000000000000000001432224323300265175ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/soc_fpga_design/xml/000077500000000000000000000000001432224323300273175ustar00rootroot00000000000000hart-software-services-2022.10/boards/custom-board-design/soc_fpga_design/xml/custom_design_cfg.xml000066400000000000000000011652141432224323300335350ustar00rootroot00000000000000 2021.1 PFSOC_MSS_INT_C0 MPFS250TS_ES FCG1152 07-08-2021_14:36:31 0.5.6 0x20220000 0x20220000 0x20220000 0x20220000 0x20220000 0x80000000 0xC0000000 0x1000000000 0x1400000000 0xD0000000 0x1800000000 0x00000000 0x00000000 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x00 0x0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0 220 0 511 0x1 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xF 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0xF 0xC 0xC 0xF 0xF 0xF 0xF 0xF 0xF 0xF 0xF 0xF 0xF 0x1 0x0 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x2 0x9 0x1 0x1 0x0 0x1 0x1 0x8 0x0 0x0 0x0 0x0 0x01 0x01 0x0 0x0 0x014 0x0 0x2 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x7 0x7 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x7 0x7 0x0 0x0 0x0 0x8 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x3 0x0 0x3 0x0 0x0 0x1 0x1 0xf000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x1 0x1 0x0 0x1 0x0 0x0 0x0 0x2 0x5 0x0 0x7F 0x1F 0x02 0x2 0x2 0x1 0x0 0xC 0x1 0x0 0x0 0x2 0x2 0x2 0x2 0x5 0x5 0x7 0x7 0x7 0x3 0x4 0x3 0x4 0x8000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x4 0x0 0x0 0x0 0x1 0x2 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F80 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F70 0x0 0x1 0x0 0x0 0x1 0x7F60 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00001D 0x00000000 0x00000004 0x0000000A 0x00C2CA 0x0 0x9140F38D 0x75955134 0x71B69961 0x000 0x440C2040 0x02481C61 0x00000000 0x00000140 0x000000A0 0x00000000 0x00000000 0x0 0x0 0x0 0x0 0x1 0x00000001 0x00000016 0x00000016 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x0 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000005 0x00000006 0x00000000 0x00000000 0x00000000 0x00000004 0x00000003 0x00000003 0x00000003 0x00000003 0x00000003 0x00000006 0x00000036 0x00000036 0x00000036 0x0 0x81881881 0x00008818 0xa92a92a9 0x00002a92 0xc28c28c2 0x00008c28 0xea2ea2ea 0x00002ea2 0x03903903 0x00009039 0x2b32b32b 0x000032b3 0x44944944 0x00009449 0x6c36c36c 0x000036c3 0x85985985 0x00009859 0xad3ad3ad 0x00003ad3 0xc69c69c6 0x00009c69 0xee3ee3ee 0x00003ee3 0x07a07a07 0x0000a07a 0x2f42f42f 0x000042f4 0x48a48a48 0x0000a48a 0x70470470 0x00004704 0x00000000 0x00000048 0x0000002C 0x00000020 0x00000004 0x00000010 0x00000000 0x1 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x1 0x22 0xF 0x8 0x11 0x33 0x20 0x130 0x8 0x10 0x8 0x0 0x6 0x1F 0x5 0xF 0xF 0xF 0x1F 0x1 0x0 0x1 0x1 0x7 0xC 0x0 0x6 0x0 0x2 0x0 0xC34 0x27100 0xA 0x10 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0xC 0x5 0x00000200 0x5 0x0 0x5 0x0 0x0 0x0 0x00000000 0x0 0x0 0x0 0x1 0x27100 0x0 0x400 0x0 0x1 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x640 0x0 0x0 0x0 0x28 0x8 0xA 0x00000000 0x8 0xE 0x0 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x0 0x00000001 0x00000000 0x00000000 0x0 0x0 0x1 0x4 0x0 0x18 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x320 0x12 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000008 0x0000000b 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x00000000 0x00000001 0x000000FF 0x00000000 0x00000000 0x00000000 0x1 0x1 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x15 0x6 0x3 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x3FFFFFFF 0x0 0x3FFFFFFF 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x8001 0x1 0x1 0x00000000 0x00000000 0x00000000 0x3F 0x3F 0x00000000 0x00000000 0x00000000 0x18 0x00000000 0x1 0x00000000 0x00000000 0x1 100000000 600000000 600000000 1000000 300000000 150000000 1600000000 0x1 0x0 0x1 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x64 0x6 0x0 0x0 0x1 0x0 0x1 0x40 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x18 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x2 0x4 0x6 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x19 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 DDR3 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x10 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x5 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x3 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3 0x0 0x7 0x0 0xF 0x0 0x0 0x0 0x0 0x0 hart-software-services-2022.10/boards/custom-board-design/uart_helper.c000066400000000000000000000123001432224323300260570ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Implementation of uart_putstring/g(). * This is function is intended to be used from ee_printf(). */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include #include #include "uart_helper.h" static inline mss_uart_instance_t *get_uart_instance(int hartid) { mss_uart_instance_t *pUart; switch (hartid) { default: pUart = &g_mss_uart0_lo; break; case HSS_HART_E51: pUart = &g_mss_uart0_lo; break; case HSS_HART_U54_1: pUart = &g_mss_uart1_lo; break; case HSS_HART_U54_2: pUart = &g_mss_uart2_lo; break; case HSS_HART_U54_3: pUart = &g_mss_uart3_lo; break; case HSS_HART_U54_4: pUart = &g_mss_uart4_lo; break; } return pUart; } int uart_putstring(int hartid, char *p) { const uint32_t len = (uint32_t)strlen(p); mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)p); // TODO: if hartId is zero (i.e., E51), replace this with non-blocking // queue implementation, with HSS_UART state machine consuming from queues... return len; } void uart_putc(int hartid, const char ch) { uint8_t string[2]; string[0] = (uint8_t)ch; string[1] = 0u; mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)string); } ssize_t uart_getline(char **pBuffer, size_t *pBufLen) { ssize_t result = 0; bool finished = false; static char myBuffer[HSS_UART_HELPER_MAX_GETLINE]; // static to be stack friendly const size_t bufferLen = ARRAY_SIZE(myBuffer); memset(myBuffer, 0, bufferLen); uint8_t cBuf[1]; while (!finished) { while (0 == MSS_UART_get_rx(&g_mss_uart0_lo, cBuf, 1)); switch (cBuf[0]) { case '\r': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case '\n': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case 0x7Fu: // delete if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[D \033[D", 7u); myBuffer[result] = 0; } break; case 0x08u: // backspace - ^H if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)" \033[D", 4u); myBuffer[result] = 0; } break; case 0x03u: // intr - ^C result = -1; myBuffer[0] = 0; finished = true; break; case 0x1Bu: // ESC result = -1; myBuffer[0] = 0; finished = true; break; case 0x04u: // ^D if (result == 0) { result = -1; myBuffer[0] = 0; finished = true; } break; default: if (result < bufferLen) { MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); myBuffer[result] = cBuf[0]; result++; } break; } } const char crlf[] = "\n"; MSS_UART_polled_tx_string(&g_mss_uart0_lo, (const uint8_t *)crlf); if (result > 0) { *pBuffer = myBuffer; *pBufLen = (size_t)result; } else { *pBuffer = NULL; *pBufLen = 0u; } return result; } bool uart_getchar(uint8_t *pbuf, int32_t timeout_sec, bool do_sec_tick) { bool result = false; bool done = false; uint8_t rx_buff[1]; HSSTicks_t start_time = 0u; HSSTicks_t last_sec_time = 0u; start_time = last_sec_time = HSS_GetTime(); const HSSTicks_t timeout_ticks = timeout_sec * TICKS_PER_SEC; while (!done) { size_t received = MSS_UART_get_rx(&g_mss_uart0_lo, rx_buff, 1u); if (0u != received) { done = true; if (MSS_UART_NO_ERROR == MSS_UART_get_rx_status(&g_mss_uart0_lo)) { *pbuf = rx_buff[0]; result = true; break; } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "UART error\n"); } } if (do_sec_tick && HSS_Timer_IsElapsed(last_sec_time, TICKS_PER_SEC)) { const uint8_t dot='.'; MSS_UART_polled_tx(&g_mss_uart0_lo, &dot, 1); last_sec_time = HSS_GetTime(); } if (timeout_sec < 0) { ; // blocking until UART data received, so nothing extra to do here... } else if (timeout_sec > 0) { // time limited done = HSS_Timer_IsElapsed(start_time, timeout_ticks); } else /* timeout == 0 */ { // one-shot break; } } return result; } hart-software-services-2022.10/boards/mpfs-icicle-kit-es/000077500000000000000000000000001432224323300231245ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/Kconfig000066400000000000000000000003741432224323300244330ustar00rootroot00000000000000menu "Icicle-Kit Design Configuration Options" config SOC_FPGA_DESIGN_XML string "Enter path to Libero XML file" default "boards/$(BOARD)/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" help This option specifies the design XML file to use. endmenu hart-software-services-2022.10/boards/mpfs-icicle-kit-es/Makefile000066400000000000000000000131351432224323300245670ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Defines target-specific build-rules variables, extra sources and include paths # # # Confusingly, the MPFS-ICICLE-KIT-ES is platform MPFS # $(info mpfs-icicle-kit-es selected) BINDIR=Default TARGET-l2scratch=hss-l2scratch.elf TARGET-envm-wrapper=hss-envm-wrapper.elf RISCV_TARGET=$(TARGET-l2scratch) $(TARGET-envm-wrapper) TARGET:=$(RISCV_TARGET) LINKER_SCRIPT-l2scratch=boards/${BOARD}/hss-l2scratch.ld CONFIG_PLATFORM_MPFS=y PLATFORM_CFLAGS += -DCONFIG_PLATFORM_MPFS=1 BOARD_DIR=boards/mpfs-icicle-kit-es INCLUDES += \ -I$(BOARD_DIR)/mpfs_hal_config/\ -I$(BOARD_DIR)/fpga_design_config/\ -I$(BOARD_DIR)/ \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform \ EXTRA_SRCS-y += \ $(BOARD_DIR)/hss_uart_init.c \ $(BOARD_DIR)/uart_helper.c \ $(BOARD_DIR)/hss_board_init.c \ EXTRA_SRCS-$(CONFIG_USE_LOGO) += \ init/hss_logo_init.c $(BOARD_DIR)/hss_uart_init.o: CFLAGS=$(CFLAGS_GCCEXT) EXTRA_OBJS-$(CONFIG_SERVICE_BOOT_USE_PAYLOAD) += $(BOARD_DIR)/payload.o $(BOARD_DIR)/payload.o: $(BOARD_DIR)/payload.bin $(LD) -r -b binary $< -o $@ ################################################################################################ # # Extra hardware dependency rules for QSPI # INCLUDES += \ -Ibaremetal/ \ ifdef CONFIG_SERVICE_QSPI_WINBOND_W25N01GV INCLUDES += \ -Ibaremetal/drivers/winbond_w25n01gv \ EXTRA_SRCS-$(CONFIG_SERVICE_QSPI) += \ baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.c baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.o: CFLAGS=$(CFLAGS_GCCEXT) endif ifdef CONFIG_SERVICE_QSPI_MICRON_MQ25T INCLUDES += \ -Ibaremetal/drivers/micron_mt25q \ EXTRA_SRCS-$(CONFIG_SERVICE_QSPI) += \ baremetal/drivers/micron_mt25q/micron_mt25q.c baremetal/drivers/micron_mt25q/micron_mt25q.o: CFLAGS=$(CFLAGS_GCCEXT) endif ################################################################################################ # # Linker Scripts # $(BOARD_DIR)/hss-l2scratch.ld: $(BOARD_DIR)/hss-l2scratch.lds config.h ################################################################################################ # # Extra dependency rules for auto-generated configuration files (from Libero XML) # SOC_CONFIG_FILES = \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_ddr_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sysreg.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_mss_clks.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_io_bank.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_off_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_options.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_segs.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddrc.h \ $(BOARD_DIR)/fpga_design_config/general/hw_gen_peripherals.h \ $(BOARD_DIR)/fpga_design_config/fpga_design_config.h \ $(BOARD_DIR)/fpga_design_config/io/hw_hsio_mux.h \ $(BOARD_DIR)/fpga_design_config/io/hw_mssio_mux.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_apb_split.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_cache.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_memory.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_crypto.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_mmc.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_scb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_trace.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_usb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart3.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart4.h \ $(BOARD_DIR)/fpga_design_config/sgmii/hw_sgmii_tip.h \ config.h: $(SOC_CONFIG_FILES) $(SOC_CONFIG_FILES): $(subst $\",,$(CONFIG_SOC_FPGA_DESIGN_XML)) @$(ECHO) " MPFSCFGGEN $<"; $(PYTHON) tools/polarfire-soc-configuration-generator/mpfs_configuration_generator.py $< $(BOARD_DIR) $(RISCV_TARGET): $(SOC_CONFIG_FILES) hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config000066400000000000000000000075161432224323300251430ustar00rootroot00000000000000 # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set # # QSPI # # CONFIG_SERVICE_QSPI_WINBOND_W25N01GV is not set # CONFIG_SERVICE_QSPI_MICRON_MQ25T is not set # end of QSPI CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_custom000066400000000000000000000072411432224323300265300ustar00rootroot00000000000000 # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set CONFIG_SERVICE_BOOT_CUSTOM_FLOW=y CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # CONFIG_MEMTEST=y CONFIG_USE_PDMA=y # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples/000077500000000000000000000000001432224323300271055ustar00rootroot00000000000000def_config_emmc_qspi-micron000066400000000000000000000074701432224323300343660ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_QSPI=y # # QSPI # CONFIG_SERVICE_QSPI_MICRON_MQ25T=y # CONFIG_SERVICE_QSPI_WINBOND_W25N01GV is not set # end of QSPI CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options def_config_emmc_qspi-winbond000066400000000000000000000074701432224323300345370ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set CONFIG_SERVICE_QSPI=y # # QSPI # # CONFIG_SERVICE_QSPI_MICRON_MQ25T is not set CONFIG_SERVICE_QSPI_WINBOND_W25N01GV=y # end of QSPI CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples/def_config_no_banner000066400000000000000000000070021432224323300331330ustar00rootroot00000000000000 # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set # CONFIG_SERVICE_SCRUB is not set CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y # CONFIG_USE_LOGO is not set # # Logo # # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options def_config_no_banner_no_tinycli_emmc_only000066400000000000000000000065361432224323300373600ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y # CONFIG_SERVICE_MMC_MODE_SDCARD is not set # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set # CONFIG_SERVICE_TINYCLI is not set # # Tiny Command Line Interface # # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set # # USB Device Mass Storage Class # # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y # CONFIG_USE_LOGO is not set # # Logo # # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y # CONFIG_DEBUG_LOOP_TIMES is not set # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options def_config_no_banner_no_tinycli_emmc_only_quiet000066400000000000000000000066331432224323300405650ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y # CONFIG_SERVICE_MMC_MODE_SDCARD is not set # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set # CONFIG_SERVICE_TINYCLI is not set # # Tiny Command Line Interface # # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set # # USB Device Mass Storage Class # # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # # CONFIG_COLOR_OUTPUT is not set # CONFIG_USE_LOGO is not set # # Logo # # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # # CONFIG_DEBUG_LOG_STATE_TRANSITIONS is not set # CONFIG_DEBUG_LOOP_TIMES is not set # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options def_config_no_tinycli_emmc_only000066400000000000000000000071161432224323300353320ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/def_config_examples # # Board/Design Configuration Options # # # Icicle-Kit Design Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml" # end of Icicle-Kit Design Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y # CONFIG_SERVICE_MMC_MODE_SDCARD is not set # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT=y CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS=0x4fffff00 # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y CONFIG_SERVICE_OPENSBI_IHC=y CONFIG_SERVICE_OPENSBI_RPROC=y # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set # CONFIG_SERVICE_TINYCLI is not set # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y CONFIG_USE_IHC=y CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # # CONFIG_LOGO_INVERT_COLORS is not set # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y # CONFIG_DEBUG_LOOP_TIMES is not set # CONFIG_DEBUG_LOOP_TIMES_THRESHOLD is not set # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/mpfs-icicle-kit-es/drivers_config/000077500000000000000000000000001432224323300261275ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/drivers_config/fpga_ip/000077500000000000000000000000001432224323300275345ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/drivers_config/fpga_ip/miv_ihc/000077500000000000000000000000001432224323300311525ustar00rootroot00000000000000miv_ihc_add_mapping.h000066400000000000000000000105531432224323300352110ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IHC driver @section intro_sec Introduction Used to configure the driver with base addresses from your Libero Projext. These addresses will not change unless you change the Libero design IHC subsytem design. This file is used for reference only. When usiing in a project copy to src/boards/your-board/platform-config/drivers_config/fpga-ip/miv_ihc and rename dropping the _reference. @section *//*==========================================================================*/ #ifndef MIV_IHC_ADD_MAPPING_H_ #define MIV_IHC_ADD_MAPPING_H_ #ifndef COMMON_AHB_BASE_ADD #define COMMON_AHB_BASE_ADD 0x50000000UL #endif #ifndef IHC_HO_BASE_OFFSET #define IHC_HO_BASE_OFFSET 0x00000000UL #endif #ifndef IHC_H1_BASE_OFFSET #define IHC_H1_BASE_OFFSET 0x00000500UL #endif #ifndef IHC_H2_BASE_OFFSET #define IHC_H2_BASE_OFFSET 0x00000A00UL #endif #ifndef IHC_H3_BASE_OFFSET #define IHC_H3_BASE_OFFSET 0x00000F00UL #endif #ifndef IHC_H4_BASE_OFFSET #define IHC_H4_BASE_OFFSET 0x00001400UL #endif /************** My Hart 0 ************/ #ifndef IHC_LOCAL_H0_REMOTE_H1 #define IHC_LOCAL_H0_REMOTE_H1 0x50000000 #endif #ifndef IHC_LOCAL_H0_REMOTE_H2 #define IHC_LOCAL_H0_REMOTE_H2 0x50000100 #endif #ifndef IHC_LOCAL_H0_REMOTE_H3 #define IHC_LOCAL_H0_REMOTE_H3 0x50000200 #endif #ifndef IHC_LOCAL_H0_REMOTE_H4 #define IHC_LOCAL_H0_REMOTE_H4 0x50000300 #endif #ifndef IHCIA_LOCAL_H0 #define IHCIA_LOCAL_H0 0x50000400 #endif /************** My Hart 1 ************/ #ifndef IHC_LOCAL_H1_REMOTE_H0 #define IHC_LOCAL_H1_REMOTE_H0 0x50000500 #endif #ifndef IHC_LOCAL_H1_REMOTE_H2 #define IHC_LOCAL_H1_REMOTE_H2 0x50000600 #endif #ifndef IHC_LOCAL_H1_REMOTE_H3 #define IHC_LOCAL_H1_REMOTE_H3 0x50000700 #endif #ifndef IHC_LOCAL_H1_REMOTE_H4 #define IHC_LOCAL_H1_REMOTE_H4 0x50000800 #endif #ifndef IHCIA_LOCAL_H1 #define IHCIA_LOCAL_H1 0x50000900 #endif /************** My Hart 2 ************/ #ifndef IHC_LOCAL_H2_REMOTE_H0 #define IHC_LOCAL_H2_REMOTE_H0 0x50000A00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H1 #define IHC_LOCAL_H2_REMOTE_H1 0x50000B00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H3 #define IHC_LOCAL_H2_REMOTE_H3 0x50000C00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H4 #define IHC_LOCAL_H2_REMOTE_H4 0x50000D00 #endif #ifndef IHCIA_LOCAL_H2 #define IHCIA_LOCAL_H2 0x50000E00 #endif /************** My Hart 3 ************/ #ifndef IHC_LOCAL_H3_REMOTE_H0 #define IHC_LOCAL_H3_REMOTE_H0 0x50000F00 #endif #ifndef IHC_LOCAL_H3_REMOTE_H1 #define IHC_LOCAL_H3_REMOTE_H1 0x50001000 #endif #ifndef IHC_LOCAL_H3_REMOTE_H2 #define IHC_LOCAL_H3_REMOTE_H2 0x50001100 #endif #ifndef IHC_LOCAL_H3_REMOTE_H4 #define IHC_LOCAL_H3_REMOTE_H4 0x50001200 #endif #ifndef IHCIA_LOCAL_H3 #define IHCIA_LOCAL_H3 0x50001300 #endif /************** My Hart 4 ************/ #ifndef IHC_LOCAL_H4_REMOTE_H0 #define IHC_LOCAL_H4_REMOTE_H0 0x50001400 #endif #ifndef IHC_LOCAL_H4_REMOTE_H1 #define IHC_LOCAL_H4_REMOTE_H1 0x50001500 #endif #ifndef IHC_LOCAL_H4_REMOTE_H2 #define IHC_LOCAL_H4_REMOTE_H2 0x50001600 #endif #ifndef IHC_LOCAL_H4_REMOTE_H3 #define IHC_LOCAL_H4_REMOTE_H3 0x50001700 #endif #ifndef IHCIA_LOCAL_H4 #define IHCIA_LOCAL_H4 0x50001800 #endif /*------------------------------------------------------------------------------ * choose the interrupt mapping used in our system * Please see miv_ihc_regs.h for the defaults */ #define IHCIA_hart0_IRQHandler fabric_f2h_63_plic_IRQHandler #define IHCIA_hart1_IRQHandler fabric_f2h_62_plic_IRQHandler #define IHCIA_hart2_IRQHandler fabric_f2h_61_plic_IRQHandler #define IHCIA_hart3_IRQHandler fabric_f2h_60_plic_IRQHandler #define IHCIA_hart4_IRQHandler fabric_f2h_59_plic_IRQHandler #define IHCIA_hart0_INT FABRIC_F2H_63_PLIC #define IHCIA_hart1_INT FABRIC_F2H_62_PLIC #define IHCIA_hart2_INT FABRIC_F2H_61_PLIC #define IHCIA_hart3_INT FABRIC_F2H_60_PLIC #define IHCIA_hart4_INT FABRIC_F2H_59_PLIC #endif /* MIV_IHC_ADD_MAPPING_H_ */ miv_ihc_config.h000066400000000000000000000051161432224323300342120ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IhC driver @section intro_sec Introduction Used to configure the driver @section *//*==========================================================================*/ #ifndef MIV_IHC_CONFIG_H_ #define MIV_IHC_CONFIG_H_ #include "miv_ihc_add_mapping.h" /*------------------------------------------------------------------------------ * define the monitor hart (HSS hart) used in our system */ #define HSS_HART_MASK HART0_MASK #define HSS_HART_ID HART0_ID /*------------------------------------------------------------------------------ * HSS_REMOTE_HARTS_MASK * This is used to define the harts the HSS is communicating with */ #define HSS_REMOTE_HARTS_MASK (HART1_MASK | HART2_MASK |HART3_MASK | HART4_MASK) #if 0 /*------------------------------------------------------------------------------ * Contex A and B hart ID's used in this system - user defined */ #define CONTEXTA_HARTID 0x01U #define CONTEXTB_HARTID 0x04U #endif /*------------------------------------------------------------------------------ * Define which harts are connected via comms channels to a particular hart * user defined */ #define IHCIA_H0_REMOTE_HARTS (HSS_REMOTE_HARTS_MASK) /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS (HSS_HART_MASK | HART4_MASK) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H3_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H4_REMOTE_HARTS (HSS_HART_MASK | HART1_MASK) /* HSS and Context A connected */ /*------------------------------------------------------------------------------ * interrupts enabled in this system design for a particular hart * User defined */ #define IHCIA_H0_REMOTE_HARTS_INTS HSS_HART_DEFAULT_INT_EN /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART4_MP_INT_EN | HART4_ACK_INT_EN) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H3_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H4_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART1_MP_INT_EN | HART1_ACK_INT_EN) /* HSS and Context A connected */ #endif /* MIV_IHC_CONFIG_H_ */ hart-software-services-2022.10/boards/mpfs-icicle-kit-es/fpga_design_config/000077500000000000000000000000001432224323300267175ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/fpga_design_config/README.md000066400000000000000000000000451432224323300301750ustar00rootroot00000000000000Placeholder for auto-generated code. hart-software-services-2022.10/boards/mpfs-icicle-kit-es/hss-l2scratch.lds000066400000000000000000000271131432224323300263140ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip Corporation. * * SPDX-License-Identifier: MIT * * GNU linker script for Hart Software Services (HSS) * */ #include "config.h" OUTPUT_ARCH( "riscv" ) /* PolarFire SoC Memory map (ditaa diagram) ---------------------------------------- +-------------+ +-----------+ | non-cache | | non-cache | | WCB (SEG1) | +---------------------+ | (SEG1) | 0x18_0000_0000 +-------------+ | DDR cached | 0x14_0000_0000 +-----------+ | non-cache | | (SEG0) | | non-cache | | WCB (SEG1) | 0x10_0000_0000 +---------------------+ | (SEG1) | 0xD000_0000 +-------------+ | DDR cached | 0xC000_0000 +-----------+ | (SEG0) | 0x8000_0000 +---------------------+ | envm (128KiB) | | | 0x2022_0100 +---------------------+ | Zero Device | | | 0x0A00_0000 +---------------------+ | | 0x0820_0000 +---------------------+ | LIM (up to 1920KiB) | | | 0x0800_0000 +---------------------+ | U54_4 ITIM (28KiB) | | | 0x0182_0000 +---------------------+ | U54_3 ITIM (28KiB) | | | 0x0181_8000 +---------------------+ | U54_2 ITIM (28KiB) | | | 0x0181_0000 +---------------------+ | U54_1 ITIM (28KiB) | | | 0x0180_8000 +---------------------+ | E51 ITIM (28KiB) | | | 0x0180_0000 +---------------------+ | DTIM (8KiB) | | | 0x0100_0000 +---------------------+ | Debug | 0x0000_0000 +---------------------+ */ /******************************************************************************* * * -- MSS hart Reset vector * * The MSS reset vector for each hart is configured by Libero and stored securely * in the MPFS. * * The most common usage will be where the reset vector for each hart will be set * to the start of the envm at address 0x2022_0100, giving (128KiB-256bytes) * of contiguous non-volatile storage. Normally this is where the initial * boot-loader will reside. * * Libero outputs the configured reset vector address to the xml file, see * LIBERO_SETTING_RESET_VECTOR_HART0 etc in * * When debugging a bare metal program that is run out of reset from envm, a linker * script will be used whereby the program will run from LIM instead of envm. * In this case, set the reset vector in the linker script to 0x0800_0000. * This means you are not continually programming the envm each time you load a * program and there is no limitation with hardware break points whn debugging. */ ENTRY(_start) /******************************************************************************* * * Memory Segments * * must be on 4k boundary (0x1000) - corresponds to page size, when using memory mem */ MEMORY { envm (rx) : ORIGIN = 0x20220100, LENGTH = (128k-256) dtim (rwx) : ORIGIN = 0x01000000, LENGTH = 7k /* DTIM */ switch_code (rx) : ORIGIN = 0x01001c00, LENGTH = 1k /* This 1K of DTIM is used to run code * when switching the envm clock */ e51_itim (rwx) : ORIGIN = 0x01800000, LENGTH = 28k u54_1_itim (rwx) : ORIGIN = 0x01808000, LENGTH = 28k u54_2_itim (rwx) : ORIGIN = 0x01810000, LENGTH = 28k u54_3_itim (rwx) : ORIGIN = 0x01818000, LENGTH = 28k u54_4_itim (rwx) : ORIGIN = 0x01820000, LENGTH = 28k l2lim (rwx) : ORIGIN = 0x08000000, LENGTH = 512k l2zerodevice (rwx) : ORIGIN = 0x0A000000, LENGTH = 512k ddr (rwx) : ORIGIN = 0x80000000, LENGTH = 32m ddrhi (rwx) : ORIGIN = 0x1000000000, LENGTH = 1888m ncddrhi (rwx) : ORIGIN = 0x1400000000, LENGTH = 2048m } PROVIDE(HEAP_SIZE = 0k); PROVIDE(STACK_SIZE_PER_HART = 16k); /******************************************************************************* * * Memory Sections and Placement */ SECTIONS { PROVIDE(__envm_start = ORIGIN(envm)); PROVIDE(__envm_end = ORIGIN(envm) + LENGTH(envm)); PROVIDE(__l2lim_start = ORIGIN(l2lim)); PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); PROVIDE(__l2_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); PROVIDE(__ddr_start = ORIGIN(ddr)); PROVIDE(__ddr_end = ORIGIN(ddr) + LENGTH(ddr)); PROVIDE(__ddrhi_start = ORIGIN(ddrhi)); PROVIDE(__ddrhi_end = ORIGIN(ddrhi) + LENGTH(ddrhi)); PROVIDE(__ncddrhi_start = ORIGIN(ncddrhi)); PROVIDE(__ncddrhi_end = ORIGIN(ncddrhi) + LENGTH(ncddrhi)); PROVIDE(__dtim_start = ORIGIN(dtim)); PROVIDE(__dtim_end = ORIGIN(dtim) + LENGTH(dtim)); PROVIDE(__e51itim_start = ORIGIN(e51_itim)); PROVIDE(__e51itim_end = ORIGIN(e51_itim) + LENGTH(e51_itim)); PROVIDE(__u54_1_itim_start = ORIGIN(u54_1_itim)); PROVIDE(__u54_1_itim_end = ORIGIN(u54_1_itim) + LENGTH(u54_1_itim)); PROVIDE(__u54_2_itim_start = ORIGIN(u54_2_itim)); PROVIDE(__u54_2_itim_end = ORIGIN(u54_2_itim) + LENGTH(u54_2_itim)); PROVIDE(__u54_3_itim_start = ORIGIN(u54_3_itim)); PROVIDE(__u54_3_itim_end = ORIGIN(u54_3_itim) + LENGTH(u54_3_itim)); PROVIDE(__u54_4_itim_start = ORIGIN(u54_4_itim)); PROVIDE(__u54_4_itim_end = ORIGIN(u54_4_itim) + LENGTH(u54_4_itim)); /* * Code and RO data lives in l2lim */ . = __l2_start; PROVIDE(_hss_start = .); PROVIDE(__l2_scratchpad_vma_start = .); .text : ALIGN(0x10) { *(.entry) . = ALIGN(0x10); *(.text .text.* .gnu.linkonce.t.*) *(.plt) . = ALIGN(0x10); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) *(.sdata2*) *(.gcc_except_table) *(.eh_frame_hdr) *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(0x10); } >l2zerodevice .gnu_build_id : ALIGN(8) { PROVIDE(gnu_build_id = .); *(.note.gnu.build-id) } >l2zerodevice PROVIDE(_hss_end = .); /******************************************************************************* * * The .ram_code section will contain the code That is run from RAM. * We are using this code to switch the clocks including envm clock. * This can not be done when running from envm * This will need to be copied to ram, before any of this code is run. * */ .ram_code : ALIGN(0x10) { __sc_load = LOADADDR (.ram_code); __sc_start = .; *(.ram_codetext) /* .ram_codetext sections (code) */ *(.ram_codetext*) /* .ram_codetext* sections (code) */ *(.ram_coderodata) /* read-only data (constants) */ *(.ram_coderodata*) . = ALIGN (0x10); __sc_end = .; } >switch_code /******************************************************************************* * * Short/global data section * */ .sdata : ALIGN(0x40) /* short/global data section */ { __sdata_load = LOADADDR(.sdata); __sdata_start = .; /* * offset used with gp(gloabl pointer) are +/- 12 bits, so set * point to middle of expected sdata range * * If sdata more than 4K, linker used direct addressing. * Perhaps we should add check/warning to linker script if sdata is > 4k */ __global_pointer$ = . + 0x800; *(.sdata .sdata.* .gnu.linkonce.s.*) . = ALIGN(0x10); __sdata_end = .; } >l2zerodevice /******************************************************************************* * * (Explicitly) Initialized data section * */ #ifdef CONFIG_SERVICE_BOOT_USE_PAYLOAD .data.payload : ALIGN(16) { _payload_start = .; KEEP(boards/mpfs-icicle-kit-es/payload.o(.*)) _payload_end = .; } #endif .data : ALIGN(0x40) { __data_load = LOADADDR(.data); __data_start = .; *(.got.plt) *(.got) *(.shdata) *(.data .data.* .gnu.linkonce.d.*) . = ALIGN(0x10); __data_end = .; } >l2zerodevice /******************************************************************************* * * Uninitialized (zero-initialized) section */ /* * Short zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. * */ .sbss : ALIGN(0x40) { __sbss_start = .; *(.sbss .sbss.* .gnu.linkonce.sb.*) *(.scommon) . = ALIGN(0x10); __sbss_end = .; } >l2zerodevice /* * General Zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. */ .bss : ALIGN(0x40) { __bss_start = .; *(.shbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(0x10); __bss_end = .; } >l2zerodevice /* * Reserved space for Hart stacks */ .stack : ALIGN(0x40) { __stack_bottom = .; __stack_bottom_h0$ = .; . += STACK_SIZE_PER_HART; __stack_top_h0$ = . - 8; __stack_bottom_h1$ = .; . += STACK_SIZE_PER_HART; __stack_top_h1$ = . - 8; __stack_bottom_h2$ = .; . += STACK_SIZE_PER_HART; __stack_top_h2$ = . - 8; __stack_bottom_h3$ = .; . += STACK_SIZE_PER_HART; __stack_top_h3$ = . - 8; __stack_bottom_h4$ = .; . += STACK_SIZE_PER_HART; __stack_top_h4$ = . - 8; __stack_top = .; } >l2zerodevice _end = .; PROVIDE(__l2_scratchpad_vma_end = .); /* * End of uninitialized data segment * *******************************************************************************/ /* .heap : ALIGN(0x10) { __heap_start = .; . += HEAP_SIZE; __heap_end = .; . = ALIGN(0x10); _heap_end = __heap_end; } >dtim */ } hart-software-services-2022.10/boards/mpfs-icicle-kit-es/hss_board_init.c000066400000000000000000000045661432224323300262720ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Board Initalization * \brief Board Initialization */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "hss_init.h" #include "hss_state_machine.h" #include "ssmb_ipi.h" #include "hss_registry.h" /******************************************************************************************************/ /*! * \brief Board Init Function Registration Table * * The following structure is used to connect in new board init functions. */ #include "hss_init.h" #include "hss_boot_pmp.h" #include "hss_sys_setup.h" #include "hss_board_init.h" const struct InitFunction /*@null@*/ boardInitFunctions[] = { // Name FunctionPointer Halt Restart { "HSS_ZeroTIMs", HSS_ZeroTIMs, false, false }, { "HSS_Setup_PLIC", HSS_Setup_PLIC, false, false }, { "HSS_Setup_BusErrorUnit", HSS_Setup_BusErrorUnit, false, false }, { "HSS_Setup_MPU", HSS_Setup_MPU, false, false }, { "HSS_DDRInit", HSS_DDRInit, false, false }, { "HSS_ZeroDDR", HSS_ZeroDDR, false, false }, #ifdef CONFIG_USE_PCIE { "HSS_PCIeInit", HSS_PCIeInit, false, false }, #endif { "HSS_USBInit", HSS_USBInit, false, false }, }; /******************************************************************************************************/ /** * \brief Board Initialization Function * * All other initialization routines to be chained off this... */ /****************************************************************************/ #include "mss_sysreg.h" bool HSS_BoardInit(void) { RunInitFunctions(ARRAY_SIZE(boardInitFunctions), boardInitFunctions); return true; } bool HSS_BoardLateInit(void) { #if defined(CONFIG_SERVICE_MMC_MODE_SDCARD) || defined(CONFIG_SERVICE_MMC_MODE_EMMC) mHSS_DEBUG_PRINTF(LOG_WARN, "Please ensure that jumpers J34/J43 are correct for " # if defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8) "1.8V" # elif defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_3V3) "3.3V" # endif " MMC voltage... \n"); #endif return true; } hart-software-services-2022.10/boards/mpfs-icicle-kit-es/hss_uart_init.c000066400000000000000000000025501432224323300261450ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Debug UART Initalization * \brief Debug UART Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" bool HSS_UARTInit(void) { // initialise debug UART #if IS_ENABLED(CONFIG_PLATFORM_MPFS) MSS_UART_init(&g_mss_uart0_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); // default all UARTs to 115200 for now // subsequent OS loads can change these if needed... MSS_UART_init(&g_mss_uart1_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart2_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart3_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart4_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); #else # error Unknown PLATFORM #endif return true; } hart-software-services-2022.10/boards/mpfs-icicle-kit-es/mpfs_hal_config/000077500000000000000000000000001432224323300262425ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/mpfs_hal_config/mss_sw_config.h000066400000000000000000000172261432224323300312630ustar00rootroot00000000000000#ifndef MSS_SW_CONFIG_H_ #define MSS_SW_CONFIG_H_ /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * Platform definitions * Version based on requirements of MPFS MSS * */ /*========================================================================*//** @mainpage Sample file detailing how mss_sw_config.h should be constructed for the MPFS MSS @section intro_sec Introduction The mss_sw_config.h has the default software configuration settings for the MPFS HAL and will be located at /src/platform/platform_config_reference folder of the bare metal SoftConsole project. The platform_config_reference is provided as a default reference configuration. When you want to configure the MPFS HAL with required configuration for your project, the mss_sw_config.h must be edited and be placed in the following project directory: /src/boards//platform_config/mpfs_hal_config/ @section *//*==========================================================================*/ /* * Include any driver setup/over-rides you may require. */ #include "drivers/fpga_ip/miv_ihc/miv_ihc_defines.h" #include "drivers_config/fpga_ip/miv_ihc/miv_ihc_config.h" /* * MPFS_HAL_FIRST_HART and MPFS_HAL_LAST_HART defines are used to specify which * harts to actually start. The value and the actual hart it represents are * listed below: * value hart * 0 E51 * 1 U54_1 * 2 U54_2 * 3 U54_3 * 4 U54_4 * Set MPFS_HAL_FIRST_HART to a value greater than 0 if you do not want your * application to start and execute code on the harts represented by smaller * value numbers. * Set MPFS_HAL_LAST_HART to a value smaller than 4 if you do not wish to use * all U54_x harts. * Harts that are not started will remain in an infinite WFI loop unless used * through some other method. * The value of MPFS_HAL_FIRST_HART must always be less than MPFS_HAL_LAST_HART. * The value of MPFS_HAL_LAST_HART must never be greater than 4. * A typical use-case where you set MPFS_HAL_FIRST_HART = 1 and * MPFS_HAL_LAST_HART = 1 is when * your application is running on U54_1 and a bootloader running on E51 loads * your application to the target memory and kicks-off U54_1 to run it. */ #ifndef MPFS_HAL_FIRST_HART #define MPFS_HAL_FIRST_HART 1 #endif #ifndef MPFS_HAL_LAST_HART #define MPFS_HAL_LAST_HART 4 #endif /* * IMAGE_LOADED_BY_BOOTLOADER * We set IMAGE_LOADED_BY_BOOTLOADER = 0 if the application image runs from * non-volatile memory after reset. (No previous stage bootloader is used.) * Set IMAGE_LOADED_BY_BOOTLOADER = 1 if the application image is loaded by a * previous stage bootloader. * * MPFS_HAL_HW_CONFIG is defined if we are a boot-loader. This is a * conditional compile switch is used to determine if MPFS HAL will perform the * hardware configurations or not. * Defined => This program acts as a First stage bootloader and performs * hardware configurations. * Not defined => This program assumes that the hardware configurations are * already performed (Typically by a previous boot stage) * * List of items initialised when MPFS_HAL_HW_CONFIG is enabled * - load virtual rom (see load_virtual_rom(void) in system_startup.c) * - l2 cache config * - Bus error unit config * - MPU config * - pmp config * - I/O, clock and clock mux's, DDR and SGMII * - will start other harts, see text describing MPFS_HAL_FIRST_HART, * MPFS_HAL_LAST_HART above * */ #define IMAGE_LOADED_BY_BOOTLOADER 0 #if (IMAGE_LOADED_BY_BOOTLOADER == 0) #define MPFS_HAL_HW_CONFIG #endif /*------------------------------------------------------------------------------ * Markers used to indicate startup status of hart */ #define HLS_DATA_IN_WFI 0x12345678U #define HLS_DATA_PASSED_WFI 0x87654321U /* * If you are using common memory for sharing across harts, * uncomment #define MPFS_HAL_SHARED_MEM_ENABLED * make sure common memory is allocated in the linker script * See app_hart_common mem section in the example platform * linker scripts. */ //#define MPFS_HAL_SHARED_MEM_ENABLED /* define the required tick rate in Milliseconds */ /* if this program is running on one hart only, only that particular hart value * will be used */ #define HART0_TICK_RATE_MS 5UL #define HART1_TICK_RATE_MS 5UL #define HART2_TICK_RATE_MS 5UL #define HART3_TICK_RATE_MS 5UL #define HART4_TICK_RATE_MS 5UL /* * Define the size of the Hart Local Storage (HLS). * In the MPFS HAL, we are using HLS for debug data storage during the initial * boot phase. * This includes the flags which indicate the hart state regarding boot state. * The HLS will take memory from top of each stack allocated at boot time. * */ #define HLS_DEBUG_AREA_SIZE 64 /* * Bus Error Unit (BEU) configurations * BEU_ENABLE => Configures the events that the BEU can report. bit value * 1= enabled, 0 = disabled. * BEU_PLIC_INT => Configures which accrued events should generate an * interrupt to the PLIC. * BEU_LOCAL_INT => Configures which accrued events should generate a * local interrupt to the hart on which the event accrued. */ #define BEU_ENABLE 0x0ULL #define BEU_PLIC_INT 0x0ULL #define BEU_LOCAL_INT 0x0ULL /* * Clear memory on startup * 0 => do not clear DTIM and L2 * 1 => Clears memory * Note: If you are the zero stage bootloader, set this to one. */ #ifndef MPFS_HAL_CLEAR_MEMORY #define MPFS_HAL_CLEAR_MEMORY 0 #endif /* * Comment out the lines to disable the corresponding hardware support not required * in your application. * This is not necessary from an operational point of view as operation dictated * by MSS configurator settings, and items are enabled/disabled by this method. * The reason you may want to use below is to save code space. */ #define SGMII_SUPPORT #define DDR_SUPPORT #define MSSIO_SUPPORT /* * Debugging IHC. This placed memory map in volatile memory and uses software * state machine */ #define LIBERO_SETTING_CONTEXT_A_HART_EN 0x0000000EUL /* harts 1 to 3 */ #define LIBERO_SETTING_CONTEXT_B_HART_EN 0x00000010UL /* hart 4 */ /* * DDR software options */ /* * Debug DDR startup through a UART * Comment out in normal operation. May be useful for debug purposes in bring-up * of a new board design. * See the weakly linked function setup_ddr_debug_port(mss_uart_instance_t * uart) * If you need to edit this function, make another copy of the function in your * application without the weak linking attribute. This copy will then get linked. * */ //#define DEBUG_DDR_INIT //#define DEBUG_DDR_RD_RW_FAIL //#define DEBUG_DDR_RD_RW_PASS //#define DEBUG_DDR_CFG_DDR_SGMII_PHY //#define DEBUG_DDR_DDRCFG /* * SDIO register address location in fabric */ /* * We want the Kconfig-generated config.h file to get the SDIO Register Address, * but it defines CONFIG_OPENSBI... * * OpenSBI type definitions conflict with mpfs_hal * so we need to undefine CONFIG_OPENSBI after including config.h */ #include "config.h" #undef CONFIG_OPENSBI #ifdef CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS # undef LIBERO_SETTING_FPGA_SWITCH_ADDRESS # define LIBERO_SETTING_FPGA_SWITCH_ADDRESS CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS #else # ifndef LIBERO_SETTING_FPGA_SWITCH_ADDRESS # define LIBERO_SETTING_FPGA_SWITCH_ADDRESS 0x4fffff00 # endif #endif #endif /* USER_CONFIG_MSS_USER_CONFIG_H_ */ hart-software-services-2022.10/boards/mpfs-icicle-kit-es/mpfs_hal_config/readme.txt000066400000000000000000000001261432224323300302370ustar00rootroot00000000000000contains user configuration of the platform e.g. division of memory between harts etc.hart-software-services-2022.10/boards/mpfs-icicle-kit-es/soc_fpga_design/000077500000000000000000000000001432224323300262365ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/soc_fpga_design/xml/000077500000000000000000000000001432224323300270365ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-icicle-kit-es/soc_fpga_design/xml/ICICLE_MSS_mss_cfg.xml000066400000000000000000011763331432224323300327510ustar00rootroot00000000000000 2022.2 ICICLE_MSS MPFS250T_ES FCVG484 08-08-2022_14:11:08 0.6.5 0x20220000 0x20220000 0x20220000 0x20220000 0x20220000 0x80000000 0xC0000000 0x1000000000 0x1400000000 0xD0000000 0x1800000000 0x00000000 0x00000000 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xB 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x00 0x0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0 220 0 511 0x1 0x0 0x1 0x1 0x1 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0xC 0xC 0x8 0x8 0x3 0x3 0x3 0x3 0x7 0x7 0x7 0xF 0x1 0x0 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0xD 0x00 0xA 0x0 0x4 0x0 0x0930 0x0930 0x0930 0x0930 0x0930 0x0930 0x0928 0x0928 0x0930 0x0930 0x0930 0x0930 0x0930 0x0930 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x1 0x1 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0xF 0xF 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0xC 0xC 0x8 0x8 0x3 0x3 0x3 0x3 0x7 0x7 0x7 0xF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xD 0x00 0xA 0x0 0x4 0x0 0x0930 0x0930 0x0930 0x0930 0x0930 0x0930 0x0928 0x0930 0x0930 0x0930 0x0930 0x0930 0x0928 0x0928 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x2 0xC 0x1 0x1 0x0 0x1 0x1 0x8 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x14 0x0 0x2 0x0 0x0 0x0 0x7 0x7 0x7 0x0 0x0 0x0 0x4 0x7 0x7 0x3 0x0 0x0 0x0 0x0 0x7 0x7 0x7 0x0 0x0 0x0 0x4 0x7 0x7 0x3 0x0 0x8 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x3 0x0 0x3 0x0 0x0 0x1 0x1 0xf000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFF000000 0x1 0x1 0x0 0x1 0x0 0x0 0x0 0x7 0x5 0x0 0x7F 0x1F 0x02 0x2 0x2 0x1 0x0 0x10 0x1 0x0 0x0 0x3 0x6 0x2 0x2 0x5 0x5 0x7 0x7 0x7 0x3 0x4 0x3 0x4 0x8000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x4 0x0 0x0 0x1 0x0 0x1 0x1 0x2 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F80 0x0 0x1 0x7000 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F40 0x0 0x1 0x6C00 0x0 0x1 0x7F30 0x0 0x1 0x6800 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00001D 0x00000000 0x00000004 0x0000000A 0x00C2CA 0x0 0x9140F38D 0x75955134 0x71B69961 0x000 0x440C2040 0x02481C61 0x00000000 0x00000140 0x000000A0 0x00000000 0x00000000 0x6 0x0 0x0 0x0 0x1 0x00000001 0x00000016 0x00000016 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x0 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000005 0x00000006 0x1 0x1 0x17 0x00000004 0x00000003 0x00000003 0x00000003 0x00000003 0x00000003 0x00000006 0x00000036 0x00000036 0x00000036 0x0 0x81881881 0x00008818 0xa92a92a9 0x00002a92 0xc28c28c2 0x00008c28 0xea2ea2ea 0x00002ea2 0x03903903 0x00009039 0x2b32b32b 0x000032b3 0x44944944 0x00009449 0x6c36c36c 0x000036c3 0x85985985 0x00009859 0xad3ad3ad 0x00003ad3 0xc69c69c6 0x00009c69 0xee3ee3ee 0x00003ee3 0x07a07a07 0x0000a07a 0x2f42f42f 0x000042f4 0x48a48a48 0x0000a48a 0x70470470 0x00004704 0x00000000 0x00000048 0x0000002C 0x00000020 0x00000004 0x00000010 0x00000000 0x1 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x1 0x22 0xF 0x8 0x11 0x33 0x20 0x130 0x8 0x10 0x8 0x0 0x6 0x1F 0x5 0xF 0xF 0xF 0x1F 0xF 0x0 0x1 0x1 0x7 0xC 0x0 0x6 0x0 0x2 0x0 0xC34 0x27100 0xA 0x10 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0xC 0x5 0x00000200 0x5 0x0 0x5 0x0 0x0 0x0 0x00000000 0x0 0x0 0x0 0x1 0x27100 0x0 0x400 0x0 0x1 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x640 0x0 0x0 0x0 0x28 0x8 0xA 0x00000000 0x8 0xE 0x0 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x0 0x00000001 0x00000000 0x00000000 0x0 0x0 0x0 0x2 0x4 0x18 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x320 0x12 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000008 0x0000000b 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x00000000 0x00000001 0x000000FF 0x00000000 0x00000000 0x00000000 0x0 0x1 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x15 0x6 0x3 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x7FFFFFFF 0x0 0x7FFFFFFF 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x8001 0x1 0x1 0x00000000 0x00000000 0x00000000 0x3F 0x3F 0x00000000 0x00000000 0x00000000 0x18 0x00000000 0x1 0x00000000 0x00000000 0x1 125000000 600000000 600000000 1000000 300000000 150000000 1600000000 0x1 0x0 0x1 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x7D 0x5 0x0 0x0 0x1 0x0 0x1 0x40 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x4B 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x60 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x2 0x4 0x6 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x14 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 DDR3 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x80 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x10 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x5 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x3 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3 0x0 0x7 0x0 0xF 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x1 hart-software-services-2022.10/boards/mpfs-icicle-kit-es/uart_helper.c000066400000000000000000000123001432224323300255760ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Implementation of uart_putstring/g(). * This is function is intended to be used from ee_printf(). */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include #include #include "uart_helper.h" static inline mss_uart_instance_t *get_uart_instance(int hartid) { mss_uart_instance_t *pUart; switch (hartid) { default: pUart = &g_mss_uart0_lo; break; case HSS_HART_E51: pUart = &g_mss_uart0_lo; break; case HSS_HART_U54_1: pUart = &g_mss_uart1_lo; break; case HSS_HART_U54_2: pUart = &g_mss_uart2_lo; break; case HSS_HART_U54_3: pUart = &g_mss_uart3_lo; break; case HSS_HART_U54_4: pUart = &g_mss_uart4_lo; break; } return pUart; } int uart_putstring(int hartid, char *p) { const uint32_t len = (uint32_t)strlen(p); mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)p); // TODO: if hartId is zero (i.e., E51), replace this with non-blocking // queue implementation, with HSS_UART state machine consuming from queues... return len; } void uart_putc(int hartid, const char ch) { uint8_t string[2]; string[0] = (uint8_t)ch; string[1] = 0u; mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)string); } ssize_t uart_getline(char **pBuffer, size_t *pBufLen) { ssize_t result = 0; bool finished = false; static char myBuffer[HSS_UART_HELPER_MAX_GETLINE]; // static to be stack friendly const size_t bufferLen = ARRAY_SIZE(myBuffer); memset(myBuffer, 0, bufferLen); uint8_t cBuf[1]; while (!finished) { while (0 == MSS_UART_get_rx(&g_mss_uart0_lo, cBuf, 1)); switch (cBuf[0]) { case '\r': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case '\n': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case 0x7Fu: // delete if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[D \033[D", 7u); myBuffer[result] = 0; } break; case 0x08u: // backspace - ^H if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)" \033[D", 4u); myBuffer[result] = 0; } break; case 0x03u: // intr - ^C result = -1; myBuffer[0] = 0; finished = true; break; case 0x1Bu: // ESC result = -1; myBuffer[0] = 0; finished = true; break; case 0x04u: // ^D if (result == 0) { result = -1; myBuffer[0] = 0; finished = true; } break; default: if (result < bufferLen) { MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); myBuffer[result] = cBuf[0]; result++; } break; } } const char crlf[] = "\n"; MSS_UART_polled_tx_string(&g_mss_uart0_lo, (const uint8_t *)crlf); if (result > 0) { *pBuffer = myBuffer; *pBufLen = (size_t)result; } else { *pBuffer = NULL; *pBufLen = 0u; } return result; } bool uart_getchar(uint8_t *pbuf, int32_t timeout_sec, bool do_sec_tick) { bool result = false; bool done = false; uint8_t rx_buff[1]; HSSTicks_t start_time = 0u; HSSTicks_t last_sec_time = 0u; start_time = last_sec_time = HSS_GetTime(); const HSSTicks_t timeout_ticks = timeout_sec * TICKS_PER_SEC; while (!done) { size_t received = MSS_UART_get_rx(&g_mss_uart0_lo, rx_buff, 1u); if (0u != received) { done = true; if (MSS_UART_NO_ERROR == MSS_UART_get_rx_status(&g_mss_uart0_lo)) { *pbuf = rx_buff[0]; result = true; break; } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "UART error\n"); } } if (do_sec_tick && HSS_Timer_IsElapsed(last_sec_time, TICKS_PER_SEC)) { const uint8_t dot='.'; MSS_UART_polled_tx(&g_mss_uart0_lo, &dot, 1); last_sec_time = HSS_GetTime(); } if (timeout_sec < 0) { ; // blocking until UART data received, so nothing extra to do here... } else if (timeout_sec > 0) { // time limited done = HSS_Timer_IsElapsed(start_time, timeout_ticks); } else /* timeout == 0 */ { // one-shot break; } } return result; } hart-software-services-2022.10/boards/mpfs-sev-kit/000077500000000000000000000000001432224323300220645ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/Kconfig000066400000000000000000000003761432224323300233750ustar00rootroot00000000000000menu "mpfs-sev-kit Configuration Options" config SOC_FPGA_DESIGN_XML string "Enter path to Libero XML file" default "boards/$(BOARD)/soc_fpga_design/xml/MSS_SEV_kit_linux_mss_cfg.xml" help This option specifies the design XML file to use. endmenu hart-software-services-2022.10/boards/mpfs-sev-kit/Makefile000066400000000000000000000127651432224323300235370ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Defines target-specific build-rules variables, extra sources and include paths # # # Confusingly, the CONFIG_MODULE_SEV_KIT is platform MPFS # $(info mpfs-sev-kit selected) BINDIR=Default TARGET-l2scratch=hss-l2scratch.elf TARGET-envm-wrapper=hss-envm-wrapper.elf RISCV_TARGET=$(TARGET-l2scratch) $(TARGET-envm-wrapper) TARGET:=$(RISCV_TARGET) LINKER_SCRIPT-l2scratch=boards/${BOARD}/hss-l2scratch.ld CONFIG_PLATFORM_MPFS=y PLATFORM_CFLAGS += -DCONFIG_PLATFORM_MPFS=1 -DCONFIG_MODULE_SEV_KIT=1 BOARD_DIR=boards/mpfs-sev-kit INCLUDES += \ -I$(BOARD_DIR)/mpfs_hal_config/\ -I$(BOARD_DIR)/fpga_design_config/\ -I$(BOARD_DIR)/ \ -Ibaremetal/polarfire-soc-bare-metal-library/src/platform \ EXTRA_SRCS-y += \ $(BOARD_DIR)/hss_uart_init.c \ $(BOARD_DIR)/uart_helper.c \ $(BOARD_DIR)/hss_board_init.c \ EXTRA_SRCS-$(CONFIG_USE_LOGO) += \ init/hss_logo_init.c $(BOARD_DIR)/hss_uart_init.o: CFLAGS=$(CFLAGS_GCCEXT) EXTRA_OBJS-$(CONFIG_SERVICE_BOOT_USE_PAYLOAD) += $(BOARD_DIR)/payload.o $(BOARD_DIR)/payload.o: $(BOARD_DIR)/payload.bin $(LD) -r -b binary $< -o $@ ################################################################################################ # # Extra hardware dependency rules for YMODEM # INCLUDES += \ -Ibaremetal/ \ EXTRA_SRCS-$(CONFIG_SERVICE_YMODEM) += \ baremetal/drivers/mss_envm/mss_envm.c EXTRA_SRCS-$(CONFIG_SERVICE_QSPI) += \ baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.c baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/micron_mt25q/micron_mt25q.o: CFLAGS=$(CFLAGS_GCCEXT) baremetal/drivers/mss_envm/mss_envm.o: CFLAGS=$(CFLAGS_GCCEXT) ################################################################################################ # # Linker Scripts # $(BOARD_DIR)/hss-l2scratch.ld: $(BOARD_DIR)/hss-l2scratch.lds config.h ################################################################################################ # # Extra dependency rules for auto-generated configuration files (from Libero XML) # SOC_CONFIG_FILES = \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_ddr_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_mss_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_cfm.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sgmii_pll.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_clk_sysreg.h \ $(BOARD_DIR)/fpga_design_config/clocks/hw_mss_clks.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_io_bank.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_off_mode.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_options.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddr_segs.h \ $(BOARD_DIR)/fpga_design_config/ddr/hw_ddrc.h \ $(BOARD_DIR)/fpga_design_config/general/hw_gen_peripherals.h \ $(BOARD_DIR)/fpga_design_config/fpga_design_config.h \ $(BOARD_DIR)/fpga_design_config/io/hw_hsio_mux.h \ $(BOARD_DIR)/fpga_design_config/io/hw_mssio_mux.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_apb_split.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_cache.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_memory.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_crypto.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_fic2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_gem1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_mmc.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_scb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_trace.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_mpu_usb.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart0.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart1.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart2.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart3.h \ $(BOARD_DIR)/fpga_design_config/memory_map/hw_pmp_hart4.h \ $(BOARD_DIR)/fpga_design_config/sgmii/hw_sgmii_tip.h \ config.h: $(SOC_CONFIG_FILES) $(SOC_CONFIG_FILES): $(subst $\",,$(CONFIG_SOC_FPGA_DESIGN_XML)) @$(ECHO) " MPFSCFGGEN $<"; $(PYTHON) tools/polarfire-soc-configuration-generator/mpfs_configuration_generator.py $< $(BOARD_DIR) $(RISCV_TARGET): $(SOC_CONFIG_FILES) hart-software-services-2022.10/boards/mpfs-sev-kit/def_config000066400000000000000000000074601432224323300241010ustar00rootroot00000000000000 # # Board/Design Configuration Options # # # mpfs-sev-kit Configuration Options # CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-sev-kit/fpga_design/design_description/MSS_SEV_mss_cfg.xml" # end of mpfs-sev-kit Configuration Options # end of Board/Design Configuration Options # # Services # CONFIG_SERVICE_BEU=y CONFIG_SERVICE_BOOT=y # # Boot Service # # CONFIG_SERVICE_BOOT_USE_PAYLOAD is not set # CONFIG_SERVICE_BOOT_CUSTOM_FLOW is not set CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR=0xA0000000 CONFIG_SERVICE_BOOT_MMC_USE_GPT=y # end of Boot Service CONFIG_SERVICE_DDR=y CONFIG_SERVICE_GOTO=y CONFIG_SERVICE_IPI_POLL=y CONFIG_SERVICE_MMC=y # # MMC # # # MMC Mode # CONFIG_SERVICE_MMC_MODE_EMMC=y CONFIG_SERVICE_MMC_MODE_SDCARD=y # end of MMC Mode # # MMC Voltage # CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8=y # end of MMC Voltage # # SDIO Control # # CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT is not set # end of SDIO Control CONFIG_SERVICE_MMC_SPIN_TIMEOUT=y # CONFIG_SERVICE_MMC_SPIN_TIMEOUT_ASSERT is not set CONFIG_SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS=1000000 # end of MMC CONFIG_SERVICE_OPENSBI=y # CONFIG_SERVICE_OPENSBI_IHC is not set # CONFIG_SERVICE_OPENSBI_RPROC is not set # CONFIG_SERVICE_POWERMODE is not set # CONFIG_SERVICE_QSPI is not set # # QSPI # # CONFIG_SERVICE_QSPI_WINBOND_W25N01GV is not set # CONFIG_SERVICE_QSPI_MICRON_MQ25T is not set # end of QSPI CONFIG_SERVICE_SCRUB=y # # RAM Scrubbing Service # CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER=4096 CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS=256 # CONFIG_SERVICE_SCRUB_CACHED_DDR is not set # end of RAM Scrubbing Service CONFIG_SERVICE_SGDMA=y # CONFIG_SERVICE_SPI is not set CONFIG_SERVICE_TINYCLI=y # # Tiny Command Line Interface # CONFIG_SERVICE_TINYCLI_TIMEOUT=1 CONFIG_SERVICE_TINYCLI_REGISTER=y # CONFIG_SERVICE_TINYCLI_MONITOR is not set # end of Tiny Command Line Interface # CONFIG_SERVICE_UART is not set CONFIG_SERVICE_USBDMSC=y # # USB Device Mass Storage Class # CONFIG_SERVICE_USBDMSC_REGISTER=y # end of USB Device Mass Storage Class CONFIG_SERVICE_WDOG=y # # Watchdog Service # # CONFIG_SERVICE_WDOG_DEBUG is not set CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC=240 CONFIG_SERVICE_WDOG_ENABLE_E51=y # end of Watchdog Service # CONFIG_SERVICE_YMODEM is not set # end of Services # # General Configuration Options # # # Miscellaneous # CONFIG_USE_PCIE=y CONFIG_OPENSBI=y # CONFIG_USE_IHC is not set CONFIG_ALLOW_COLDREBOOT=y # # Cold Reboot # CONFIG_ALLOW_COLDREBOOT_ALWAYS=y # end of Cold Reboot # end of Miscellaneous # # OpenSBI # # CONFIG_PROVIDE_DTB is not set # end of OpenSBI # # Memory Options # # CONFIG_SKIP_DDR is not set CONFIG_MEMTEST=y # CONFIG_USE_PDMA is not set # CONFIG_INITIALIZE_MEMORIES is not set # end of Memory Options # end of General Configuration Options # # Build Options # CONFIG_COLOR_OUTPUT=y CONFIG_USE_LOGO=y # # Logo # CONFIG_LOGO_INVERT_COLORS=y # end of Logo # CONFIG_CC_STACKPROTECTOR_STRONG is not set # CONFIG_CC_DUMP_STACKSIZE is not set # CONFIG_LD_RELAX is not set CONFIG_CC_USE_MAKEDEP=y CONFIG_CC_USE_GNU_BUILD_ID=y CONFIG_CC_HAS_INTTYPES=y CONFIG_DISPLAY_TOOL_VERSIONS=y # CONFIG_LOG_FUNCTION_NAMES is not set # end of Build Options # # Compression # CONFIG_COMPRESSION=y CONFIG_COMPRESSION_MINIZ=y # end of Compression # # Crypto # # CONFIG_CRYPTO_SIGNING is not set # end of Crypto # # Debug Options # CONFIG_DEBUG_LOG_STATE_TRANSITIONS=y CONFIG_DEBUG_LOOP_TIMES=y CONFIG_DEBUG_LOOP_TIMES_THRESHOLD=2500000 # CONFIG_DEBUG_IPI_STATS is not set # CONFIG_DEBUG_CHUNK_DOWNLOADS is not set # CONFIG_DEBUG_MSCGEN_IPI is not set # CONFIG_DEBUG_PROFILING_SUPPORT is not set CONFIG_DEBUG_PERF_CTRS=y CONFIG_DEBUG_PERF_CTRS_NUM=16 # CONFIG_DEBUG_RESET_REASON is not set # end of Debug Options # # SSMB Options # # CONFIG_HSS_USE_IHC is not set CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES=8 # CONFIG_IPI_FIXED_BASE is not set # end of SSMB Options hart-software-services-2022.10/boards/mpfs-sev-kit/drivers_config/000077500000000000000000000000001432224323300250675ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/drivers_config/fpga_ip/000077500000000000000000000000001432224323300264745ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/drivers_config/fpga_ip/miv_ihc/000077500000000000000000000000001432224323300301125ustar00rootroot00000000000000miv_ihc_add_mapping.h000066400000000000000000000105461432224323300341530ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/drivers_config/fpga_ip/miv_ihc/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IHC driver @section intro_sec Introduction Used to configure the driver with base addresses from your Libero Projext. These addresses will not change unless you change the Libero design IHC subsytem design. This file is used for reference only. When usiing in a project copy to src/boards/your-board/platform-config/drivers_config/fpga-ip/miv_ihc and rename dropping the _reference. @section *//*==========================================================================*/ #ifndef MIV_IHC_ADD_MAPPING_H_ #define MIV_IHC_ADD_MAPPING_H_ #ifndef COMMON_AHB_BASE_ADD #define COMMON_AHB_BASE_ADD 0x50000000UL #endif #ifndef IHC_HO_BASE_OFFSET #define IHC_HO_BASE_OFFSET 0x00000000UL #endif #ifndef IHC_H1_BASE_OFFSET #define IHC_H1_BASE_OFFSET 0x00000500UL #endif #ifndef IHC_H2_BASE_OFFSET #define IHC_H2_BASE_OFFSET 0x00000A00UL #endif #ifndef IHC_H3_BASE_OFFSET #define IHC_H3_BASE_OFFSET 0x00000F00UL #endif #ifndef IHC_H4_BASE_OFFSET #define IHC_H4_BASE_OFFSET 0x00001400UL #endif /************** My Hart 0 ************/ #ifndef IHC_LOCAL_H0_REMOTE_H1 #define IHC_LOCAL_H0_REMOTE_H1 0x50000000 #endif #ifndef IHC_LOCAL_H0_REMOTE_H2 #define IHC_LOCAL_H0_REMOTE_H2 0x50000100 #endif #ifndef IHC_LOCAL_H0_REMOTE_H3 #define IHC_LOCAL_H0_REMOTE_H3 0x50000200 #endif #ifndef IHC_LOCAL_H0_REMOTE_H4 #define IHC_LOCAL_H0_REMOTE_H4 0x50000300 #endif #ifndef IHCIA_LOCAL_H0 #define IHCIA_LOCAL_H0 0x50000400 #endif /************** My Hart 1 ************/ #ifndef IHC_LOCAL_H1_REMOTE_H0 #define IHC_LOCAL_H1_REMOTE_H0 0x50000500 #endif #ifndef IHC_LOCAL_H1_REMOTE_H2 #define IHC_LOCAL_H1_REMOTE_H2 0x50000600 #endif #ifndef IHC_LOCAL_H1_REMOTE_H3 #define IHC_LOCAL_H1_REMOTE_H3 0x50000700 #endif #ifndef IHC_LOCAL_H1_REMOTE_H4 #define IHC_LOCAL_H1_REMOTE_H4 0x50000800 #endif #ifndef IHCIA_LOCAL_H1 #define IHCIA_LOCAL_H1 0x50000900 #endif /************** My Hart 2 ************/ #ifndef IHC_LOCAL_H2_REMOTE_H0 #define IHC_LOCAL_H2_REMOTE_H0 0x50000A00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H1 #define IHC_LOCAL_H2_REMOTE_H1 0x50000B00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H3 #define IHC_LOCAL_H2_REMOTE_H3 0x50000C00 #endif #ifndef IHC_LOCAL_H2_REMOTE_H4 #define IHC_LOCAL_H2_REMOTE_H4 0x50000D00 #endif #ifndef IHCIA_LOCAL_H2 #define IHCIA_LOCAL_H2 0x50000E00 #endif /************** My Hart 3 ************/ #ifndef IHC_LOCAL_H3_REMOTE_H0 #define IHC_LOCAL_H3_REMOTE_H0 0x50000F00 #endif #ifndef IHC_LOCAL_H3_REMOTE_H1 #define IHC_LOCAL_H3_REMOTE_H1 0x50001000 #endif #ifndef IHC_LOCAL_H3_REMOTE_H2 #define IHC_LOCAL_H3_REMOTE_H2 0x50001100 #endif #ifndef IHC_LOCAL_H3_REMOTE_H4 #define IHC_LOCAL_H3_REMOTE_H4 0x50001200 #endif #ifndef IHCIA_LOCAL_H3 #define IHCIA_LOCAL_H3 0x50001300 #endif /************** My Hart 4 ************/ #ifndef IHC_LOCAL_H4_REMOTE_H0 #define IHC_LOCAL_H4_REMOTE_H0 0x50001400 #endif #ifndef IHC_LOCAL_H4_REMOTE_H1 #define IHC_LOCAL_H4_REMOTE_H1 0x50001500 #endif #ifndef IHC_LOCAL_H4_REMOTE_H2 #define IHC_LOCAL_H4_REMOTE_H2 0x50001600 #endif #ifndef IHC_LOCAL_H4_REMOTE_H3 #define IHC_LOCAL_H4_REMOTE_H3 0x50001700 #endif #ifndef IHCIA_LOCAL_H4 #define IHCIA_LOCAL_H4 0x50001800 #endif /*------------------------------------------------------------------------------ * choose the interrupt mapping used in our system * Please see miv_ihc_regs.h for the defaults */ #define IHCIA_hart0_IRQHandler fabric_f2h_63_plic_IRQHandler #define IHCIA_hart1_IRQHandler fabric_f2h_62_plic_IRQHandler #define IHCIA_hart2_IRQHandler fabric_f2h_61_plic_IRQHandler #define IHCIA_hart3_IRQHandler fabric_f2h_60_plic_IRQHandler #define IHCIA_hart4_IRQHandler fabric_f2h_59_plic_IRQHandler #define IHCIA_hart0_INT FABRIC_F2H_63_PLIC #define IHCIA_hart1_INT FABRIC_F2H_62_PLIC #define IHCIA_hart2_INT FABRIC_F2H_61_PLIC #define IHCIA_hart3_INT FABRIC_F2H_60_PLIC #define IHCIA_hart4_INT FABRIC_F2H_59_PLIC #endif /* MIV_IHC_ADD_MAPPING_H_ */ hart-software-services-2022.10/boards/mpfs-sev-kit/drivers_config/fpga_ip/miv_ihc/miv_ihc_config.h000066400000000000000000000045401432224323300332310ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /*========================================================================*//** @mainpage Configuration for the MiV-IhC driver @section intro_sec Introduction Used to configure the driver @section *//*==========================================================================*/ #ifndef MIV_IHC_CONFIG_H_ #define MIV_IHC_CONFIG_H_ #include "miv_ihc_add_mapping.h" /*------------------------------------------------------------------------------ * define the monitor hart (HSS hart) used in our system */ #define HSS_HART_MASK HART0_MASK #define HSS_HART_ID HART0_ID /*------------------------------------------------------------------------------ * HSS_REMOTE_HARTS_MASK * This is used to define the harts the HSS is communicating with */ #define HSS_REMOTE_HARTS_MASK (HART1_MASK | HART2_MASK |HART3_MASK | HART4_MASK) /*------------------------------------------------------------------------------ * Define which harts are connected via comms channels to a particular hart * user defined */ #define IHCIA_H0_REMOTE_HARTS (HSS_REMOTE_HARTS_MASK) /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS (HSS_HART_MASK | HART4_MASK) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H3_REMOTE_HARTS (HSS_HART_MASK) #define IHCIA_H4_REMOTE_HARTS (HSS_HART_MASK | HART1_MASK) /* HSS and Context A connected */ /*------------------------------------------------------------------------------ * interrupts enabled in this system design for a particular hart * User defined */ #define IHCIA_H0_REMOTE_HARTS_INTS HSS_HART_DEFAULT_INT_EN /* connected to all harts */ #define IHCIA_H1_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART4_MP_INT_EN | HART4_ACK_INT_EN) /* HSS and Context B connected */ #define IHCIA_H2_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H3_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN) #define IHCIA_H4_REMOTE_HARTS_INTS (HSS_HART_MP_INT_EN | HSS_HART_ACK_INT_EN | HART1_MP_INT_EN | HART1_ACK_INT_EN) /* HSS and Context A connected */ #endif /* MIV_IHC_CONFIG_H_ */ hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design/000077500000000000000000000000001432224323300243325ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design/design_description/000077500000000000000000000000001432224323300302065ustar00rootroot00000000000000MSS_SEV_mss_cfg.xml000066400000000000000000011763211432224323300335440ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design/design_description 2022.2 MSS_SEV MPFS250T_ES FCG1152 09-21-2022_14:19:01 0.6.5 0x20220000 0x20220000 0x20220000 0x20220000 0x20220000 0x80000000 0xC0000000 0x1000000000 0x1400000000 0xD0000000 0x1800000000 0x00000000 0x00000000 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xB 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x00 0x0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9F 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFFFFFFFFF 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0xFFFFFFFFF 0x0 0x1F 0 220 0 511 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0xB 0xF 0xF 0xF 0xB 0xF 0xF 0xF 0xB 0x8 0x8 0xB 0x1 0x0 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0xD 0x00 0xA 0x0 0x4 0x0 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0xF 0xF 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0x4 0xB 0xF 0xF 0xF 0xB 0xF 0xF 0xF 0xB 0x8 0x8 0xB 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xD 0x00 0xA 0x0 0x4 0x0 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x0928 0x7 0x00 0x9 0x0 0x8 0x0 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0829 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x2 0xC 0x1 0x1 0x0 0x1 0x1 0x8 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x14 0x0 0x2 0x0 0x0 0x0 0x7 0x7 0x7 0x0 0x0 0x0 0x4 0x7 0x7 0x3 0x0 0x0 0x0 0x0 0x7 0x7 0x7 0x0 0x0 0x0 0x4 0x7 0x7 0x3 0x0 0x8 0x0 0x1 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x3 0x0 0x3 0x0 0x0 0x1 0x1 0xf000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xFF000000 0x1 0x1 0x0 0x1 0x0 0x0 0x0 0x7 0x5 0x0 0x7F 0x1F 0x02 0x2 0x2 0x1 0x0 0x10 0x1 0x0 0x0 0x3 0x6 0x2 0x2 0x5 0x5 0x7 0x7 0x7 0x3 0x4 0x3 0x4 0x8000 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x1 0x1 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x1 0x6 0x4 0x0 0x0 0x1 0x0 0x1 0x1 0x2 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7F80 0x0 0x1 0x7002 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x7FB8 0x0 0x1 0x0 0x0 0x1 0x7FA8 0x0 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00001D 0x00000000 0x00000004 0x0000000A 0x00C2CA 0x0 0x9140F38D 0x75955134 0x71B69961 0x000 0x440C2040 0x02481C61 0x00000000 0x00000140 0x000000A0 0x00000000 0x00000000 0x6 0x0 0x0 0x0 0x1 0x00000001 0x00000016 0x00000016 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x0 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000005 0x00000006 0x1 0x1 0x17 0x00000004 0x00000003 0x00000003 0x00000003 0x00000003 0x00000003 0x00000006 0x00000036 0x00000036 0x00000036 0x0 0x81881881 0x00008818 0xa92a92a9 0x00002a92 0xc28c28c2 0x00008c28 0xea2ea2ea 0x00002ea2 0x03903903 0x00009039 0x2b32b32b 0x000032b3 0x44944944 0x00009449 0x6c36c36c 0x000036c3 0x85985985 0x00009859 0xad3ad3ad 0x00003ad3 0xc69c69c6 0x00009c69 0xee3ee3ee 0x00003ee3 0x07a07a07 0x0000a07a 0x2f42f42f 0x000042f4 0x48a48a48 0x0000a48a 0x70470470 0x00004704 0x00000000 0x00000048 0x0000002C 0x00000020 0x00000004 0x00000010 0x00000000 0x1 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x1 0x22 0xF 0x8 0x11 0x33 0x20 0x130 0x8 0x10 0x8 0x0 0x6 0x1F 0x5 0xF 0xF 0xF 0x1F 0xF 0x0 0x1 0x1 0x7 0xC 0x0 0x6 0x0 0x2 0x0 0xC34 0x27100 0xA 0x10 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0xC 0x5 0x00000200 0x5 0x0 0x5 0x0 0x0 0x0 0x00000000 0x0 0x0 0x0 0x1 0x27100 0x0 0x400 0x0 0x1 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x640 0x0 0x0 0x0 0x28 0x8 0xA 0x00000000 0x8 0xE 0x0 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x0 0x00000001 0x00000000 0x00000000 0x0 0x0 0x0 0x2 0x4 0x18 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x0 0x0 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x320 0x12 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000008 0x0000000b 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x00000001 0x00000000 0x00000001 0x000000FF 0x00000000 0x00000000 0x00000000 0x0 0x1 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0 0x00000000 0x00000000 0x00000000 0x15 0x6 0x3 0x00000001 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x1 0x00000000 0x00000000 0x00000000 0x00000000 0x7FFFFFFF 0x0 0x7FFFFFFF 0x0 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x8001 0x1 0x1 0x00000000 0x00000000 0x00000000 0x3F 0x3F 0x00000000 0x00000000 0x00000000 0x18 0x00000000 0x1 0x00000000 0x00000000 0x1 125000000 600000000 600000000 1000000 300000000 150000000 1600000000 0x1 0x0 0x1 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x7D 0x5 0x0 0x0 0x1 0x0 0x1 0x40 0x1 0x1 0x1 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x60 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x2 0x4 0x6 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x14 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 DDR3 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x2 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x0 0x8 0x0 0x0 0x0 0x0 0x6 0x0 0x0 0x0 0xd 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x80 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x10 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x0 0x5 0x0 0x0 0x0 0x0 0x3 0x0 0x0 0x0 0x3 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3 0x0 0x7 0x0 0xF 0x0 0x0 0x0 0x0 0x0 0x1 0x1 0x1 0x1 0x1 0x0 0x0 0x0 0x1 0x1 0x0 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x1 0x1 hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design/mss_configuration/000077500000000000000000000000001432224323300300635ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design/mss_configuration/MSS_SEV.cfg000066400000000000000000002505021432224323300317270ustar00rootroot00000000000000ALT_MSSIO_0_ATP_EN false ALT_MSSIO_0_CLAMP_DIODE false ALT_MSSIO_0_LPMD_IBUF false ALT_MSSIO_0_LPMD_OBUF false ALT_MSSIO_0_LP_PERSIST false ALT_MSSIO_0_MD_IBUF true ALT_MSSIO_0_OUT_DRIVE 8 ALT_MSSIO_0_RES_PULL UP ALT_MSSIO_0_SCHMITT_TRIGGER false ALT_MSSIO_10_ATP_EN false ALT_MSSIO_10_CLAMP_DIODE false ALT_MSSIO_10_LPMD_IBUF false ALT_MSSIO_10_LPMD_OBUF false ALT_MSSIO_10_LP_PERSIST false ALT_MSSIO_10_MD_IBUF true ALT_MSSIO_10_OUT_DRIVE 8 ALT_MSSIO_10_RES_PULL UP ALT_MSSIO_10_SCHMITT_TRIGGER false ALT_MSSIO_11_ATP_EN false ALT_MSSIO_11_CLAMP_DIODE false ALT_MSSIO_11_LPMD_IBUF false ALT_MSSIO_11_LPMD_OBUF false ALT_MSSIO_11_LP_PERSIST false ALT_MSSIO_11_MD_IBUF true ALT_MSSIO_11_OUT_DRIVE 8 ALT_MSSIO_11_RES_PULL UP ALT_MSSIO_11_SCHMITT_TRIGGER false ALT_MSSIO_12_ATP_EN false ALT_MSSIO_12_CLAMP_DIODE false ALT_MSSIO_12_LPMD_IBUF false ALT_MSSIO_12_LPMD_OBUF false ALT_MSSIO_12_LP_PERSIST false ALT_MSSIO_12_MD_IBUF true ALT_MSSIO_12_OUT_DRIVE 8 ALT_MSSIO_12_RES_PULL UP ALT_MSSIO_12_SCHMITT_TRIGGER false ALT_MSSIO_13_ATP_EN false ALT_MSSIO_13_CLAMP_DIODE false ALT_MSSIO_13_LPMD_IBUF false ALT_MSSIO_13_LPMD_OBUF false ALT_MSSIO_13_LP_PERSIST false ALT_MSSIO_13_MD_IBUF true ALT_MSSIO_13_OUT_DRIVE 8 ALT_MSSIO_13_RES_PULL UP ALT_MSSIO_13_SCHMITT_TRIGGER false ALT_MSSIO_14_ATP_EN false ALT_MSSIO_14_CLAMP_DIODE false ALT_MSSIO_14_LPMD_IBUF false ALT_MSSIO_14_LPMD_OBUF false ALT_MSSIO_14_LP_PERSIST false ALT_MSSIO_14_MD_IBUF true ALT_MSSIO_14_OUT_DRIVE 8 ALT_MSSIO_14_RES_PULL UP ALT_MSSIO_14_SCHMITT_TRIGGER false ALT_MSSIO_15_ATP_EN false ALT_MSSIO_15_CLAMP_DIODE false ALT_MSSIO_15_LPMD_IBUF false ALT_MSSIO_15_LPMD_OBUF false ALT_MSSIO_15_LP_PERSIST false ALT_MSSIO_15_MD_IBUF true ALT_MSSIO_15_OUT_DRIVE 8 ALT_MSSIO_15_RES_PULL UP ALT_MSSIO_15_SCHMITT_TRIGGER false ALT_MSSIO_16_ATP_EN false ALT_MSSIO_16_CLAMP_DIODE false ALT_MSSIO_16_LPMD_IBUF false ALT_MSSIO_16_LPMD_OBUF false ALT_MSSIO_16_LP_PERSIST false ALT_MSSIO_16_MD_IBUF true ALT_MSSIO_16_OUT_DRIVE 8 ALT_MSSIO_16_RES_PULL UP ALT_MSSIO_16_SCHMITT_TRIGGER false ALT_MSSIO_17_ATP_EN false ALT_MSSIO_17_CLAMP_DIODE false ALT_MSSIO_17_LPMD_IBUF false ALT_MSSIO_17_LPMD_OBUF false ALT_MSSIO_17_LP_PERSIST false ALT_MSSIO_17_MD_IBUF true ALT_MSSIO_17_OUT_DRIVE 8 ALT_MSSIO_17_RES_PULL UP ALT_MSSIO_17_SCHMITT_TRIGGER false ALT_MSSIO_18_ATP_EN false ALT_MSSIO_18_CLAMP_DIODE false ALT_MSSIO_18_LPMD_IBUF false ALT_MSSIO_18_LPMD_OBUF false ALT_MSSIO_18_LP_PERSIST false ALT_MSSIO_18_MD_IBUF true ALT_MSSIO_18_OUT_DRIVE 8 ALT_MSSIO_18_RES_PULL UP ALT_MSSIO_18_SCHMITT_TRIGGER false ALT_MSSIO_19_ATP_EN false ALT_MSSIO_19_CLAMP_DIODE false ALT_MSSIO_19_LPMD_IBUF false ALT_MSSIO_19_LPMD_OBUF false ALT_MSSIO_19_LP_PERSIST false ALT_MSSIO_19_MD_IBUF true ALT_MSSIO_19_OUT_DRIVE 8 ALT_MSSIO_19_RES_PULL UP ALT_MSSIO_19_SCHMITT_TRIGGER false ALT_MSSIO_1_ATP_EN false ALT_MSSIO_1_CLAMP_DIODE false ALT_MSSIO_1_LPMD_IBUF false ALT_MSSIO_1_LPMD_OBUF false ALT_MSSIO_1_LP_PERSIST false ALT_MSSIO_1_MD_IBUF true ALT_MSSIO_1_OUT_DRIVE 8 ALT_MSSIO_1_RES_PULL UP ALT_MSSIO_1_SCHMITT_TRIGGER false ALT_MSSIO_20_ATP_EN false ALT_MSSIO_20_CLAMP_DIODE false ALT_MSSIO_20_LPMD_IBUF false ALT_MSSIO_20_LPMD_OBUF false ALT_MSSIO_20_LP_PERSIST false ALT_MSSIO_20_MD_IBUF true ALT_MSSIO_20_OUT_DRIVE 8 ALT_MSSIO_20_RES_PULL UP ALT_MSSIO_20_SCHMITT_TRIGGER false ALT_MSSIO_21_ATP_EN false ALT_MSSIO_21_CLAMP_DIODE false ALT_MSSIO_21_LPMD_IBUF false ALT_MSSIO_21_LPMD_OBUF false ALT_MSSIO_21_LP_PERSIST false ALT_MSSIO_21_MD_IBUF true ALT_MSSIO_21_OUT_DRIVE 8 ALT_MSSIO_21_RES_PULL UP ALT_MSSIO_21_SCHMITT_TRIGGER false ALT_MSSIO_22_ATP_EN false ALT_MSSIO_22_CLAMP_DIODE false ALT_MSSIO_22_LPMD_IBUF false ALT_MSSIO_22_LPMD_OBUF false ALT_MSSIO_22_LP_PERSIST false ALT_MSSIO_22_MD_IBUF true ALT_MSSIO_22_OUT_DRIVE 8 ALT_MSSIO_22_RES_PULL UP ALT_MSSIO_22_SCHMITT_TRIGGER false ALT_MSSIO_23_ATP_EN false ALT_MSSIO_23_CLAMP_DIODE false ALT_MSSIO_23_LPMD_IBUF false ALT_MSSIO_23_LPMD_OBUF false ALT_MSSIO_23_LP_PERSIST false ALT_MSSIO_23_MD_IBUF true ALT_MSSIO_23_OUT_DRIVE 8 ALT_MSSIO_23_RES_PULL UP ALT_MSSIO_23_SCHMITT_TRIGGER false ALT_MSSIO_24_ATP_EN false ALT_MSSIO_24_CLAMP_DIODE false ALT_MSSIO_24_LPMD_IBUF false ALT_MSSIO_24_LPMD_OBUF false ALT_MSSIO_24_LP_PERSIST false ALT_MSSIO_24_MD_IBUF true ALT_MSSIO_24_OUT_DRIVE 8 ALT_MSSIO_24_RES_PULL UP ALT_MSSIO_24_SCHMITT_TRIGGER false ALT_MSSIO_25_ATP_EN false ALT_MSSIO_25_CLAMP_DIODE false ALT_MSSIO_25_LPMD_IBUF false ALT_MSSIO_25_LPMD_OBUF false ALT_MSSIO_25_LP_PERSIST false ALT_MSSIO_25_MD_IBUF true ALT_MSSIO_25_OUT_DRIVE 8 ALT_MSSIO_25_RES_PULL UP ALT_MSSIO_25_SCHMITT_TRIGGER false ALT_MSSIO_26_ATP_EN false ALT_MSSIO_26_CLAMP_DIODE false ALT_MSSIO_26_LPMD_IBUF false ALT_MSSIO_26_LPMD_OBUF false ALT_MSSIO_26_LP_PERSIST false ALT_MSSIO_26_MD_IBUF true ALT_MSSIO_26_OUT_DRIVE 8 ALT_MSSIO_26_RES_PULL UP ALT_MSSIO_26_SCHMITT_TRIGGER false ALT_MSSIO_27_ATP_EN false ALT_MSSIO_27_CLAMP_DIODE false ALT_MSSIO_27_LPMD_IBUF false ALT_MSSIO_27_LPMD_OBUF false ALT_MSSIO_27_LP_PERSIST false ALT_MSSIO_27_MD_IBUF true ALT_MSSIO_27_OUT_DRIVE 8 ALT_MSSIO_27_RES_PULL UP ALT_MSSIO_27_SCHMITT_TRIGGER false ALT_MSSIO_28_ATP_EN false ALT_MSSIO_28_CLAMP_DIODE false ALT_MSSIO_28_LPMD_IBUF false ALT_MSSIO_28_LPMD_OBUF false ALT_MSSIO_28_LP_PERSIST false ALT_MSSIO_28_MD_IBUF true ALT_MSSIO_28_OUT_DRIVE 8 ALT_MSSIO_28_RES_PULL UP ALT_MSSIO_28_SCHMITT_TRIGGER false ALT_MSSIO_29_ATP_EN false ALT_MSSIO_29_CLAMP_DIODE false ALT_MSSIO_29_LPMD_IBUF false ALT_MSSIO_29_LPMD_OBUF false ALT_MSSIO_29_LP_PERSIST false ALT_MSSIO_29_MD_IBUF true ALT_MSSIO_29_OUT_DRIVE 8 ALT_MSSIO_29_RES_PULL UP ALT_MSSIO_29_SCHMITT_TRIGGER false ALT_MSSIO_2_ATP_EN false ALT_MSSIO_2_CLAMP_DIODE false ALT_MSSIO_2_LPMD_IBUF false ALT_MSSIO_2_LPMD_OBUF false ALT_MSSIO_2_LP_PERSIST false ALT_MSSIO_2_MD_IBUF true ALT_MSSIO_2_OUT_DRIVE 8 ALT_MSSIO_2_RES_PULL UP ALT_MSSIO_2_SCHMITT_TRIGGER false ALT_MSSIO_30_ATP_EN false ALT_MSSIO_30_CLAMP_DIODE false ALT_MSSIO_30_LPMD_IBUF false ALT_MSSIO_30_LPMD_OBUF false ALT_MSSIO_30_LP_PERSIST false ALT_MSSIO_30_MD_IBUF true ALT_MSSIO_30_OUT_DRIVE 8 ALT_MSSIO_30_RES_PULL UP ALT_MSSIO_30_SCHMITT_TRIGGER false ALT_MSSIO_31_ATP_EN false ALT_MSSIO_31_CLAMP_DIODE false ALT_MSSIO_31_LPMD_IBUF false ALT_MSSIO_31_LPMD_OBUF false ALT_MSSIO_31_LP_PERSIST false ALT_MSSIO_31_MD_IBUF true ALT_MSSIO_31_OUT_DRIVE 8 ALT_MSSIO_31_RES_PULL UP ALT_MSSIO_31_SCHMITT_TRIGGER false ALT_MSSIO_32_ATP_EN false ALT_MSSIO_32_CLAMP_DIODE false ALT_MSSIO_32_LPMD_IBUF false ALT_MSSIO_32_LPMD_OBUF false ALT_MSSIO_32_LP_PERSIST false ALT_MSSIO_32_MD_IBUF true ALT_MSSIO_32_OUT_DRIVE 8 ALT_MSSIO_32_RES_PULL UP ALT_MSSIO_32_SCHMITT_TRIGGER false ALT_MSSIO_33_ATP_EN false ALT_MSSIO_33_CLAMP_DIODE false ALT_MSSIO_33_LPMD_IBUF false ALT_MSSIO_33_LPMD_OBUF false ALT_MSSIO_33_LP_PERSIST false ALT_MSSIO_33_MD_IBUF true ALT_MSSIO_33_OUT_DRIVE 8 ALT_MSSIO_33_RES_PULL UP ALT_MSSIO_33_SCHMITT_TRIGGER false ALT_MSSIO_34_ATP_EN false ALT_MSSIO_34_CLAMP_DIODE false ALT_MSSIO_34_LPMD_IBUF false ALT_MSSIO_34_LPMD_OBUF false ALT_MSSIO_34_LP_PERSIST false ALT_MSSIO_34_MD_IBUF true ALT_MSSIO_34_OUT_DRIVE 8 ALT_MSSIO_34_RES_PULL UP ALT_MSSIO_34_SCHMITT_TRIGGER false ALT_MSSIO_35_ATP_EN false ALT_MSSIO_35_CLAMP_DIODE false ALT_MSSIO_35_LPMD_IBUF false ALT_MSSIO_35_LPMD_OBUF false ALT_MSSIO_35_LP_PERSIST false ALT_MSSIO_35_MD_IBUF true ALT_MSSIO_35_OUT_DRIVE 8 ALT_MSSIO_35_RES_PULL UP ALT_MSSIO_35_SCHMITT_TRIGGER false ALT_MSSIO_36_ATP_EN false ALT_MSSIO_36_CLAMP_DIODE false ALT_MSSIO_36_LPMD_IBUF false ALT_MSSIO_36_LPMD_OBUF false ALT_MSSIO_36_LP_PERSIST false ALT_MSSIO_36_MD_IBUF true ALT_MSSIO_36_OUT_DRIVE 8 ALT_MSSIO_36_RES_PULL UP ALT_MSSIO_36_SCHMITT_TRIGGER false ALT_MSSIO_37_ATP_EN false ALT_MSSIO_37_CLAMP_DIODE false ALT_MSSIO_37_LPMD_IBUF false ALT_MSSIO_37_LPMD_OBUF false ALT_MSSIO_37_LP_PERSIST false ALT_MSSIO_37_MD_IBUF true ALT_MSSIO_37_OUT_DRIVE 8 ALT_MSSIO_37_RES_PULL UP ALT_MSSIO_37_SCHMITT_TRIGGER false ALT_MSSIO_3_ATP_EN false ALT_MSSIO_3_CLAMP_DIODE false ALT_MSSIO_3_LPMD_IBUF false ALT_MSSIO_3_LPMD_OBUF false ALT_MSSIO_3_LP_PERSIST false ALT_MSSIO_3_MD_IBUF true ALT_MSSIO_3_OUT_DRIVE 8 ALT_MSSIO_3_RES_PULL UP ALT_MSSIO_3_SCHMITT_TRIGGER false ALT_MSSIO_4_ATP_EN false ALT_MSSIO_4_CLAMP_DIODE false ALT_MSSIO_4_LPMD_IBUF false ALT_MSSIO_4_LPMD_OBUF false ALT_MSSIO_4_LP_PERSIST false ALT_MSSIO_4_MD_IBUF true ALT_MSSIO_4_OUT_DRIVE 8 ALT_MSSIO_4_RES_PULL UP ALT_MSSIO_4_SCHMITT_TRIGGER false ALT_MSSIO_5_ATP_EN false ALT_MSSIO_5_CLAMP_DIODE false ALT_MSSIO_5_LPMD_IBUF false ALT_MSSIO_5_LPMD_OBUF false ALT_MSSIO_5_LP_PERSIST false ALT_MSSIO_5_MD_IBUF true ALT_MSSIO_5_OUT_DRIVE 8 ALT_MSSIO_5_RES_PULL UP ALT_MSSIO_5_SCHMITT_TRIGGER false ALT_MSSIO_6_ATP_EN false ALT_MSSIO_6_CLAMP_DIODE false ALT_MSSIO_6_LPMD_IBUF false ALT_MSSIO_6_LPMD_OBUF false ALT_MSSIO_6_LP_PERSIST false ALT_MSSIO_6_MD_IBUF true ALT_MSSIO_6_OUT_DRIVE 8 ALT_MSSIO_6_RES_PULL UP ALT_MSSIO_6_SCHMITT_TRIGGER false ALT_MSSIO_7_ATP_EN false ALT_MSSIO_7_CLAMP_DIODE false ALT_MSSIO_7_LPMD_IBUF false ALT_MSSIO_7_LPMD_OBUF false ALT_MSSIO_7_LP_PERSIST false ALT_MSSIO_7_MD_IBUF true ALT_MSSIO_7_OUT_DRIVE 8 ALT_MSSIO_7_RES_PULL UP ALT_MSSIO_7_SCHMITT_TRIGGER false ALT_MSSIO_8_ATP_EN false ALT_MSSIO_8_CLAMP_DIODE false ALT_MSSIO_8_LPMD_IBUF false ALT_MSSIO_8_LPMD_OBUF false ALT_MSSIO_8_LP_PERSIST false ALT_MSSIO_8_MD_IBUF true ALT_MSSIO_8_OUT_DRIVE 8 ALT_MSSIO_8_RES_PULL UP ALT_MSSIO_8_SCHMITT_TRIGGER false ALT_MSSIO_9_ATP_EN false ALT_MSSIO_9_CLAMP_DIODE false ALT_MSSIO_9_LPMD_IBUF false ALT_MSSIO_9_LPMD_OBUF false ALT_MSSIO_9_LP_PERSIST false ALT_MSSIO_9_MD_IBUF true ALT_MSSIO_9_OUT_DRIVE 8 ALT_MSSIO_9_RES_PULL UP ALT_MSSIO_9_SCHMITT_TRIGGER false BANK2_VOLTAGE 3.3 BANK4_VOLTAGE 1.8 BANK5_VOLTAGE 3.3 CAN_0 UNUSED CAN_0_TX_EBL_N UNUSED CAN_1 UNUSED CAN_1_TX_EBL_N UNUSED CAN_CLK_FREQ 80 CAN_CLK_SOURCE MSS_PLL CORE_UP UNUSED CRYPTO UNUSED CRYPTO_DLL_JITTER_TOLERANCE MEDIUM_LOW CRYPTO_ENABLE_ALARM false CRYPTO_ENABLE_BUSERROR false CRYPTO_ENABLE_BUSY true CRYPTO_ENABLE_COMPLETE false CRYPTO_ENABLE_DLL_LOCK true CRYPTO_ENABLE_MESH false CRYPTO_ENABLE_STREAMING false CRYPTO_MSS_CLK_FREQ 200 CRYPTO_USE_EMBEDDED_DLL true DDR3_ADDRESS_MIRROR false DDR3_ADDRESS_ORDERING CHIP_ROW_BANK_COL DDR3_BANK_ADDR_WIDTH 3 DDR3_BURST_LENGTH 0 DDR3_CAS_ADDITIVE_LATENCY 0 DDR3_CAS_LATENCY 5 DDR3_CAS_WRITE_LATENCY 5 DDR3_CLOCK_DDR 666 DDR3_COL_ADDR_WIDTH 11 DDR3_CONTROLLER_ADD_CMD_DRIVE 34 DDR3_CONTROLLER_CLK_DRIVE 34 DDR3_CONTROLLER_DQS_DRIVE 34 DDR3_CONTROLLER_DQS_ODT 60 DDR3_CONTROLLER_DQ_DRIVE 34 DDR3_CONTROLLER_DQ_ODT 120 DDR3_DM_MODE DM DDR3_DQDQS_TRAINING_OFFSET 1 DDR3_ENABLE_ECC false DDR3_ENABLE_LOOKAHEAD_PRECHARGE_ACTIVATE false DDR3_MEMORY_FORMAT COMPONENT DDR3_NB_CLKS 1 DDR3_NB_RANKS 1 DDR3_ODT_ENABLE_RD_RNK0_ODT0 false DDR3_ODT_ENABLE_RD_RNK0_ODT1 false DDR3_ODT_ENABLE_RD_RNK1_ODT0 false DDR3_ODT_ENABLE_RD_RNK1_ODT1 false DDR3_ODT_ENABLE_WR_RNK0_ODT0 false DDR3_ODT_ENABLE_WR_RNK0_ODT1 false DDR3_ODT_ENABLE_WR_RNK1_ODT0 false DDR3_ODT_ENABLE_WR_RNK1_ODT1 false DDR3_OUTPUT_DRIVE_STRENGTH RZQ6 DDR3_PARTIAL_ARRAY_SELF_REFRESH FULL DDR3_READ_BURST_TYPE SEQUENTIAL DDR3_ROW_ADDR_WIDTH 13 DDR3_RTT_NOM DISABLED DDR3_RTT_WR OFF DDR3_SELF_REFRESH_TEMPERATURE NORMAL DDR3_TIMING_FAW 40 DDR3_TIMING_RAS 35 DDR3_TIMING_RC 47.5 DDR3_TIMING_RCD 12.5 DDR3_TIMING_REFI 7.8 DDR3_TIMING_RFC 110 DDR3_TIMING_RP 12.5 DDR3_TIMING_RRD 6.25 DDR3_TIMING_RTP 8 DDR3_TIMING_WR 18 DDR3_TIMING_WTR 4 DDR3_WIDTH 32 DDR3_ZQ_CALIB_PERIOD 200 DDR3_ZQ_CALIB_TYPE 0 DDR3_ZQ_CAL_INIT_TIME 512 DDR3_ZQ_CAL_L_TIME 256 DDR3_ZQ_CAL_S_TIME 64 DDR4_ADDRESS_MIRROR false DDR4_ADDRESS_ORDERING CHIP_ROW_BG_BANK_COL DDR4_AUTO_SELF_REFRESH 3 DDR4_BANK_ADDR_WIDTH 2 DDR4_BANK_GROUP_ADDRESS_WIDTH 1 DDR4_BURST_LENGTH 0 DDR4_CAS_ADDITIVE_LATENCY 0 DDR4_CAS_LATENCY 12 DDR4_CAS_WRITE_LATENCY 11 DDR4_CA_PARITY_LATENCY_MODE 0 DDR4_CLOCK_DDR 800 DDR4_COL_ADDR_WIDTH 10 DDR4_CONTROLLER_ADD_CMD_DRIVE 34 DDR4_CONTROLLER_CLK_DRIVE 48 DDR4_CONTROLLER_DQS_DRIVE 48 DDR4_CONTROLLER_DQS_ODT 120 DDR4_CONTROLLER_DQ_DRIVE 48 DDR4_CONTROLLER_DQ_ODT 120 DDR4_DM_MODE DM DDR4_DQDQS_TRAINING_OFFSET 1 DDR4_ENABLE_ECC false DDR4_ENABLE_LOOKAHEAD_PRECHARGE_ACTIVATE false DDR4_ENABLE_PAR_ALERT false DDR4_GRANULARITY_MODE 0 DDR4_INTERNAL_VREF_MONITER 0 DDR4_MEMORY_FORMAT COMPONENT DDR4_NB_CLKS 1 DDR4_NB_RANKS 1 DDR4_ODT_ENABLE_RD_RNK0_ODT0 false DDR4_ODT_ENABLE_RD_RNK0_ODT1 false DDR4_ODT_ENABLE_RD_RNK1_ODT0 false DDR4_ODT_ENABLE_RD_RNK1_ODT1 false DDR4_ODT_ENABLE_WR_RNK0_ODT0 false DDR4_ODT_ENABLE_WR_RNK0_ODT1 false DDR4_ODT_ENABLE_WR_RNK1_ODT0 false DDR4_ODT_ENABLE_WR_RNK1_ODT1 false DDR4_OUTPUT_DRIVE_STRENGTH RZQ7 DDR4_POWERDOWN_INPUT_BUFFER 1 DDR4_READ_BURST_TYPE SEQUENTIAL DDR4_READ_PREAMBLE 0 DDR4_ROW_ADDR_WIDTH 15 DDR4_RTT_NOM RZQ4 DDR4_RTT_PARK 0 DDR4_RTT_WR OFF DDR4_SELF_REFRESH_ABORT_MODE 0 DDR4_TEMPERATURE_REFRESH_MODE 0 DDR4_TEMPERATURE_REFRESH_RANGE NORMAL DDR4_TIMING_CCD_L 5 DDR4_TIMING_CCD_S 4 DDR4_TIMING_FAW 25 DDR4_TIMING_RAS 35 DDR4_TIMING_RC 50 DDR4_TIMING_RCD 15 DDR4_TIMING_REFI 7.8 DDR4_TIMING_RFC 160 DDR4_TIMING_RP 15 DDR4_TIMING_RRD_L 5 DDR4_TIMING_RRD_S 4 DDR4_TIMING_RTP 7.5 DDR4_TIMING_WR 15 DDR4_TIMING_WTR_L 6 DDR4_TIMING_WTR_S 2 DDR4_VREF_CA 45 DDR4_VREF_CALIB_ENABLE 1 DDR4_VREF_CALIB_RANGE 1 DDR4_VREF_CALIB_VALUE 64.5 DDR4_VREF_DATA 65 DDR4_WIDTH 32 DDR4_WRITE_PREAMBLE 0 DDR4_ZQ_CALIB_PERIOD 200 DDR4_ZQ_CALIB_TYPE 0 DDR4_ZQ_CAL_INIT_TIME 1024 DDR4_ZQ_CAL_L_TIME 512 DDR4_ZQ_CAL_S_TIME 128 DDR_CACHED_32BIT_MEM_SIZE 32 DDR_CACHED_32BIT_MEM_UNIT MB DDR_CACHED_64BIT_MEM_SIZE 1888 DDR_CACHED_64BIT_MEM_UNIT MB DDR_NON_CACHED_32BIT_MEM_SIZE 128 DDR_NON_CACHED_32BIT_MEM_UNIT MB DDR_NON_CACHED_64BIT_MEM_SIZE 0 DDR_NON_CACHED_64BIT_MEM_UNIT GB DDR_REFCLK DEDICATED_IO DDR_SDRAM_TYPE LPDDR4 DIE MPFS250T_ES EMMC MSSIO_B4 EMMC_DATA_7_4 MSSIO_B4 EMMC_SD_CLK_SOURCE MSS_PLL EMMC_SD_SDIO_FREQ 200 EMMC_SD_SWITCHING ENABLED_SD EMMC_SPEED_MODE HIGH_SPEED_200 ENABLE_FEEDBACK_PORTS false EXPOSE_BOOT_STATUS_PORTS false FF_IN_PROGRESS UNUSED FIC_0_AXI4_INITIATOR_USED false FIC_0_AXI4_TARGET_USED false FIC_0_EMBEDDED_DLL_JITTER_RANGE LOW FIC_0_EMBEDDED_DLL_USED false FIC_1_AXI4_INITIATOR_USED false FIC_1_AXI4_TARGET_USED true FIC_1_EMBEDDED_DLL_JITTER_RANGE MEDIUM_LOW FIC_1_EMBEDDED_DLL_USED true FIC_2_AXI4_TARGET_USED false FIC_2_EMBEDDED_DLL_JITTER_RANGE LOW FIC_2_EMBEDDED_DLL_USED false FIC_3_APB_INITIATOR_USED true FIC_3_EMBEDDED_DLL_JITTER_RANGE LOW FIC_3_EMBEDDED_DLL_USED false FLASH_VALID UNUSED FREQOUT UNUSED G5C_IOOUT UNUSED GPIO_0_0 UNUSED GPIO_0_0_7_RESET_SOURCE MSS GPIO_0_0_DIR IN GPIO_0_1 UNUSED GPIO_0_10 UNUSED GPIO_0_10_DIR IN GPIO_0_11 UNUSED GPIO_0_11_DIR IN GPIO_0_12 UNUSED GPIO_0_12_DIR IN GPIO_0_13 UNUSED GPIO_0_13_DIR IN GPIO_0_1_DIR IN GPIO_0_2 UNUSED GPIO_0_2_DIR IN GPIO_0_3 UNUSED GPIO_0_3_DIR IN GPIO_0_4 UNUSED GPIO_0_4_DIR IN GPIO_0_5 UNUSED GPIO_0_5_DIR IN GPIO_0_6 UNUSED GPIO_0_6_DIR IN GPIO_0_7 UNUSED GPIO_0_7_DIR IN GPIO_0_8 UNUSED GPIO_0_8_13_RESET_SOURCE MSS GPIO_0_8_DIR IN GPIO_0_9 UNUSED GPIO_0_9_DIR IN GPIO_1_0 UNUSED GPIO_1_0_7_RESET_SOURCE MSS GPIO_1_0_DIR IN GPIO_1_1 UNUSED GPIO_1_10 UNUSED GPIO_1_10_DIR IN GPIO_1_11 UNUSED GPIO_1_11_DIR IN GPIO_1_12 MSSIO_B2 GPIO_1_12_DIR OUT GPIO_1_13 UNUSED GPIO_1_13_DIR IN GPIO_1_14 UNUSED GPIO_1_14_DIR IN GPIO_1_15 UNUSED GPIO_1_15_DIR IN GPIO_1_16 MSSIO_B2 GPIO_1_16_23_RESET_SOURCE MSS GPIO_1_16_DIR OUT GPIO_1_17 UNUSED GPIO_1_17_DIR IN GPIO_1_18 UNUSED GPIO_1_18_DIR IN GPIO_1_19 UNUSED GPIO_1_19_DIR IN GPIO_1_1_DIR IN GPIO_1_2 UNUSED GPIO_1_20 MSSIO_B2 GPIO_1_20_DIR OUT GPIO_1_21 UNUSED GPIO_1_21_DIR IN GPIO_1_22 UNUSED GPIO_1_22_DIR IN GPIO_1_23 MSSIO_B2 GPIO_1_23_DIR OUT GPIO_1_2_DIR IN GPIO_1_3 UNUSED GPIO_1_3_DIR IN GPIO_1_4 UNUSED GPIO_1_4_DIR IN GPIO_1_5 UNUSED GPIO_1_5_DIR IN GPIO_1_6 UNUSED GPIO_1_6_DIR IN GPIO_1_7 UNUSED GPIO_1_7_DIR IN GPIO_1_8 UNUSED GPIO_1_8_15_RESET_SOURCE MSS GPIO_1_8_DIR IN GPIO_1_9 UNUSED GPIO_1_9_DIR IN GPIO_2_0 UNUSED GPIO_2_0_7_RESET_SOURCE MSS GPIO_2_0_DIR IN GPIO_2_1 FABRIC GPIO_2_10 UNUSED GPIO_2_10_DIR IN GPIO_2_11 UNUSED GPIO_2_11_DIR IN GPIO_2_12 UNUSED GPIO_2_12_DIR IN GPIO_2_13 UNUSED GPIO_2_13_DIR IN GPIO_2_14 UNUSED GPIO_2_14_DIR IN GPIO_2_15 UNUSED GPIO_2_15_DIR IN GPIO_2_16 UNUSED GPIO_2_16_23_RESET_SOURCE MSS GPIO_2_16_DIR IN GPIO_2_17 UNUSED GPIO_2_17_DIR IN GPIO_2_18 FABRIC GPIO_2_18_DIR OUT GPIO_2_19 FABRIC GPIO_2_19_DIR OUT GPIO_2_1_DIR OUT GPIO_2_2 FABRIC GPIO_2_20 UNUSED GPIO_2_20_DIR IN GPIO_2_21 UNUSED GPIO_2_21_DIR IN GPIO_2_22 UNUSED GPIO_2_22_DIR IN GPIO_2_23 UNUSED GPIO_2_23_DIR IN GPIO_2_24 UNUSED GPIO_2_24_31_RESET_SOURCE MSS GPIO_2_24_DIR IN GPIO_2_25 FABRIC GPIO_2_25_DIR IN GPIO_2_26 UNUSED GPIO_2_26_DIR IN GPIO_2_27 UNUSED GPIO_2_27_DIR IN GPIO_2_28 UNUSED GPIO_2_28_DIR IN GPIO_2_29 UNUSED GPIO_2_29_DIR IN GPIO_2_2_DIR OUT GPIO_2_3 FABRIC GPIO_2_30 UNUSED GPIO_2_30_DIR IN GPIO_2_31 UNUSED GPIO_2_31_DIR IN GPIO_2_3_DIR OUT GPIO_2_4 FABRIC GPIO_2_4_DIR OUT GPIO_2_5 UNUSED GPIO_2_5_DIR IN GPIO_2_6 UNUSED GPIO_2_6_DIR IN GPIO_2_7 UNUSED GPIO_2_7_DIR IN GPIO_2_8 FABRIC GPIO_2_8_15_RESET_SOURCE MSS GPIO_2_8_DIR OUT GPIO_2_9 FABRIC GPIO_2_9_DIR OUT GPIO_INTERRUPT_FAB_CR_DATA 0x00000000 I2C_0 FABRIC I2C_0_BAUD_RATE_CLOCK FABRIC I2C_0_SMBUS UNUSED I2C_0_SPEED_MODE STANDARD I2C_1 UNUSED I2C_1_BAUD_RATE_CLOCK UNUSED I2C_1_SMBUS UNUSED I2C_1_SPEED_MODE STANDARD INTERNAL_DEBUG false INTERRUPT true IO_REFCLK_FREQ 125 JTAG_TRACE false JTAG_TRACE_CONTROL_VIA_FABRIC false L2CACHE_DMA_WAY0 true L2CACHE_DMA_WAY1 true L2CACHE_DMA_WAY10 false L2CACHE_DMA_WAY11 false L2CACHE_DMA_WAY12 false L2CACHE_DMA_WAY13 false L2CACHE_DMA_WAY14 false L2CACHE_DMA_WAY15 false L2CACHE_DMA_WAY2 true L2CACHE_DMA_WAY3 true L2CACHE_DMA_WAY4 true L2CACHE_DMA_WAY5 true L2CACHE_DMA_WAY6 true L2CACHE_DMA_WAY7 true L2CACHE_DMA_WAY8 false L2CACHE_DMA_WAY9 false L2CACHE_E51_D_WAY0 true L2CACHE_E51_D_WAY1 true L2CACHE_E51_D_WAY10 false L2CACHE_E51_D_WAY11 false L2CACHE_E51_D_WAY12 false L2CACHE_E51_D_WAY13 false L2CACHE_E51_D_WAY14 false L2CACHE_E51_D_WAY15 false L2CACHE_E51_D_WAY2 true L2CACHE_E51_D_WAY3 true L2CACHE_E51_D_WAY4 true L2CACHE_E51_D_WAY5 true L2CACHE_E51_D_WAY6 true L2CACHE_E51_D_WAY7 true L2CACHE_E51_D_WAY8 false L2CACHE_E51_D_WAY9 false L2CACHE_E51_I_WAY0 true L2CACHE_E51_I_WAY1 true L2CACHE_E51_I_WAY10 false L2CACHE_E51_I_WAY11 false L2CACHE_E51_I_WAY12 false L2CACHE_E51_I_WAY13 false L2CACHE_E51_I_WAY14 false L2CACHE_E51_I_WAY15 false L2CACHE_E51_I_WAY2 true L2CACHE_E51_I_WAY3 true L2CACHE_E51_I_WAY4 true L2CACHE_E51_I_WAY5 true L2CACHE_E51_I_WAY6 true L2CACHE_E51_I_WAY7 true L2CACHE_E51_I_WAY8 false L2CACHE_E51_I_WAY9 false L2CACHE_LIM_SIZE 4 L2CACHE_PORT_0_WAY0 true L2CACHE_PORT_0_WAY1 true L2CACHE_PORT_0_WAY10 false L2CACHE_PORT_0_WAY11 false L2CACHE_PORT_0_WAY12 false L2CACHE_PORT_0_WAY13 false L2CACHE_PORT_0_WAY14 false L2CACHE_PORT_0_WAY15 false L2CACHE_PORT_0_WAY2 true L2CACHE_PORT_0_WAY3 true L2CACHE_PORT_0_WAY4 true L2CACHE_PORT_0_WAY5 true L2CACHE_PORT_0_WAY6 true L2CACHE_PORT_0_WAY7 true L2CACHE_PORT_0_WAY8 false L2CACHE_PORT_0_WAY9 false L2CACHE_PORT_1_WAY0 true L2CACHE_PORT_1_WAY1 true L2CACHE_PORT_1_WAY10 false L2CACHE_PORT_1_WAY11 false L2CACHE_PORT_1_WAY12 false L2CACHE_PORT_1_WAY13 false L2CACHE_PORT_1_WAY14 false L2CACHE_PORT_1_WAY15 false L2CACHE_PORT_1_WAY2 true L2CACHE_PORT_1_WAY3 true L2CACHE_PORT_1_WAY4 true L2CACHE_PORT_1_WAY5 true L2CACHE_PORT_1_WAY6 true L2CACHE_PORT_1_WAY7 true L2CACHE_PORT_1_WAY8 false L2CACHE_PORT_1_WAY9 false L2CACHE_PORT_2_WAY0 true L2CACHE_PORT_2_WAY1 true L2CACHE_PORT_2_WAY10 false L2CACHE_PORT_2_WAY11 false L2CACHE_PORT_2_WAY12 false L2CACHE_PORT_2_WAY13 false L2CACHE_PORT_2_WAY14 false L2CACHE_PORT_2_WAY15 false L2CACHE_PORT_2_WAY2 true L2CACHE_PORT_2_WAY3 true L2CACHE_PORT_2_WAY4 true L2CACHE_PORT_2_WAY5 true L2CACHE_PORT_2_WAY6 true L2CACHE_PORT_2_WAY7 true L2CACHE_PORT_2_WAY8 false L2CACHE_PORT_2_WAY9 false L2CACHE_PORT_3_WAY0 true L2CACHE_PORT_3_WAY1 true L2CACHE_PORT_3_WAY10 false L2CACHE_PORT_3_WAY11 false L2CACHE_PORT_3_WAY12 false L2CACHE_PORT_3_WAY13 false L2CACHE_PORT_3_WAY14 false L2CACHE_PORT_3_WAY15 false L2CACHE_PORT_3_WAY2 true L2CACHE_PORT_3_WAY3 true L2CACHE_PORT_3_WAY4 true L2CACHE_PORT_3_WAY5 true L2CACHE_PORT_3_WAY6 true L2CACHE_PORT_3_WAY7 true L2CACHE_PORT_3_WAY8 false L2CACHE_PORT_3_WAY9 false L2CACHE_SCRATCH_SIZE 4 L2CACHE_U54_1_D_WAY0 true L2CACHE_U54_1_D_WAY1 true L2CACHE_U54_1_D_WAY10 false L2CACHE_U54_1_D_WAY11 false L2CACHE_U54_1_D_WAY12 false L2CACHE_U54_1_D_WAY13 false L2CACHE_U54_1_D_WAY14 false L2CACHE_U54_1_D_WAY15 false L2CACHE_U54_1_D_WAY2 true L2CACHE_U54_1_D_WAY3 true L2CACHE_U54_1_D_WAY4 true L2CACHE_U54_1_D_WAY5 true L2CACHE_U54_1_D_WAY6 true L2CACHE_U54_1_D_WAY7 true L2CACHE_U54_1_D_WAY8 false L2CACHE_U54_1_D_WAY9 false L2CACHE_U54_1_I_WAY0 true L2CACHE_U54_1_I_WAY1 true L2CACHE_U54_1_I_WAY10 false L2CACHE_U54_1_I_WAY11 false L2CACHE_U54_1_I_WAY12 false L2CACHE_U54_1_I_WAY13 false L2CACHE_U54_1_I_WAY14 false L2CACHE_U54_1_I_WAY15 false L2CACHE_U54_1_I_WAY2 true L2CACHE_U54_1_I_WAY3 true L2CACHE_U54_1_I_WAY4 true L2CACHE_U54_1_I_WAY5 true L2CACHE_U54_1_I_WAY6 true L2CACHE_U54_1_I_WAY7 true L2CACHE_U54_1_I_WAY8 false L2CACHE_U54_1_I_WAY9 false L2CACHE_U54_2_D_WAY0 true L2CACHE_U54_2_D_WAY1 true L2CACHE_U54_2_D_WAY10 false L2CACHE_U54_2_D_WAY11 false L2CACHE_U54_2_D_WAY12 false L2CACHE_U54_2_D_WAY13 false L2CACHE_U54_2_D_WAY14 false L2CACHE_U54_2_D_WAY15 false L2CACHE_U54_2_D_WAY2 true L2CACHE_U54_2_D_WAY3 true L2CACHE_U54_2_D_WAY4 true L2CACHE_U54_2_D_WAY5 true L2CACHE_U54_2_D_WAY6 true L2CACHE_U54_2_D_WAY7 true L2CACHE_U54_2_D_WAY8 false L2CACHE_U54_2_D_WAY9 false L2CACHE_U54_2_I_WAY0 true L2CACHE_U54_2_I_WAY1 true L2CACHE_U54_2_I_WAY10 false L2CACHE_U54_2_I_WAY11 false L2CACHE_U54_2_I_WAY12 false L2CACHE_U54_2_I_WAY13 false L2CACHE_U54_2_I_WAY14 false L2CACHE_U54_2_I_WAY15 false L2CACHE_U54_2_I_WAY2 true L2CACHE_U54_2_I_WAY3 true L2CACHE_U54_2_I_WAY4 true L2CACHE_U54_2_I_WAY5 true L2CACHE_U54_2_I_WAY6 true L2CACHE_U54_2_I_WAY7 true L2CACHE_U54_2_I_WAY8 false L2CACHE_U54_2_I_WAY9 false L2CACHE_U54_3_D_WAY0 true L2CACHE_U54_3_D_WAY1 true L2CACHE_U54_3_D_WAY10 false L2CACHE_U54_3_D_WAY11 false L2CACHE_U54_3_D_WAY12 false L2CACHE_U54_3_D_WAY13 false L2CACHE_U54_3_D_WAY14 false L2CACHE_U54_3_D_WAY15 false L2CACHE_U54_3_D_WAY2 true L2CACHE_U54_3_D_WAY3 true L2CACHE_U54_3_D_WAY4 true L2CACHE_U54_3_D_WAY5 true L2CACHE_U54_3_D_WAY6 true L2CACHE_U54_3_D_WAY7 true L2CACHE_U54_3_D_WAY8 false L2CACHE_U54_3_D_WAY9 false L2CACHE_U54_3_I_WAY0 true L2CACHE_U54_3_I_WAY1 true L2CACHE_U54_3_I_WAY10 false L2CACHE_U54_3_I_WAY11 false L2CACHE_U54_3_I_WAY12 false L2CACHE_U54_3_I_WAY13 false L2CACHE_U54_3_I_WAY14 false L2CACHE_U54_3_I_WAY15 false L2CACHE_U54_3_I_WAY2 true L2CACHE_U54_3_I_WAY3 true L2CACHE_U54_3_I_WAY4 true L2CACHE_U54_3_I_WAY5 true L2CACHE_U54_3_I_WAY6 true L2CACHE_U54_3_I_WAY7 true L2CACHE_U54_3_I_WAY8 false L2CACHE_U54_3_I_WAY9 false L2CACHE_U54_4_D_WAY0 true L2CACHE_U54_4_D_WAY1 true L2CACHE_U54_4_D_WAY10 false L2CACHE_U54_4_D_WAY11 false L2CACHE_U54_4_D_WAY12 false L2CACHE_U54_4_D_WAY13 false L2CACHE_U54_4_D_WAY14 false L2CACHE_U54_4_D_WAY15 false L2CACHE_U54_4_D_WAY2 true L2CACHE_U54_4_D_WAY3 true L2CACHE_U54_4_D_WAY4 true L2CACHE_U54_4_D_WAY5 true L2CACHE_U54_4_D_WAY6 true L2CACHE_U54_4_D_WAY7 true L2CACHE_U54_4_D_WAY8 false L2CACHE_U54_4_D_WAY9 false L2CACHE_U54_4_I_WAY0 true L2CACHE_U54_4_I_WAY1 true L2CACHE_U54_4_I_WAY10 false L2CACHE_U54_4_I_WAY11 false L2CACHE_U54_4_I_WAY12 false L2CACHE_U54_4_I_WAY13 false L2CACHE_U54_4_I_WAY14 false L2CACHE_U54_4_I_WAY15 false L2CACHE_U54_4_I_WAY2 true L2CACHE_U54_4_I_WAY3 true L2CACHE_U54_4_I_WAY4 true L2CACHE_U54_4_I_WAY5 true L2CACHE_U54_4_I_WAY6 true L2CACHE_U54_4_I_WAY7 true L2CACHE_U54_4_I_WAY8 false L2CACHE_U54_4_I_WAY9 false LOCK_DOWN_B2_IOS false LOCK_DOWN_B4_IOS false LOCK_DOWN_DDR_IOS false LOCK_DOWN_SGMII_IOS false LPDDR3_ADDRESS_ORDERING CHIP_ROW_BANK_COL LPDDR3_BANK_ADDR_WIDTH 3 LPDDR3_CLOCK_DDR 666 LPDDR3_COL_ADDR_WIDTH 11 LPDDR3_CONTROLLER_ADD_CMD_DRIVE 40 LPDDR3_CONTROLLER_CLK_DRIVE 48 LPDDR3_CONTROLLER_DQS_DRIVE 48 LPDDR3_CONTROLLER_DQS_ODT 120 LPDDR3_CONTROLLER_DQ_DRIVE 48 LPDDR3_CONTROLLER_DQ_ODT 120 LPDDR3_DATA_LATENCY RL10WL6 LPDDR3_DM_MODE DM LPDDR3_DQDQS_TRAINING_OFFSET 1 LPDDR3_DQ_ODT DISABLE LPDDR3_ENABLE_ECC false LPDDR3_ENABLE_LOOKAHEAD_PRECHARGE_ACTIVATE false LPDDR3_MEMORY_FORMAT COMPONENT LPDDR3_ODT_ENABLE_RD_RNK0_ODT0 false LPDDR3_ODT_ENABLE_WR_RNK0_ODT0 false LPDDR3_OUTPUT_DRIVE_STRENGTH PDPU34P3 LPDDR3_POWERDOWN_ODT 0 LPDDR3_ROW_ADDR_WIDTH 14 LPDDR3_TIMING_FAW 50 LPDDR3_TIMING_MRR 4 LPDDR3_TIMING_MRW 10 LPDDR3_TIMING_RAS 42 LPDDR3_TIMING_RC 57 LPDDR3_TIMING_RCD 15 LPDDR3_TIMING_REFI 3.9 LPDDR3_TIMING_RFC 130 LPDDR3_TIMING_RP 15 LPDDR3_TIMING_RRD 10 LPDDR3_TIMING_RTP 8 LPDDR3_TIMING_WR 18 LPDDR3_TIMING_WTR 4 LPDDR3_WIDTH 32 LPDDR3_ZQ_CALIB_PERIOD 200 LPDDR3_ZQ_CALIB_TYPE 0 LPDDR3_ZQ_CAL_INIT_TIME 1 LPDDR3_ZQ_CAL_L_TIME 360 LPDDR3_ZQ_CAL_R_TIME 50 LPDDR3_ZQ_CAL_S_TIME 90 LPDDR4_ADDRESS_ORDERING CHIP_ROW_BANK_COL LPDDR4_BANK_ADDR_WIDTH 3 LPDDR4_CA_ODT RZQ4 LPDDR4_CLOCK_DDR 800 LPDDR4_COL_ADDR_WIDTH 10 LPDDR4_CONTROLLER_ADD_CMD_DRIVE 34 LPDDR4_CONTROLLER_CLK_DRIVE 34 LPDDR4_CONTROLLER_DQS_DRIVE 40 LPDDR4_CONTROLLER_DQS_ODT 40 LPDDR4_CONTROLLER_DQ_DRIVE 40 LPDDR4_CONTROLLER_DQ_ODT 80 LPDDR4_DM_MODE DM LPDDR4_DQDQS_TRAINING_OFFSET 6 LPDDR4_DQ_ODT RZQ2 LPDDR4_DRIVE_STRENGTH RZQ6 LPDDR4_ENABLE_ECC false LPDDR4_ENABLE_LOOKAHEAD_PRECHARGE_ACTIVATE false LPDDR4_MEMORY_FORMAT COMPONENT LPDDR4_ODTE_CA 0 LPDDR4_ODTE_CK 0 LPDDR4_ODTE_CS 0 LPDDR4_PULLUP_CAL VDDQ2P5 LPDDR4_RD_POSTAMBLE CK0P5 LPDDR4_RD_PREAMBLE STATIC LPDDR4_READ_LATENCY RL14 LPDDR4_ROW_ADDR_WIDTH 16 LPDDR4_SELF_REFRESH_ABORT_MODE 0 LPDDR4_SOC_ODT RZQ6 LPDDR4_TIMING_FAW 40 LPDDR4_TIMING_MRR 8 LPDDR4_TIMING_MRW 10 LPDDR4_TIMING_RAS 42 LPDDR4_TIMING_RC 63 LPDDR4_TIMING_RCD 18 LPDDR4_TIMING_REFI 3.905 LPDDR4_TIMING_RFC 380 LPDDR4_TIMING_RP 21 LPDDR4_TIMING_RRD 10 LPDDR4_TIMING_RTP 10 LPDDR4_TIMING_WR 18 LPDDR4_TIMING_WTR 8 LPDDR4_VREF_CA 50 LPDDR4_VREF_CALIB_ENABLE 1 LPDDR4_VREF_CALIB_RANGE 1 LPDDR4_VREF_CALIB_VALUE 31.2 LPDDR4_VREF_DATA 15 LPDDR4_WIDTH 32 LPDDR4_WRITE_LATENCY WL8 LPDDR4_WR_POSTAMBLE CK0P5 LPDDR4_ZQ_CALIB_PERIOD 200 LPDDR4_ZQ_CAL_LATCH_TIME 30 LPDDR4_ZQ_CAL_R_TIME 50 LPDDR4_ZQ_CAL_TIME 1 LP_STATE UNUSED M2F_MONITOR UNUSED MAC_0 SGMII_IO_B5 MAC_0_MANAGEMENT MSSIO_B2_B MAC_0_OTHER UNUSED MAC_0_TSU UNUSED MAC_1 SGMII_IO_B5 MAC_1_MANAGEMENT UNUSED MAC_1_OTHER UNUSED MAC_1_TSU UNUSED MAC_SGMII_REFCLK DEDICATED_IO MAC_TSU_REFCLK DEDICATED_IO MMUART_0 FABRIC MMUART_0_MODE ASYNCHRONOUS MMUART_0_MODEM UNUSED MMUART_0_OTHER UNUSED MMUART_1 FABRIC MMUART_1_MODE ASYNCHRONOUS MMUART_1_MODEM UNUSED MMUART_1_OTHER UNUSED MMUART_2 UNUSED MMUART_3 UNUSED MMUART_4 UNUSED MODULE_NAME MSS_SEV MSSIO_0_ATP_EN false MSSIO_0_CLAMP_DIODE false MSSIO_0_LPMD_IBUF false MSSIO_0_LPMD_OBUF false MSSIO_0_LP_PERSIST false MSSIO_0_MD_IBUF true MSSIO_0_OUT_DRIVE 8 MSSIO_0_RES_PULL UP MSSIO_0_SCHMITT_TRIGGER false MSSIO_10_ATP_EN false MSSIO_10_CLAMP_DIODE false MSSIO_10_LPMD_IBUF false MSSIO_10_LPMD_OBUF false MSSIO_10_LP_PERSIST false MSSIO_10_MD_IBUF true MSSIO_10_OUT_DRIVE 8 MSSIO_10_RES_PULL UP MSSIO_10_SCHMITT_TRIGGER false MSSIO_11_ATP_EN false MSSIO_11_CLAMP_DIODE false MSSIO_11_LPMD_IBUF false MSSIO_11_LPMD_OBUF false MSSIO_11_LP_PERSIST false MSSIO_11_MD_IBUF true MSSIO_11_OUT_DRIVE 8 MSSIO_11_RES_PULL UP MSSIO_11_SCHMITT_TRIGGER false MSSIO_12_ATP_EN false MSSIO_12_CLAMP_DIODE false MSSIO_12_LPMD_IBUF false MSSIO_12_LPMD_OBUF false MSSIO_12_LP_PERSIST false MSSIO_12_MD_IBUF true MSSIO_12_OUT_DRIVE 8 MSSIO_12_RES_PULL UP MSSIO_12_SCHMITT_TRIGGER false MSSIO_13_ATP_EN false MSSIO_13_CLAMP_DIODE false MSSIO_13_LPMD_IBUF false MSSIO_13_LPMD_OBUF false MSSIO_13_LP_PERSIST false MSSIO_13_MD_IBUF true MSSIO_13_OUT_DRIVE 8 MSSIO_13_RES_PULL UP MSSIO_13_SCHMITT_TRIGGER false MSSIO_14_ATP_EN false MSSIO_14_CLAMP_DIODE false MSSIO_14_LPMD_IBUF false MSSIO_14_LPMD_OBUF false MSSIO_14_LP_PERSIST false MSSIO_14_MD_IBUF true MSSIO_14_OUT_DRIVE 8 MSSIO_14_RES_PULL UP MSSIO_14_SCHMITT_TRIGGER false MSSIO_15_ATP_EN false MSSIO_15_CLAMP_DIODE false MSSIO_15_LPMD_IBUF false MSSIO_15_LPMD_OBUF false MSSIO_15_LP_PERSIST false MSSIO_15_MD_IBUF true MSSIO_15_OUT_DRIVE 8 MSSIO_15_RES_PULL UP MSSIO_15_SCHMITT_TRIGGER false MSSIO_16_ATP_EN false MSSIO_16_CLAMP_DIODE false MSSIO_16_LPMD_IBUF false MSSIO_16_LPMD_OBUF false MSSIO_16_LP_PERSIST false MSSIO_16_MD_IBUF true MSSIO_16_OUT_DRIVE 8 MSSIO_16_RES_PULL UP MSSIO_16_SCHMITT_TRIGGER false MSSIO_17_ATP_EN false MSSIO_17_CLAMP_DIODE false MSSIO_17_LPMD_IBUF false MSSIO_17_LPMD_OBUF false MSSIO_17_LP_PERSIST false MSSIO_17_MD_IBUF true MSSIO_17_OUT_DRIVE 8 MSSIO_17_RES_PULL UP MSSIO_17_SCHMITT_TRIGGER false MSSIO_18_ATP_EN false MSSIO_18_CLAMP_DIODE false MSSIO_18_LPMD_IBUF false MSSIO_18_LPMD_OBUF false MSSIO_18_LP_PERSIST false MSSIO_18_MD_IBUF true MSSIO_18_OUT_DRIVE 8 MSSIO_18_RES_PULL UP MSSIO_18_SCHMITT_TRIGGER false MSSIO_19_ATP_EN false MSSIO_19_CLAMP_DIODE false MSSIO_19_LPMD_IBUF false MSSIO_19_LPMD_OBUF false MSSIO_19_LP_PERSIST false MSSIO_19_MD_IBUF true MSSIO_19_OUT_DRIVE 8 MSSIO_19_RES_PULL UP MSSIO_19_SCHMITT_TRIGGER false MSSIO_1_ATP_EN false MSSIO_1_CLAMP_DIODE false MSSIO_1_LPMD_IBUF false MSSIO_1_LPMD_OBUF false MSSIO_1_LP_PERSIST false MSSIO_1_MD_IBUF true MSSIO_1_OUT_DRIVE 8 MSSIO_1_RES_PULL UP MSSIO_1_SCHMITT_TRIGGER false MSSIO_20_ATP_EN false MSSIO_20_CLAMP_DIODE false MSSIO_20_LPMD_IBUF false MSSIO_20_LPMD_OBUF false MSSIO_20_LP_PERSIST false MSSIO_20_MD_IBUF true MSSIO_20_OUT_DRIVE 8 MSSIO_20_RES_PULL UP MSSIO_20_SCHMITT_TRIGGER false MSSIO_21_ATP_EN false MSSIO_21_CLAMP_DIODE false MSSIO_21_LPMD_IBUF false MSSIO_21_LPMD_OBUF false MSSIO_21_LP_PERSIST false MSSIO_21_MD_IBUF true MSSIO_21_OUT_DRIVE 8 MSSIO_21_RES_PULL UP MSSIO_21_SCHMITT_TRIGGER false MSSIO_22_ATP_EN false MSSIO_22_CLAMP_DIODE false MSSIO_22_LPMD_IBUF false MSSIO_22_LPMD_OBUF false MSSIO_22_LP_PERSIST false MSSIO_22_MD_IBUF true MSSIO_22_OUT_DRIVE 8 MSSIO_22_RES_PULL UP MSSIO_22_SCHMITT_TRIGGER false MSSIO_23_ATP_EN false MSSIO_23_CLAMP_DIODE false MSSIO_23_LPMD_IBUF false MSSIO_23_LPMD_OBUF false MSSIO_23_LP_PERSIST false MSSIO_23_MD_IBUF true MSSIO_23_OUT_DRIVE 8 MSSIO_23_RES_PULL UP MSSIO_23_SCHMITT_TRIGGER false MSSIO_24_ATP_EN false MSSIO_24_CLAMP_DIODE false MSSIO_24_LPMD_IBUF false MSSIO_24_LPMD_OBUF false MSSIO_24_LP_PERSIST false MSSIO_24_MD_IBUF true MSSIO_24_OUT_DRIVE 8 MSSIO_24_RES_PULL UP MSSIO_24_SCHMITT_TRIGGER false MSSIO_25_ATP_EN false MSSIO_25_CLAMP_DIODE false MSSIO_25_LPMD_IBUF false MSSIO_25_LPMD_OBUF false MSSIO_25_LP_PERSIST false MSSIO_25_MD_IBUF true MSSIO_25_OUT_DRIVE 8 MSSIO_25_RES_PULL UP MSSIO_25_SCHMITT_TRIGGER false MSSIO_26_ATP_EN false MSSIO_26_CLAMP_DIODE false MSSIO_26_LPMD_IBUF false MSSIO_26_LPMD_OBUF false MSSIO_26_LP_PERSIST false MSSIO_26_MD_IBUF true MSSIO_26_OUT_DRIVE 8 MSSIO_26_RES_PULL UP MSSIO_26_SCHMITT_TRIGGER false MSSIO_27_ATP_EN false MSSIO_27_CLAMP_DIODE false MSSIO_27_LPMD_IBUF false MSSIO_27_LPMD_OBUF false MSSIO_27_LP_PERSIST false MSSIO_27_MD_IBUF true MSSIO_27_OUT_DRIVE 8 MSSIO_27_RES_PULL UP MSSIO_27_SCHMITT_TRIGGER false MSSIO_28_ATP_EN false MSSIO_28_CLAMP_DIODE false MSSIO_28_LPMD_IBUF false MSSIO_28_LPMD_OBUF false MSSIO_28_LP_PERSIST false MSSIO_28_MD_IBUF true MSSIO_28_OUT_DRIVE 8 MSSIO_28_RES_PULL UP MSSIO_28_SCHMITT_TRIGGER false MSSIO_29_ATP_EN false MSSIO_29_CLAMP_DIODE false MSSIO_29_LPMD_IBUF false MSSIO_29_LPMD_OBUF false MSSIO_29_LP_PERSIST false MSSIO_29_MD_IBUF true MSSIO_29_OUT_DRIVE 8 MSSIO_29_RES_PULL UP MSSIO_29_SCHMITT_TRIGGER false MSSIO_2_ATP_EN false MSSIO_2_CLAMP_DIODE false MSSIO_2_LPMD_IBUF false MSSIO_2_LPMD_OBUF false MSSIO_2_LP_PERSIST false MSSIO_2_MD_IBUF true MSSIO_2_OUT_DRIVE 8 MSSIO_2_RES_PULL UP MSSIO_2_SCHMITT_TRIGGER false MSSIO_30_ATP_EN false MSSIO_30_CLAMP_DIODE false MSSIO_30_LPMD_IBUF false MSSIO_30_LPMD_OBUF false MSSIO_30_LP_PERSIST false MSSIO_30_MD_IBUF true MSSIO_30_OUT_DRIVE 8 MSSIO_30_RES_PULL UP MSSIO_30_SCHMITT_TRIGGER false MSSIO_31_ATP_EN false MSSIO_31_CLAMP_DIODE false MSSIO_31_LPMD_IBUF false MSSIO_31_LPMD_OBUF false MSSIO_31_LP_PERSIST false MSSIO_31_MD_IBUF true MSSIO_31_OUT_DRIVE 8 MSSIO_31_RES_PULL UP MSSIO_31_SCHMITT_TRIGGER false MSSIO_32_ATP_EN false MSSIO_32_CLAMP_DIODE false MSSIO_32_LPMD_IBUF false MSSIO_32_LPMD_OBUF false MSSIO_32_LP_PERSIST false MSSIO_32_MD_IBUF true MSSIO_32_OUT_DRIVE 8 MSSIO_32_RES_PULL UP MSSIO_32_SCHMITT_TRIGGER false MSSIO_33_ATP_EN false MSSIO_33_CLAMP_DIODE false MSSIO_33_LPMD_IBUF false MSSIO_33_LPMD_OBUF false MSSIO_33_LP_PERSIST false MSSIO_33_MD_IBUF true MSSIO_33_OUT_DRIVE 8 MSSIO_33_RES_PULL UP MSSIO_33_SCHMITT_TRIGGER false MSSIO_34_ATP_EN false MSSIO_34_CLAMP_DIODE false MSSIO_34_LPMD_IBUF false MSSIO_34_LPMD_OBUF false MSSIO_34_LP_PERSIST false MSSIO_34_MD_IBUF true MSSIO_34_OUT_DRIVE 8 MSSIO_34_RES_PULL UP MSSIO_34_SCHMITT_TRIGGER false MSSIO_35_ATP_EN false MSSIO_35_CLAMP_DIODE false MSSIO_35_LPMD_IBUF false MSSIO_35_LPMD_OBUF false MSSIO_35_LP_PERSIST false MSSIO_35_MD_IBUF true MSSIO_35_OUT_DRIVE 8 MSSIO_35_RES_PULL UP MSSIO_35_SCHMITT_TRIGGER false MSSIO_36_ATP_EN false MSSIO_36_CLAMP_DIODE false MSSIO_36_LPMD_IBUF false MSSIO_36_LPMD_OBUF false MSSIO_36_LP_PERSIST false MSSIO_36_MD_IBUF true MSSIO_36_OUT_DRIVE 8 MSSIO_36_RES_PULL UP MSSIO_36_SCHMITT_TRIGGER false MSSIO_37_ATP_EN false MSSIO_37_CLAMP_DIODE false MSSIO_37_LPMD_IBUF false MSSIO_37_LPMD_OBUF false MSSIO_37_LP_PERSIST false MSSIO_37_MD_IBUF true MSSIO_37_OUT_DRIVE 8 MSSIO_37_RES_PULL UP MSSIO_37_SCHMITT_TRIGGER false MSSIO_3_ATP_EN false MSSIO_3_CLAMP_DIODE false MSSIO_3_LPMD_IBUF false MSSIO_3_LPMD_OBUF false MSSIO_3_LP_PERSIST false MSSIO_3_MD_IBUF true MSSIO_3_OUT_DRIVE 8 MSSIO_3_RES_PULL UP MSSIO_3_SCHMITT_TRIGGER false MSSIO_4_ATP_EN false MSSIO_4_CLAMP_DIODE false MSSIO_4_LPMD_IBUF false MSSIO_4_LPMD_OBUF false MSSIO_4_LP_PERSIST false MSSIO_4_MD_IBUF true MSSIO_4_OUT_DRIVE 8 MSSIO_4_RES_PULL UP MSSIO_4_SCHMITT_TRIGGER false MSSIO_5_ATP_EN false MSSIO_5_CLAMP_DIODE false MSSIO_5_LPMD_IBUF false MSSIO_5_LPMD_OBUF false MSSIO_5_LP_PERSIST false MSSIO_5_MD_IBUF true MSSIO_5_OUT_DRIVE 8 MSSIO_5_RES_PULL UP MSSIO_5_SCHMITT_TRIGGER false MSSIO_6_ATP_EN false MSSIO_6_CLAMP_DIODE false MSSIO_6_LPMD_IBUF false MSSIO_6_LPMD_OBUF false MSSIO_6_LP_PERSIST false MSSIO_6_MD_IBUF true MSSIO_6_OUT_DRIVE 8 MSSIO_6_RES_PULL UP MSSIO_6_SCHMITT_TRIGGER false MSSIO_7_ATP_EN false MSSIO_7_CLAMP_DIODE false MSSIO_7_LPMD_IBUF false MSSIO_7_LPMD_OBUF false MSSIO_7_LP_PERSIST false MSSIO_7_MD_IBUF true MSSIO_7_OUT_DRIVE 8 MSSIO_7_RES_PULL UP MSSIO_7_SCHMITT_TRIGGER false MSSIO_8_ATP_EN false MSSIO_8_CLAMP_DIODE false MSSIO_8_LPMD_IBUF false MSSIO_8_LPMD_OBUF false MSSIO_8_LP_PERSIST false MSSIO_8_MD_IBUF true MSSIO_8_OUT_DRIVE 8 MSSIO_8_RES_PULL UP MSSIO_8_SCHMITT_TRIGGER false MSSIO_9_ATP_EN false MSSIO_9_CLAMP_DIODE false MSSIO_9_LPMD_IBUF false MSSIO_9_LPMD_OBUF false MSSIO_9_LP_PERSIST false MSSIO_9_MD_IBUF true MSSIO_9_OUT_DRIVE 8 MSSIO_9_RES_PULL UP MSSIO_9_SCHMITT_TRIGGER false MSSIO_REFCLK_IOSTD LVDS25 MSSIO_REFCLK_ODT 100 MSSIO_REFCLK_PULL_UP false MSSIO_REFCLK_SCHMITT_TRIGGER false MSSIO_REFCLK_THEVENIN OFF MSS_AHB_APB_CLK_DIV 4 MSS_AXI_CLK_DIV 2 MSS_CLK_DIV 1 MSS_PLLOUT_FREQ 600.000 MSS_PMP_ENABLE false MSS_REFCLK DEDICATED_IO PACKAGE FCG1152 PFSOC_MSS_VERSION 2022.2 PLL_NW_REFCLK0_FREQ 100 PLL_NW_REFCLK1_FREQ 125 PMP_CAN0_CONTEXT_A_EN true PMP_CAN0_CONTEXT_B_EN false PMP_CAN1_CONTEXT_A_EN false PMP_CAN1_CONTEXT_B_EN true PMP_CRYPTO_CFG_CONTEXT_A_EN true PMP_CRYPTO_CFG_CONTEXT_B_EN false PMP_CRYPTO_MEM_CONTEXT_A_EN true PMP_CRYPTO_MEM_CONTEXT_B_EN false PMP_EMMC_CONTEXT_A_EN true PMP_EMMC_CONTEXT_B_EN false PMP_GEM0_CONTEXT_A_EN true PMP_GEM0_CONTEXT_B_EN false PMP_GEM1_CONTEXT_A_EN false PMP_GEM1_CONTEXT_B_EN true PMP_GPIO0_CONTEXT_A_EN true PMP_GPIO0_CONTEXT_B_EN false PMP_GPIO1_CONTEXT_A_EN false PMP_GPIO1_CONTEXT_B_EN true PMP_GPIO2_CONTEXT_A_EN true PMP_GPIO2_CONTEXT_B_EN false PMP_I2C0_CONTEXT_A_EN true PMP_I2C0_CONTEXT_B_EN false PMP_I2C1_CONTEXT_A_EN false PMP_I2C1_CONTEXT_B_EN true PMP_INITIATOR_U54_1_CONTEXT_A_EN true PMP_INITIATOR_U54_1_CONTEXT_B_EN false PMP_INITIATOR_U54_2_CONTEXT_A_EN true PMP_INITIATOR_U54_2_CONTEXT_B_EN false PMP_INITIATOR_U54_3_CONTEXT_A_EN false PMP_INITIATOR_U54_3_CONTEXT_B_EN true PMP_INITIATOR_U54_4_CONTEXT_A_EN false PMP_INITIATOR_U54_4_CONTEXT_B_EN true PMP_MMUART1_CONTEXT_A_EN true PMP_MMUART1_CONTEXT_B_EN false PMP_MMUART2_CONTEXT_A_EN true PMP_MMUART2_CONTEXT_B_EN false PMP_MMUART3_CONTEXT_A_EN false PMP_MMUART3_CONTEXT_B_EN true PMP_MMUART4_CONTEXT_A_EN false PMP_MMUART4_CONTEXT_B_EN true PMP_QSPI_CONTEXT_A_EN true PMP_QSPI_CONTEXT_B_EN false PMP_RTC_CONTEXT_A_EN true PMP_RTC_CONTEXT_B_EN false PMP_SPI0_CONTEXT_A_EN true PMP_SPI0_CONTEXT_B_EN false PMP_SPI1_CONTEXT_A_EN false PMP_SPI1_CONTEXT_B_EN true PMP_USB_CONTEXT_A_EN true PMP_USB_CONTEXT_B_EN false QSPI UNUSED QSPI_CLK UNUSED QSPI_DATA_3_2 UNUSED SD MSSIO_B4 SD_CLE UNUSED SD_LED UNUSED SD_LED_IS_INVERTED false SD_PORTS_DISABLE false SD_SDIO_SPEED_MODE DDR50 SD_VOLT_0 UNUSED SD_VOLT_0_IS_INVERTED false SD_VOLT_1 UNUSED SD_VOLT_1_IS_INVERTED false SD_VOLT_2 UNUSED SD_VOLT_2_IS_INVERTED false SD_VOLT_CMD_DIR_IS_INVERTED true SD_VOLT_DIR_0_IS_INVERTED true SD_VOLT_DIR_1_3_IS_INVERTED true SD_VOLT_EN_IS_INVERTED false SD_VOLT_PORTS MSSIO_B4 SD_VOLT_SEL_IS_INVERTED true SGMII_RX0_IOSTD LVDS33 SGMII_RX0_ODT 100 SGMII_RX0_PULLMODE NONE SGMII_RX0_VCM_RANGE MID SGMII_RX1_IOSTD LVDS33 SGMII_RX1_ODT 100 SGMII_RX1_PULLMODE NONE SGMII_RX1_VCM_RANGE MID SGMII_TX0_IOSTD LVDS33 SGMII_TX0_OUT_DRIVE 6 SGMII_TX0_PULLMODE NONE SGMII_TX0_SOURCE_TERM 100 SGMII_TX1_IOSTD LVDS33 SGMII_TX1_OUT_DRIVE 6 SGMII_TX1_PULLMODE NONE SGMII_TX1_SOURCE_TERM 100 SPEED STD SPI_0 UNUSED SPI_0_SPEED_MODE MASTER SPI_0_SS1 UNUSED SPI_1 UNUSED SPI_1_SPEED_MODE MASTER SPI_1_SS1 UNUSED USB MSSIO_B2 USOC_DEBUG_TRACE false WD_RESETN UNUSED hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design_config/000077500000000000000000000000001432224323300256575ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/fpga_design_config/README.md000066400000000000000000000000451432224323300271350ustar00rootroot00000000000000Placeholder for auto-generated code. hart-software-services-2022.10/boards/mpfs-sev-kit/hss-l2scratch.lds000066400000000000000000000271371432224323300252620ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * GNU linker script for Hart Software Services (HSS) * */ #include "config.h" OUTPUT_ARCH( "riscv" ) /* PolarFire SoC Memory map (ditaa diagram) ---------------------------------------- +-------------+ +-----------+ | non-cache | | non-cache | | WCB (SEG1) | +---------------------+ | (SEG1) | 0x18_0000_0000 +-------------+ | DDR cached | 0x14_0000_0000 +-----------+ | non-cache | | (SEG0) | | non-cache | | WCB (SEG1) | 0x10_0000_0000 +---------------------+ | (SEG1) | 0xD000_0000 +-------------+ | DDR cached | 0xC000_0000 +-----------+ | (SEG0) | 0x8000_0000 +---------------------+ | envm (128KiB) | | | 0x2022_0100 +---------------------+ | Zero Device | | | 0x0A00_0000 +---------------------+ | | 0x0820_0000 +---------------------+ | LIM (up to 1920KiB) | | | 0x0800_0000 +---------------------+ | U54_4 ITIM (28KiB) | | | 0x0182_0000 +---------------------+ | U54_3 ITIM (28KiB) | | | 0x0181_8000 +---------------------+ | U54_2 ITIM (28KiB) | | | 0x0181_0000 +---------------------+ | U54_1 ITIM (28KiB) | | | 0x0180_8000 +---------------------+ | E51 ITIM (28KiB) | | | 0x0180_0000 +---------------------+ | DTIM (8KiB) | | | 0x0100_0000 +---------------------+ | Debug | 0x0000_0000 +---------------------+ */ /******************************************************************************* * * -- MSS hart Reset vector * * The MSS reset vector for each hart is configured by Libero and stored securely * in the MPFS. * * The most common usage will be where the reset vector for each hart will be set * to the start of the envm at address 0x2022_0100, giving (128KiB-256bytes) * of contiguous non-volatile storage. Normally this is where the initial * boot-loader will reside. * * Libero outputs the configured reset vector address to the xml file, see * LIBERO_SETTING_RESET_VECTOR_HART0 etc in * * When debugging a bare metal program that is run out of reset from envm, a linker * script will be used whereby the program will run from LIM instead of envm. * In this case, set the reset vector in the linker script to 0x0800_0000. * This means you are not continually programming the envm each time you load a * program and there is no limitation with hardware break points whn debugging. */ ENTRY(_start) /******************************************************************************* * * Memory Segments * * must be on 4k boundary (0x1000) - corresponds to page size, when using memory mem */ MEMORY { envm (rx) : ORIGIN = 0x20220100, LENGTH = (128k-256) dtim (rwx) : ORIGIN = 0x01000000, LENGTH = 7k /* DTIM */ switch_code (rx) : ORIGIN = 0x01001c00, LENGTH = 1k /* This 1K of DTIM is used to run code * when switching the envm clock */ e51_itim (rwx) : ORIGIN = 0x01800000, LENGTH = 28k u54_1_itim (rwx) : ORIGIN = 0x01808000, LENGTH = 28k u54_2_itim (rwx) : ORIGIN = 0x01810000, LENGTH = 28k u54_3_itim (rwx) : ORIGIN = 0x01818000, LENGTH = 28k u54_4_itim (rwx) : ORIGIN = 0x01820000, LENGTH = 28k l2lim (rwx) : ORIGIN = 0x08000000, LENGTH = 512k l2zerodevice (rwx) : ORIGIN = 0x0A000000, LENGTH = 512k ddr (rwx) : ORIGIN = 0x80000000, LENGTH = 32m ddrhi (rwx) : ORIGIN = 0x1000000000, LENGTH = 1888m ncddrhi (rwx) : ORIGIN = 0x1400000000, LENGTH = 2048m } PROVIDE(HEAP_SIZE = 0k); PROVIDE(STACK_SIZE_PER_HART = 16k); /******************************************************************************* * * Memory Sections and Placement */ SECTIONS { PROVIDE(__envm_start = ORIGIN(envm)); PROVIDE(__envm_end = ORIGIN(envm) + LENGTH(envm)); PROVIDE(__l2lim_start = ORIGIN(l2lim)); PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); PROVIDE(__l2_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); PROVIDE(__ddr_start = ORIGIN(ddr)); PROVIDE(__ddr_end = ORIGIN(ddr) + LENGTH(ddr)); PROVIDE(__ddrhi_start = ORIGIN(ddrhi)); PROVIDE(__ddrhi_end = ORIGIN(ddrhi) + LENGTH(ddrhi)); PROVIDE(__ncddrhi_start = ORIGIN(ncddrhi)); PROVIDE(__ncddrhi_end = ORIGIN(ncddrhi) + LENGTH(ncddrhi)); PROVIDE(__dtim_start = ORIGIN(dtim)); PROVIDE(__dtim_end = ORIGIN(dtim) + LENGTH(dtim)); PROVIDE(__e51itim_start = ORIGIN(e51_itim)); PROVIDE(__e51itim_end = ORIGIN(e51_itim) + LENGTH(e51_itim)); PROVIDE(__u54_1_itim_start = ORIGIN(u54_1_itim)); PROVIDE(__u54_1_itim_end = ORIGIN(u54_1_itim) + LENGTH(u54_1_itim)); PROVIDE(__u54_2_itim_start = ORIGIN(u54_2_itim)); PROVIDE(__u54_2_itim_end = ORIGIN(u54_2_itim) + LENGTH(u54_2_itim)); PROVIDE(__u54_3_itim_start = ORIGIN(u54_3_itim)); PROVIDE(__u54_3_itim_end = ORIGIN(u54_3_itim) + LENGTH(u54_3_itim)); PROVIDE(__u54_4_itim_start = ORIGIN(u54_4_itim)); PROVIDE(__u54_4_itim_end = ORIGIN(u54_4_itim) + LENGTH(u54_4_itim)); /* * Code and RO data lives in l2lim */ . = __l2_start; PROVIDE(_hss_start = .); PROVIDE(__l2_scratchpad_vma_start = .); .text : ALIGN(0x10) { *(.entry) . = ALIGN(0x10); *(.text .text.* .gnu.linkonce.t.*) *(.plt) . = ALIGN(0x10); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) *(.sdata2*) *(.gcc_except_table) *(.eh_frame_hdr) *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(0x10); } >l2zerodevice .gnu_build_id : ALIGN(8) { PROVIDE(gnu_build_id = .); *(.note.gnu.build-id) } >l2zerodevice PROVIDE(_hss_end = .); /******************************************************************************* * * The .ram_code section will contain the code That is run from RAM. * We are using this code to switch the clocks including envm clock. * This can not be done when running from envm * This will need to be copied to ram, before any of this code is run. * */ .ram_code : ALIGN(0x10) { __sc_load = LOADADDR (.ram_code); __sc_start = .; *(.ram_codetext) /* .ram_codetext sections (code) */ *(.ram_codetext*) /* .ram_codetext* sections (code) */ *(.ram_coderodata) /* read-only data (constants) */ *(.ram_coderodata*) . = ALIGN (0x10); __sc_end = .; } >switch_code /******************************************************************************* * * Short/global data section * */ .sdata : ALIGN(0x40) /* short/global data section */ { __sdata_load = LOADADDR(.sdata); __sdata_start = .; /* * offset used with gp(gloabl pointer) are +/- 12 bits, so set * point to middle of expected sdata range * * If sdata more than 4K, linker used direct addressing. * Perhaps we should add check/warning to linker script if sdata is > 4k */ __global_pointer$ = . + 0x800; *(.sdata .sdata.* .gnu.linkonce.s.*) . = ALIGN(0x10); __sdata_end = .; } >l2zerodevice /******************************************************************************* * * (Explicitly) Initialized data section * */ #ifdef CONFIG_SERVICE_BOOT_USE_PAYLOAD .data.payload : ALIGN(16) { _payload_start = .; KEEP(boards/mpfs-icicle-kit-es/payload.o(.*)) _payload_end = .; } #endif .data : ALIGN(0x40) { __data_load = LOADADDR(.data); __data_start = .; *(.got.plt) *(.got) *(.shdata) *(.data .data.* .gnu.linkonce.d.*) . = ALIGN(0x10); __data_end = .; } >l2zerodevice /******************************************************************************* * * Uninitialized (zero-initialized) section */ /* * Short zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. * */ .sbss : ALIGN(0x40) { __sbss_start = .; *(.sbss .sbss.* .gnu.linkonce.sb.*) *(.scommon) . = ALIGN(0x10); __sbss_end = .; } >l2zerodevice /* * General Zero-initialized section * The name BSS is an anacronym for "Block Started by Symbol" from a mid 1950s * assembly language for the IBM 704. */ .bss : ALIGN(0x40) { __bss_start = .; *(.shbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(0x10); __bss_end = .; } >l2zerodevice /* * Reserved space for Hart stacks */ .stack : ALIGN(0x40) { __stack_bottom = .; __stack_bottom_h0$ = .; . += STACK_SIZE_PER_HART; __stack_top_h0$ = . - 8; __stack_bottom_h1$ = .; . += STACK_SIZE_PER_HART; __stack_top_h1$ = . - 8; __stack_bottom_h2$ = .; . += STACK_SIZE_PER_HART; __stack_top_h2$ = . - 8; __stack_bottom_h3$ = .; . += STACK_SIZE_PER_HART; __stack_top_h3$ = . - 8; __stack_bottom_h4$ = .; . += STACK_SIZE_PER_HART; __stack_top_h4$ = . - 8; __stack_top = .; } >l2zerodevice _end = .; PROVIDE(__l2_scratchpad_vma_end = .); /* * End of uninitialized data segment * *******************************************************************************/ /* .heap : ALIGN(0x10) { __heap_start = .; . += HEAP_SIZE; __heap_end = .; . = ALIGN(0x10); _heap_end = __heap_end; } >dtim */ } hart-software-services-2022.10/boards/mpfs-sev-kit/hss_board_init.c000066400000000000000000000076771432224323300252400ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Board Initalization * \brief Board Initialization */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "hss_init.h" #include "hss_state_machine.h" #include "ssmb_ipi.h" #include "hss_registry.h" #ifndef __IO # define __IO volatile #endif #include "mss_io_config.h" #include "io/hw_mssio_mux.h" /******************************************************************************************************/ /*! * \brief Board Init Function Registration Table * * The following structure is used to connect in new board init functions. */ #include "hss_init.h" #include "hss_boot_pmp.h" #include "hss_sys_setup.h" #include "hss_board_init.h" const struct InitFunction /*@null@*/ boardInitFunctions[] = { // Name FunctionPointer Halt Restart { "HSS_ZeroTIMs", HSS_ZeroTIMs, false, false }, { "HSS_Setup_PLIC", HSS_Setup_PLIC, false, false }, { "HSS_Setup_BusErrorUnit", HSS_Setup_BusErrorUnit, false, false }, { "HSS_Setup_MPU", HSS_Setup_MPU, false, false }, { "HSS_DDRInit", HSS_DDRInit, false, false }, { "HSS_ZeroDDR", HSS_ZeroDDR, false, false }, #ifdef CONFIG_USE_PCIE { "HSS_PCIeInit", HSS_PCIeInit, false, false }, #endif { "HSS_USBInit", HSS_USBInit, false, false }, }; /******************************************************************************************************/ /** * \brief Board Initialization Function * * All other initialization routines to be chained off this... */ /****************************************************************************/ #include "mss_sysreg.h" bool HSS_BoardInit(void) { RunInitFunctions(ARRAY_SIZE(boardInitFunctions), boardInitFunctions); return true; } bool HSS_BoardLateInit(void) { #if defined(CONFIG_SERVICE_MMC_MODE_SDCARD) || defined(CONFIG_SERVICE_MMC_MODE_EMMC) mHSS_DEBUG_PRINTF(LOG_WARN, "Please ensure that jumpers J16/J35/J36 are correct for " # if defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8) "1.8V" # elif defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_3V3) "3.3V" # endif " MMC voltage... \n"); #endif return true; } /* * this function is used to switch external demux, and is board dependent * For the SEV kit, we are changing I/O pullup and pull down states * The setup for this is being automated in a future MSS Configurator release * */ uint8_t switch_external_mux(MSS_IO_OPTIONS option) { uint8_t result = false; switch(option) { case SD_MSSIO_CONFIGURATION: SYSREG->IOMUX5_CR = LIBERO_SETTING_IOMUX5_CR; SYSREG->IOMUX5_CR &= ~((0xF << 0) | (0xF << 16) | (0xF << 28)); SYSREG->IOMUX5_CR |= ((0xE << 0) | (0xE << 16) | (0xD << 28)); //making usb pin pull down SYSREG->IOMUX4_CR = LIBERO_SETTING_IOMUX4_CR; SYSREG->IOMUX4_CR &= ~(0xF << 16); SYSREG->IOMUX4_CR |= (0xD << 16); break; case EMMC_MSSIO_CONFIGURATION: SYSREG->IOMUX5_CR = LIBERO_SETTING_IOMUX5_CR; //masking pads need to make 30, 34, 37 and force pull down (0xD) SYSREG->IOMUX5_CR &= ~((0xF << 0) | (0xF << 16) | (0xF << 28)); SYSREG->IOMUX5_CR |= ((0xD << 0) | (0xD << 16) | (0xD << 28)); //making usb pin pull down SYSREG->IOMUX4_CR = LIBERO_SETTING_IOMUX4_CR; SYSREG->IOMUX4_CR &= ~(0xF << 16); SYSREG->IOMUX4_CR |= (0xD << 16); break; case NO_SUPPORT_MSSIO_CONFIGURATION: break; case NOT_SETUP_MSSIO_CONFIGURATION: break; } result = true; return result; } hart-software-services-2022.10/boards/mpfs-sev-kit/hss_uart_init.c000066400000000000000000000025501432224323300251050ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Debug UART Initalization * \brief Debug UART Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" bool HSS_UARTInit(void) { // initialise debug UART #if IS_ENABLED(CONFIG_PLATFORM_MPFS) MSS_UART_init(&g_mss_uart0_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); // default all UARTs to 115200 for now // subsequent OS loads can change these if needed... MSS_UART_init(&g_mss_uart1_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart2_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart3_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); MSS_UART_init(&g_mss_uart4_lo, MSS_UART_115200_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); #else # error Unknown PLATFORM #endif return true; } hart-software-services-2022.10/boards/mpfs-sev-kit/mpfs_hal_config/000077500000000000000000000000001432224323300252025ustar00rootroot00000000000000hart-software-services-2022.10/boards/mpfs-sev-kit/mpfs_hal_config/mss_sw_config.h000066400000000000000000000172271432224323300302240ustar00rootroot00000000000000#ifndef MSS_SW_CONFIG_H_ #define MSS_SW_CONFIG_H_ /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HAL Embedded Software * */ /******************************************************************************* * * Platform definitions * Version based on requirements of MPFS MSS * */ /*========================================================================*//** @mainpage Sample file detailing how mss_sw_config.h should be constructed for the MPFS MSS @section intro_sec Introduction The mss_sw_config.h has the default software configuration settings for the MPFS HAL and will be located at /src/platform/platform_config_reference folder of the bare metal SoftConsole project. The platform_config_reference is provided as a default reference configuration. When you want to configure the MPFS HAL with required configuration for your project, the mss_sw_config.h must be edited and be placed in the following project directory: /src/boards//platform_config/mpfs_hal_config/ @section *//*==========================================================================*/ /* * Include any driver setup/over-rides you may require. */ #include "drivers/fpga_ip/miv_ihc/miv_ihc_defines.h" #include "drivers_config/fpga_ip/miv_ihc/miv_ihc_config.h" /* * MPFS_HAL_FIRST_HART and MPFS_HAL_LAST_HART defines are used to specify which * harts to actually start. The value and the actual hart it represents are * listed below: * value hart * 0 E51 * 1 U54_1 * 2 U54_2 * 3 U54_3 * 4 U54_4 * Set MPFS_HAL_FIRST_HART to a value greater than 0 if you do not want your * application to start and execute code on the harts represented by smaller * value numbers. * Set MPFS_HAL_LAST_HART to a value smaller than 4 if you do not wish to use * all U54_x harts. * Harts that are not started will remain in an infinite WFI loop unless used * through some other method. * The value of MPFS_HAL_FIRST_HART must always be less than MPFS_HAL_LAST_HART. * The value of MPFS_HAL_LAST_HART must never be greater than 4. * A typical use-case where you set MPFS_HAL_FIRST_HART = 1 and * MPFS_HAL_LAST_HART = 1 is when * your application is running on U54_1 and a bootloader running on E51 loads * your application to the target memory and kicks-off U54_1 to run it. */ #ifndef MPFS_HAL_FIRST_HART #define MPFS_HAL_FIRST_HART 1 #endif #ifndef MPFS_HAL_LAST_HART #define MPFS_HAL_LAST_HART 4 #endif /* * IMAGE_LOADED_BY_BOOTLOADER * We set IMAGE_LOADED_BY_BOOTLOADER = 0 if the application image runs from * non-volatile memory after reset. (No previous stage bootloader is used.) * Set IMAGE_LOADED_BY_BOOTLOADER = 1 if the application image is loaded by a * previous stage bootloader. * * MPFS_HAL_HW_CONFIG is defined if we are a boot-loader. This is a * conditional compile switch is used to determine if MPFS HAL will perform the * hardware configurations or not. * Defined => This program acts as a First stage bootloader and performs * hardware configurations. * Not defined => This program assumes that the hardware configurations are * already performed (Typically by a previous boot stage) * * List of items initialised when MPFS_HAL_HW_CONFIG is enabled * - load virtual rom (see load_virtual_rom(void) in system_startup.c) * - l2 cache config * - Bus error unit config * - MPU config * - pmp config * - I/O, clock and clock mux's, DDR and SGMII * - will start other harts, see text describing MPFS_HAL_FIRST_HART, * MPFS_HAL_LAST_HART above * */ #define IMAGE_LOADED_BY_BOOTLOADER 0 #if (IMAGE_LOADED_BY_BOOTLOADER == 0) #define MPFS_HAL_HW_CONFIG #endif /* * If you are using common memory for sharing across harts, * uncomment #define MPFS_HAL_SHARED_MEM_ENABLED * make sure common memory is allocated in the linker script * See app_hart_common mem section in the example platform * linker scripts. */ //#define MPFS_HAL_SHARED_MEM_ENABLED /* define the required tick rate in Milliseconds */ /* if this program is running on one hart only, only that particular hart value * will be used */ #define HART0_TICK_RATE_MS 5UL #define HART1_TICK_RATE_MS 5UL #define HART2_TICK_RATE_MS 5UL #define HART3_TICK_RATE_MS 5UL #define HART4_TICK_RATE_MS 5UL /* * Define the size of the Hart Local Storage (HLS). * In the MPFS HAL, we are using HLS for debug data storage during the initial * boot phase. * This includes the flags which indicate the hart state regarding boot state. * The HLS will take memory from top of each stack allocated at boot time. * */ #define HLS_DEBUG_AREA_SIZE 64 /* * Bus Error Unit (BEU) configurations * BEU_ENABLE => Configures the events that the BEU can report. bit value * 1= enabled, 0 = disabled. * BEU_PLIC_INT => Configures which accrued events should generate an * interrupt to the PLIC. * BEU_LOCAL_INT => Configures which accrued events should generate a * local interrupt to the hart on which the event accrued. */ #define BEU_ENABLE 0x0ULL #define BEU_PLIC_INT 0x0ULL #define BEU_LOCAL_INT 0x0ULL /* * Clear memory on startup * 0 => do not clear DTIM and L2 * 1 => Clears memory * Note: If you are the zero stage bootloader, set this to one. */ #ifndef MPFS_HAL_CLEAR_MEMORY #define MPFS_HAL_CLEAR_MEMORY 0 #endif /* * Comment out the lines to disable the corresponding hardware support not required * in your application. * This is not necessary from an operational point of view as operation dictated * by MSS configurator settings, and items are enabled/disabled by this method. * The reason you may want to use below is to save code space. */ #define SGMII_SUPPORT #define DDR_SUPPORT #define MSSIO_SUPPORT /* * The hardware configuration settings imported from Libero project get generated * into /src/boards// folder. * If you need to overwrite them for testing purposes, you can do so here. * e.g. If you want change the default SEG registers configuration defined by * LIBERO_SETTING_SEG0_0, define it here and it will take precedence. * #define LIBERO_SETTING_SEG0_0 0x80007F80UL * */ #define LIBERO_SETTING_CONTEXT_A_HART_EN 0x0000000EUL /* harts 1 to 3 */ #define LIBERO_SETTING_CONTEXT_B_HART_EN 0x00000010UL /* hart 4 */ #define LIBERO_SETTING_FPGA_SWITCH_ADDRESS 0 /* not used in SEV kit but define required */ /* * DDR software options */ /* * Debug DDR startup through a UART * Comment out in normal operation. Useful for debug purposes in bring-up of DDR * in a new board design. * See the weak function setup_ddr_debug_port(mss_uart_instance_t * uart) * If you need to edit this function, make a copy of the function without the * weak declaration in your application code. * */ //#define DEBUG_DDR_INIT //#define DEBUG_DDR_RD_RW_FAIL //#define DEBUG_DDR_RD_RW_PASS //#define DEBUG_DDR_CFG_DDR_SGMII_PHY //#define DEBUG_DDR_DDRCFG /* * To match DCT version Feb 2022 * These settings are non default in the MSS Configurator * The have been updated in the MSS Configurator UI. */ //On the tab DDR Controller, 3 => ODT DQ == 80, 6 => ODT DQ == 40, //#define LIBERO_SETTING_RPC_ODT_DQ 0x00000003UL // Mode register 3 - 1 => VDDQ3 , 0 => VDDQ2P5 //#define LIBERO_SETTING_CFG_PU_CAL 0x00000000UL // On the tab DDR Controller, DQ DQS offset set to 6 for SEV kit @800MHz //#define LIBERO_SETTING_RPC_156_VALUE 6U #endif hart-software-services-2022.10/boards/mpfs-sev-kit/mpfs_hal_config/readme.txt000066400000000000000000000001261432224323300271770ustar00rootroot00000000000000contains user configuration of the platform e.g. division of memory between harts etc.hart-software-services-2022.10/boards/mpfs-sev-kit/uart_helper.c000066400000000000000000000123001432224323300245360ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Implementation of uart_putstring/g(). * This is function is intended to be used from ee_printf(). */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include #include #include "uart_helper.h" static inline mss_uart_instance_t *get_uart_instance(int hartid) { mss_uart_instance_t *pUart; switch (hartid) { default: pUart = &g_mss_uart0_lo; break; case HSS_HART_E51: pUart = &g_mss_uart0_lo; break; case HSS_HART_U54_1: pUart = &g_mss_uart1_lo; break; case HSS_HART_U54_2: pUart = &g_mss_uart2_lo; break; case HSS_HART_U54_3: pUart = &g_mss_uart3_lo; break; case HSS_HART_U54_4: pUart = &g_mss_uart4_lo; break; } return pUart; } int uart_putstring(int hartid, char *p) { const uint32_t len = (uint32_t)strlen(p); mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)p); // TODO: if hartId is zero (i.e., E51), replace this with non-blocking // queue implementation, with HSS_UART state machine consuming from queues... return len; } void uart_putc(int hartid, const char ch) { uint8_t string[2]; string[0] = (uint8_t)ch; string[1] = 0u; mss_uart_instance_t *pUart = get_uart_instance(hartid); while (!(MSS_UART_TEMT & MSS_UART_get_tx_status(pUart))) { ; } MSS_UART_polled_tx_string(pUart, (const uint8_t *)string); } ssize_t uart_getline(char **pBuffer, size_t *pBufLen) { ssize_t result = 0; bool finished = false; static char myBuffer[HSS_UART_HELPER_MAX_GETLINE]; // static to be stack friendly const size_t bufferLen = ARRAY_SIZE(myBuffer); memset(myBuffer, 0, bufferLen); uint8_t cBuf[1]; while (!finished) { while (0 == MSS_UART_get_rx(&g_mss_uart0_lo, cBuf, 1)); switch (cBuf[0]) { case '\r': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case '\n': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); finished = true; break; case 0x7Fu: // delete if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[D \033[D", 7u); myBuffer[result] = 0; } break; case 0x08u: // backspace - ^H if (result) { result--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)" \033[D", 4u); myBuffer[result] = 0; } break; case 0x03u: // intr - ^C result = -1; myBuffer[0] = 0; finished = true; break; case 0x1Bu: // ESC result = -1; myBuffer[0] = 0; finished = true; break; case 0x04u: // ^D if (result == 0) { result = -1; myBuffer[0] = 0; finished = true; } break; default: if (result < bufferLen) { MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); myBuffer[result] = cBuf[0]; result++; } break; } } const char crlf[] = "\n"; MSS_UART_polled_tx_string(&g_mss_uart0_lo, (const uint8_t *)crlf); if (result > 0) { *pBuffer = myBuffer; *pBufLen = (size_t)result; } else { *pBuffer = NULL; *pBufLen = 0u; } return result; } bool uart_getchar(uint8_t *pbuf, int32_t timeout_sec, bool do_sec_tick) { bool result = false; bool done = false; uint8_t rx_buff[1]; HSSTicks_t start_time = 0u; HSSTicks_t last_sec_time = 0u; start_time = last_sec_time = HSS_GetTime(); const HSSTicks_t timeout_ticks = timeout_sec * TICKS_PER_SEC; while (!done) { size_t received = MSS_UART_get_rx(&g_mss_uart0_lo, rx_buff, 1u); if (0u != received) { done = true; if (MSS_UART_NO_ERROR == MSS_UART_get_rx_status(&g_mss_uart0_lo)) { *pbuf = rx_buff[0]; result = true; break; } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "UART error\n"); } } if (do_sec_tick && HSS_Timer_IsElapsed(last_sec_time, TICKS_PER_SEC)) { const uint8_t dot='.'; MSS_UART_polled_tx(&g_mss_uart0_lo, &dot, 1); last_sec_time = HSS_GetTime(); } if (timeout_sec < 0) { ; // blocking until UART data received, so nothing extra to do here... } else if (timeout_sec > 0) { // time limited done = HSS_Timer_IsElapsed(start_time, timeout_ticks); } else /* timeout == 0 */ { // one-shot break; } } return result; } hart-software-services-2022.10/envm-wrapper/000077500000000000000000000000001432224323300207105ustar00rootroot00000000000000hart-software-services-2022.10/envm-wrapper/Makefile000066400000000000000000000116611432224323300223550ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # eNVM Compression Wrapper COMPRESS=tools/compression/hss-deflate.py OBJS-envm-wrapper = \ envm-wrapper/envm-wrapper_crt.o \ envm-wrapper/envm-wrapper_validate_crc.o \ envm-wrapper/envm-wrapper_stubs.o \ \ application/hart0/hss_clock.o \ init/hss_sys_setup.o \ modules/misc/hss_crc32.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_l2_cache.o \ modules/misc/csr_helper.o \ modules/misc/assert.o \ modules/misc/c_stubs.o \ modules/misc/stack_guard.o \ thirdparty/miniz/miniz.o #ifndef CONFIG_CODE_SIGNING OBJS-envm-wrapper += \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_nwc_init.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_pll.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_io.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/nwc/mss_sgmii.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common/mss_peripherals.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/startup_gcc/mss_utils.o \ baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/mss_mmuart/mss_uart.o \ #endif EXTRA_OBJS-envm-wrapper = LINKER_SCRIPT-envm-wrapper = envm-wrapper/envm-wrapper.ld COMPRESSED_TARGET=$(BINDIR)/$(TARGET-l2scratch:.elf=.bin.deflate) envm-wrapper/envm-wrapper_crt.o: $(COMPRESSED_TARGET) thirdparty/miniz/miniz.o: CFLAGS=$(CFLAGS_GCCEXT) -DMINIZ_NO_STDIO -DMINIZ_NO_TIME envm-wrapper/envm-wrapper_validate_crc.o: CFLAGS=$(CFLAGS_GCCEXT) define common-boot-mode-programmer -$(RM) -r $(BINDIR)/bootmode1 [ "$(SC_INSTALL_DIR)" ] || ( echo "SC_INSTALL_DIR environment variable is unset"; exit 1 ) [ -d $(SC_INSTALL_DIR) ] || ( echo "SoftConsole subdirectory >>$(SC_INSTALL_DIR)<< does not exist."; exit 2 ) $(MPFS_BOOTMODE_PROGRAMMER) --workdir `pwd`/Default --die $(DIE) --package $(PACKAGE) --bootmode $(BOOTMODE) $(1) $(2) endef MPFS_BOOTMODE_PROGRAMMER_VERSION := $(findstring v3.6,$(shell $(MPFS_BOOTMODE_PROGRAMMER) --help)) EXPECTED_MPFS_BOOTMODE_PROGRAMMER_VERSION := v3.6 ifneq ($(MPFS_BOOTMODE_PROGRAMMER_VERSION),$(EXPECTED_MPFS_BOOTMODE_PROGRAMMER_VERSION)) $(info INFO: Expected mpfsBootmodeProgrammer.jar version $(EXPECTED_MPFS_BOOTMODE_PROGRAMMER_VERSION) but found $(MPFS_BOOTMODE_PROGRAMMER_VERSION)) $(info INFO: This version of the HSS relies on SoftConsole v2021.3 or later) endif $(TARGET-envm-wrapper): LIBS:= $(TARGET-envm-wrapper): $(COMPRESSED_TARGET) $(OBJS-envm-wrapper) $(call main-build-target,envm-wrapper) @$(ECHO) " BIN `basename $@ .elf`.bin" $(OBJCOPY) -O binary $(BINDIR)/$@ $(BINDIR)/`basename $@ .elf`.bin @$(ECHO) " HEX `basename $@ .elf`.hex"; $(call common-boot-mode-programmer,--dryrun,`basename $@`) @$(CP) $(BINDIR)/bootmode1/hss-envm-wrapper-bm1-p0.hex $(BINDIR)/`basename $@ .elf`.${BOARD}.hex $(SIZE) $(BINDIR)/$(TARGET-envm-wrapper) 2>/dev/null $(COMPRESSED_TARGET): $(BINDIR)/$(TARGET-l2scratch:.elf=.bin) $(COMPRESS) @$(ECHO) " COMPRESS $<" $(PYTHON) $(COMPRESS) $< $@ envm-wrapper_clean: -$(RM) $(COMPRESSED_TARGET) $(OBJS-envm-wrapper) $(BINDIR)/$(TARGET-envm-wrapper) $(BINDIR)/`basename $(TARGET-envm-wrapper) .elf`.sym $(BINDIR)/`basename $(TARGET-envm-wrapper) .elf`.bin HEX_FILE-envm-wrapper=$(BINDIR)/$(TARGET-envm-wrapper:.elf=.hex) BIN_FILE-envm-wrapper=$(BINDIR)/$(TARGET-envm-wrapper:.elf=.bin) BIN_FILE-envm-wrapper: $(TARGET-envm-wrapper) BOOTMODE?=1 PACKAGE?=FCVG484 DIE?=MPFS250T_ES FPGENPROG?=/opt/microsemi/Libero_SoC_v2021.2/Libero/bin64/fpgenprog FPGENPROG:=$(FPGENPROG:_bin=) program: $(BIN_FILE-envm-wrapper) $(call common-boot-mode-programmer,,$(TARGET-envm-wrapper)) verify: $(BIN_FILE-envm-wrapper) $(call common-boot-mode-programmer,--verify,$(TARGET-envm-wrapper)) hart-software-services-2022.10/envm-wrapper/envm-wrapper.ld000066400000000000000000000176331432224323300236660ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip Corporation. * * SPDX-License-Identifier: MIT * * GNU linker script for Hart Software Services (HSS) ENVM Wrapper * The purpose of the wrapper is to allow a DEFLATE compressed image to be * stored in ENVM, but decompressed (inflated) to L2-LIM at runtime... */ /* PolarFire SoC Memory map (ditaa diagram) ---------------------------------------- +-------------+ +-----------+ | non-cache | | non-cache | | WCB (SEG1) | +---------------------+ | (SEG1) | 0x18_0000_0000 +-------------+ | DDR cached | 0x14_0000_0000 +-----------+ | non-cache | | (SEG0) | | non-cache | | WCB (SEG1) | 0x10_0000_0000 +---------------------+ | (SEG1) | 0xD000_0000 +-------------+ | DDR cached | 0xC000_0000 +-----------+ | (SEG0) | 0x8000_0000 +---------------------+ | eNVM (128KiB) | ------------------+ | | | 0x2022_0100 +---------------------+ | decompresses HSS | Zero Device | | (inflate) from eNVM | | | to LIM 0x0A00_0000 +---------------------+ | | | | 0x0820_0000 +---------------------+ | | LIM (up to 1920KiB) | <-----------------+ | | 0x0800_0000 +---------------------+ | U54_4 ITIM (28KiB) | | | 0x0182_0000 +---------------------+ | U54_3 ITIM (28KiB) | | | 0x0181_8000 +---------------------+ | U54_2 ITIM (28KiB) | | | 0x0181_0000 +---------------------+ | U54_1 ITIM (28KiB) | | | 0x0180_8000 +---------------------+ | E51 ITIM (28KiB) | | | 0x0180_0000 +---------------------+ | DTIM (8KiB) | | | 0x0100_0000 +---------------------+ | | +---------------------+ | Debug | 0x0000_0000 +---------------------+ */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) PROVIDE(HEAP_SIZE = 64k); PROVIDE(STACK_SIZE_PER_HART = 16k); MEMORY { envm (rx) : ORIGIN = 0x20220100, LENGTH = (128k-256) dtim (rwx) : ORIGIN = 0x01000000, LENGTH = 8k e51_itim (rwx) : ORIGIN = 0x01800000, LENGTH = 28k u54_1_itim (rwx) : ORIGIN = 0x01808000, LENGTH = 28k u54_2_itim (rwx) : ORIGIN = 0x01810000, LENGTH = 28k u54_3_itim (rwx) : ORIGIN = 0x01818000, LENGTH = 28k u54_4_itim (rwx) : ORIGIN = 0x01820000, LENGTH = 28k l2lim (rwx) : ORIGIN = 0x08000000, LENGTH = 512k l2zerodevice (rwx) :ORIGIN = 0x0A000000, LENGTH = 512k ddr (rwx) : ORIGIN = 0x80000000, LENGTH = 1024m ddrhi (rwx) : ORIGIN = 0x1400000000, LENGTH = 1024m } SECTIONS { PROVIDE(__envm_start = ORIGIN(envm)); PROVIDE(__envm_end = ORIGIN(envm) + LENGTH(envm)); PROVIDE(__l2lim_start = ORIGIN(l2lim)); PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); PROVIDE(__l2_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); PROVIDE(__ddr_start = ORIGIN(ddr)); PROVIDE(__ddr_end = ORIGIN(ddr) + LENGTH(ddr)); PROVIDE(__ddrhi_start = ORIGIN(ddrhi)); PROVIDE(__ddrhi_end = ORIGIN(ddrhi) + LENGTH(ddrhi)); PROVIDE(__dtim_start = ORIGIN(dtim)); PROVIDE(__dtim_end = ORIGIN(dtim) + LENGTH(dtim)); PROVIDE(__e51itim_start = ORIGIN(e51_itim)); PROVIDE(__e51itim_end = ORIGIN(e51_itim) + LENGTH(e51_itim)); PROVIDE(__u54_1_itim_start = ORIGIN(u54_1_itim)); PROVIDE(__u54_1_itim_end = ORIGIN(u54_1_itim) + LENGTH(u54_1_itim)); PROVIDE(__u54_2_itim_start = ORIGIN(u54_2_itim)); PROVIDE(__u54_2_itim_end = ORIGIN(u54_2_itim) + LENGTH(u54_2_itim)); PROVIDE(__u54_3_itim_start = ORIGIN(u54_3_itim)); PROVIDE(__u54_3_itim_end = ORIGIN(u54_3_itim) + LENGTH(u54_3_itim)); PROVIDE(__u54_4_itim_start = ORIGIN(u54_4_itim)); PROVIDE(__u54_4_itim_end = ORIGIN(u54_4_itim) + LENGTH(u54_4_itim)); PROVIDE(_hss_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_scratchpad_vma_start = ORIGIN(l2zerodevice)); PROVIDE(__l2_scratchpad_vma_end = ORIGIN(l2zerodevice) + LENGTH(l2zerodevice)); . = __envm_start; .text : ALIGN(0x10) { *(.entry) . = ALIGN(0x10); *(.text .text.* .gnu.linkonce.t.*) *(.plt) . = ALIGN(0x10); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) *(.sdata2*) *(.gcc_except_table) *(.eh_frame_hdr) *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(0x10); } >envm .gnu_build_id : ALIGN(8) { PROVIDE(gnu_build_id = .); *(.note.gnu.build-id) } >envm PROVIDE(_hss_end = .); .sdata : ALIGN(0x40) { __sdata_load = LOADADDR(.sdata); __sdata_start = .; __global_pointer$ = . + 0x800; *(.sdata .sdata.* .gnu.linkonce.s.*) . = ALIGN(0x10); __sdata_end = .; } >dtim AT>envm .data : ALIGN(0x40) { __data_load = LOADADDR(.data); __data_start = .; *(.got.plt) *(.got) *(.shdata) *(.data .data.* .gnu.linkonce.d.*) . = ALIGN(0x10); __data_end = .; } >dtim AT>envm _end = .; .sbss : ALIGN(0x40) { __sbss_start = .; *(.sbss .sbss.* .gnu.linkonce.sb.*) *(.scommon) . = ALIGN(0x10); __sbss_end = .; } >dtim .bss : ALIGN(0x40) { __bss_start = .; *(.shbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(0x10); __bss_end = .; } >dtim .stack : ALIGN(0x40) { __stack_bottom = .; __stack_bottom_h0$ = .; . += STACK_SIZE_PER_HART; __stack_top_h0$ = . - 8; __stack_bottom_h1$ = .; . += STACK_SIZE_PER_HART; __stack_top_h1$ = . - 8; __stack_bottom_h2$ = .; . += STACK_SIZE_PER_HART; __stack_top_h2$ = . - 8; __stack_bottom_h3$ = .; . += STACK_SIZE_PER_HART; __stack_top_h3$ = . - 8; __stack_bottom_h4$ = .; . += STACK_SIZE_PER_HART; __stack_top_h4$ = . - 8; __stack_top = . - 8; } >l2lim .heap : ALIGN(0x40) { PROVIDE(__l2lim_heap_base = .); . += HEAP_SIZE; } >l2lim PROVIDE(__l2lim_heap_end =.); PROVIDE(_hss_end = .); } hart-software-services-2022.10/envm-wrapper/envm-wrapper_crt.S000066400000000000000000000233731432224323300243370ustar00rootroot00000000000000/* * The HSS software is released under the following software license: * * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * */ #include "config.h" #include #include #include #include #include /* * These must match the definition in include/hss_types.h! * */ #define mHSS_COMPRESSED_VERSION_FASTLZ 1u #define mHSS_COMPRESSED_VERSION_DEFLATE 2u #define OFFSET_OF(TYPE, FIELD) TYPE##_##FIELD##_##OFFSET #define HSS_CompressedImage_magic_OFFSET 0u #define HSS_CompressedImage_version_OFFSET 4u #define HSS_CompressedImage_headerLength_OFFSET 8u #define HSS_CompressedImage_headerCrc_OFFSET 16u #define HSS_CompressedImage_compressedCrc_OFFSET 20u #define HSS_CompressedImage_originalCrc_OFFSET 24u #define HSS_CompressedImage_compressedImageLen_OFFSET 32u #define HSS_CompressedImage_originalImageLen_OFFSET 40u #define HSS_CompressedImage_hash_OFFSET 48u #define HSS_CompressedImage_ecdsaSig_OFFSET 80u /* */ .section .entry, "ax", @progbits .attribute unaligned_access, 0 .attribute stack_align, 16 .align 3 .globl _start _start: #j _start la t0, .early_trap_handler csrw CSR_MTVEC, t0 li ra, 0 .reset_regs: // flush the instruction cache fence.i // Reset all registers except ra, a0, a1 and a2 li gp, 0 li sp, 0 li tp, 0 li t0, 0 li t1, 0 li t2, 0 li s0, 0 li s1, 0 li a3, 0 li a4, 0 li a5, 0 li a6, 0 li a7, 0 li s2, 0 li s3, 0 li s4, 0 li s5, 0 li s6, 0 li s7, 0 li s8, 0 li s9, 0 li s10, 0 li s11, 0 li t3, 0 li t4, 0 li t5, 0 li t6, 0 csrw CSR_MSCRATCH, 0 .configure: li a0, 0 la a1, decompress_done_flag REG_S a0, 0(a1) la s8, STACK_SIZE_PER_HART csrr a0, CSR_MHARTID la tp, __stack_bottom add tp, tp, 63 and tp, tp, -64 li a1, 1 .setup_stack: mul a2, s8, a0 add tp, tp, a2 la sp, STACK_SIZE_PER_HART add sp, sp, tp .disable_and_clear_interrupts: csrw CSR_MIE, zero # disable all interrupts csrw CSR_MIP, zero # clear all interrupts .check_if_e51: beqz a0, .e51_decompress .wait_for_decompress_done: la a1, decompress_done_flag REG_L a0, 0(a1) beqz a0, .wait_for_decompress_done j .decompress_done .e51_decompress: call config_l2_cache call .clear_dtim call .clear_l2lim call .clear_l2scratchpad call init_memory call HSS_Setup_Clocks call mss_nwc_init #ifndef CONFIG_CRYPTO_SIGNING .e51_print_message: la a0, g_mss_uart0_lo li a1, 115200 #define MSS_UART_DATA_8_BITS (0x03) #define MSS_UART_NO_PARITY (0x00) #define MSS_UART_ONE_STOP_BIT (0x00) li a2, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT la a0, g_mss_uart1_lo call MSS_UART_init la a0, g_mss_uart2_lo call MSS_UART_init la a0, g_mss_uart3_lo call MSS_UART_init la a0, g_mss_uart4_lo call MSS_UART_init la a0, g_mss_uart0_lo call MSS_UART_init la a1, decomp_msg call MSS_UART_polled_tx_string #endif la a0, hss_l2scratch_lz # compressed image header lw a1, OFFSET_OF(HSS_CompressedImage, version)(a0) # version li a2, mHSS_COMPRESSED_VERSION_DEFLATE beq a1, a2, .e51_miniz_decompress .spin_unknown_compressor: j .spin_unknown_compressor .e51_miniz_decompress: # a3 => compressed length... REG_L a3, OFFSET_OF(HSS_CompressedImage, compressedImageLen)(a0) # a2 => pointer to source REG_L a2, OFFSET_OF(HSS_CompressedImage, headerLength)(a0) add a2, a0, a2 # ... jump source past header to payload # a1 => pointer to store decompressed size, seeded with inital value from image header REG_L a0, OFFSET_OF(HSS_CompressedImage, originalImageLen)(a0) la a1, decompressed_size REG_S a0, 0(a1) # a0 => pointer to destination (where to decompress to) la a0, __l2_start # destination call mz_uncompress j .clear_progress .clear_progress: call validate_crc li a1, 1 beq a0, a1, .crc_good #ifndef CONFIG_CRYPTO_SIGNING la a0, g_mss_uart0_lo la a1, failed_msg call MSS_UART_polled_tx_string 1: la a0, g_mss_uart0_lo call MSS_UART_get_tx_status andi a0, a0, 64 beq a0, zero, 1b # loop until transmitter empty (TEMT) #endif .spin_bad_crc: j .spin_bad_crc .crc_good: #ifndef CONFIG_CRYPTO_SIGNING la a0, g_mss_uart0_lo la a1, passed_msg call MSS_UART_polled_tx_string 1: la a0, g_mss_uart0_lo call MSS_UART_get_tx_status andi a0, a0, 64 beq a0, zero, 1b # loop until transmitter empty (TEMT) #endif li a0, 1 la a1, decompress_done_flag REG_S a0, 0(a1) .decompress_done: fence.i nop nop call _hss_start la a0, _hss_start csrw CSR_MEPC, a0 csrw CSR_MIE, zero # disable all interrupts csrr a0, CSR_MSTATUS and a0, a0, ~MSTATUS_MPIE li a1, ~MSTATUS_MPP and a0, a0, a1 li a1, (PRV_M << 11) or a0, a0, a1 csrw CSR_MSTATUS, a0 csrr a0, CSR_MHARTID li a1, 0 mret .align 3 .early_trap_handler: j .early_trap_handler /*********************************************************************************** * * The following init_memory() symbol overrides the weak symbol in the HAL and does * a safe copy of RW data and clears zero-init memory * */ // zero_section helper function: // a0 = exec_start_addr // a1 = exec_end_addr // .text .type .zero_section, @function .zero_section: beq a0, a1, .zero_section_done sd zero, (a0) addi a0, a0, 8 j .zero_section .zero_section_done: ret // copy_section helper function: // a0 = load_addr // a1 = exec_start_addr // a2 = exec_end_addr .globl copy_section .type copy_section, @function copy_section: beq a1, a0, .copy_section_done // if load_addr == exec_start_addr, goto copy_section_done .check_if_copy_section_done: beq a1, a2, .copy_section_done // if offset != length, goto keep_copying .keep_copying: ld a3, 0(a0) // val = *load_addr sd a3, 0(a1) // *exec_start_addr = val; addi a0, a0, 8 // load_addr = load_addr + 8 addi a1, a1, 8 // exec_start_addr = exec_start_addr + 8 j .check_if_copy_section_done .copy_section_done: ret // init_memory function, used to initialize memory early before C code runs // .globl init_memory .type init_memory, @function init_memory: addi sp,sp,-16 sd ra,8(sp) // // Initialize R/W data // (sdata and data sections) // la a0, __sdata_load la a1, __sdata_start la a2, __sdata_end call copy_section la a0, __data_load la a1, __data_start la a2, __data_end call copy_section // // Clear zero-init memory // (SBSS and BSS sections) // la a0, __sbss_start la a1, __sbss_end call .zero_section la a0, __bss_start la a1, __bss_end ld ra,8(sp) addi sp,sp,16 tail .zero_section /*********************************************************************************** * * The following config_copy() symbol overrides the weak symbol in the HAL and does * a safe copy of HW config data */ // config_copy helper function: // a0 = dest // a1 = src // a2 = length .globl config_copy .weak config_copy .type config_copy, @function config_copy: li a5,0 # initialize offset .check_if_config_copy_done: beq a2,a5, .config_copy_done # if offset == length, goto config_copy_done .do_config_copy: add a4,a1,a5 # csrc = src + offset lbu a3,0(a4) # tmp = *csrc add a4,a0,a5 # cdest = dest + offset addi a5,a5,1 # offset = offset + 1 sb a3,0(a4) # *cdest = *csrc j .check_if_config_copy_done .config_copy_done: ret /*********************************************************************************** * */ .clear_l2scratchpad: // Clear the LIM // // On reset, the first 15 ways are L2 and the last way is cache // We can initialize all, as cache write through to DDR is blocked // until DDR is initialized, so will have no effect other than clear ECC // // NOTE: we need to check if we are debugging from LIM,if so do not initialize la a4, __l2_start la a5, __l2_end j 1f .clear_l2lim: // Clear the LIM // // On reset, the first 15 ways are L2 and the last way is cache // We can initialize all, as cache write through to DDR is blocked // until DDR is initialized, so will have no effect other than clear ECC // // NOTE: we need to check if we are debugging from LIM,if so do not initialize // la a4, __l2lim_start la a5, __l2lim_end j 1f .clear_dtim: // // Clear the E51 DTIM to prevent any memory errors on initial access // to the cache // la a4, __dtim_start la a5, __dtim_end 1: // common loop used by both .clear_l2lim and .clear_dtim REG_S x0, 0(a4) add a4, a4, __SIZEOF_POINTER__ blt a4, a5, 1b .done_clear: ret /*********************************************************************************** * */ .section .data .align 8 decomp_msg: .ascii "\033[2J\033[H" #if defined(CONFIG_COLOR_OUTPUT) .ascii "\033[0m" #endif .asciz "\r\nHSS: decompressing from eNVM to L2 Scratch ... \0" passed_msg: .asciz "Passed\r\n" failed_msg: .asciz "Failed\r\n\0" .globl __sc_start, __sc_load, __sc_end __sc_start: __sc_load: __sc_end: .int 0 /*********************************************************************************** * */ .section .text, "ax", @progbits .option push .option norelax .align 4 .globl hss_l2scratch_lz hss_l2scratch_lz: .incbin "Default/hss-l2scratch.bin.deflate" .section .data .align 8 decompressed_size: .long 0 .align 4 .data decompress_done_flag: .int 0 .option pop hart-software-services-2022.10/envm-wrapper/envm-wrapper_stubs.c000066400000000000000000000030621432224323300247200ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_progress.h" #include "uart_helper.h" void HSS_Debug_Timestamp(void) { ; } void HSS_Debug_Highlight(HSS_Debug_LogLevel_t logLevel) { ; } void HSS_ShowProgress(size_t totalNumTasks, size_t numTasksRemaining) { ; } int sbi_printf(const char *fmt, ...) { (void)fmt; return 0; } void *sbi_memcpy(void *dest, const void *src, size_t n); void *sbi_memcpy(void *dest, const void *src, size_t n) { char *pSrc = (char *)src; char *pDest = (char *)dest; while (n) { *pDest = *pSrc; ++pDest; ++pSrc; --n; } return dest; } void *sbi_memset(void *s, int c, size_t n); void *sbi_memset(void *s, int c, size_t n) { char *pChar = (char *)s; while (n) { *pChar = c; ++pChar; --n; } return s; } void sbi_puts(const char *buf) { (void)buf; } size_t sbi_strlen(const char *str); size_t sbi_strlen(const char *s) { size_t result = 0; while (*s) { ++s; ++result; } return result; } extern uint64_t __l2lim_heap_base; uintptr_t malloc_base = (uintptr_t)&__l2lim_heap_base; void *malloc(size_t size); void *malloc(size_t size) { void *result = (void *)malloc_base; malloc_base += size; return result; } void free(void *ptr); void free(void *ptr) { ; } hart-software-services-2022.10/envm-wrapper/envm-wrapper_validate_crc.c000066400000000000000000000014541432224323300262030ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Implementation of validate_crc() for envm-wrapper. */ #include "hss_types.h" #include #include "hss_debug.h" #include #include #include #include "uart_helper.h" #include "hss_sys_setup.h" #include "hss_crc32.h" bool validate_crc(void); bool validate_crc(void) { extern const struct HSS_CompressedImage hss_l2scratch_lz; extern const unsigned char __l2_start; uint32_t crc32 = CRC32_calculate(&__l2_start, hss_l2scratch_lz.originalImageLen); bool result = 0; if (hss_l2scratch_lz.originalCrc == crc32) { result = 1; } return result; } hart-software-services-2022.10/hart-software-services hw all-harts attach.launch000066400000000000000000000132661432224323300275740ustar00rootroot00000000000000 hart-software-services-2022.10/hart-software-services hw all-harts debug.launch000066400000000000000000000133241432224323300274110ustar00rootroot00000000000000 hart-software-services-2022.10/include/000077500000000000000000000000001432224323300177105ustar00rootroot00000000000000hart-software-services-2022.10/include/csr_helper.h000066400000000000000000000043261432224323300222140ustar00rootroot00000000000000#ifndef HSS_CSR_HELPER_H #define HSS_CSR_HELPER_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - CSR Helper * */ /** * \file CSR Helper * \brief CSR Helper */ #ifdef __cplusplus extern "C" { #endif #include "config.h" #include "hss_types.h" #include "hss_debug.h" #if IS_ENABLED(CONFIG_OPENSBI) # include "sbi/riscv_asm.h" # define ffs SBI_FFS # define fls SBI_FLS # include "sbi/sbi_bitops.h" # undef ffs # undef fls # include "sbi/sbi_hart.h" # include "sbi/sbi_hsm.h" # include "sbi/sbi_init.h" # include "sbi/sbi_scratch.h" #define set_csr(reg, bit) __extension__({ unsigned long __tmp; \ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) # define read_csr csr_read # define write_csr csr_write #else # include "mpfs_hal/encoding.h" # include "mpfs_hal/bits.h" # define csr_read read_csr # define csr_write write_csr #endif HSSTicks_t CSR_GetTickCount(void); HSSTicks_t CSR_GetTime(void); void CSR_ClearMSIP(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/device_serial_number.h000066400000000000000000000030341432224323300242270ustar00rootroot00000000000000#ifndef DEVICE_SERIAL_NUMBER_H #define DEVICE_SERIAL_NUMBER_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Serial Number wrapper * */ #ifdef __cplusplus extern "C" { #endif bool Device_Serial_Number_Init(void); bool Get_Device_Serial_Number(uint8_t **ppBuffer, size_t* pLen); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_atomic.h000066400000000000000000000032641432224323300222170ustar00rootroot00000000000000#ifndef HSS_ATOMIC_H #define HSS_ATOMIC_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - HSS Atomic Fences * */ /** * \file Hart Software Services - Atomic Fences * \brief Hart Software Services - Atomic Fences */ #ifdef __cplusplus extern "C" { #endif #include "hss_atomic.h" #ifndef mb # define mb() asm volatile ("fence" ::: "memory") #endif #ifndef mb_i # define mb_i() asm volatile ("fence.i" ::: "memory") #endif #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_board_init.h000066400000000000000000000027371432224323300230610ustar00rootroot00000000000000#ifndef HSS_BOARD_INIT_H #define HSS_BOARD_INIT_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Board Init Routines * */ #ifdef __cplusplus extern "C" { #endif bool HSS_BoardInit(void); bool HSS_BoardLateInit(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_boot_init.h000066400000000000000000000031441432224323300227260ustar00rootroot00000000000000#ifndef HSS_BOOT_INIT_H #define HSS_BOOT_INIT_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Boot Init Routines * */ #ifdef __cplusplus extern "C" { #endif bool HSS_BootInit(void); void HSS_BootSelectQSPI(void); void HSS_BootSelectMMC(void); void HSS_BootSelectPayload(void); void HSS_BootSelectSPI(void); void HSS_BootListStorageProviders(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_clock.h000066400000000000000000000043571432224323300220420ustar00rootroot00000000000000#ifndef HSS_CLOCK_H #define HSS_CLOCK_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Hart Software Services - Clock and Timer Abstraction */ /** * \file Local Clock Abstraction * \brief Local Clock Abstraction methods - get tick count */ #ifdef __cplusplus extern "C" { #endif //# define TICKS_PER_SEC 50000llu // This is about 1 sec on RENODE //# define TICKS_PER_MILLISEC 5llu // This is about 1 millisec on RENODE #if IS_ENABLED(CONFIG_PLATFORM_MPFS) # include "clocks/hw_mss_clks.h" # define TICKS_PER_SEC ((unsigned long long)LIBERO_SETTING_MSS_RTC_TOGGLE_CLK) # define TICKS_PER_MILLISEC (TICKS_PER_SEC/1000llu) # define ONE_SEC (1llu * TICKS_PER_SEC) # define ONE_MILLISEC (1llu * TICKS_PER_MILLISEC) #endif typedef uint64_t HSSTicks_t; HSSTicks_t HSS_GetTime(void); HSSTicks_t HSS_GetTickCount(void); bool HSS_Timer_IsElapsed(HSSTicks_t startTick, HSSTicks_t durationInTicks); void HSS_SpinDelay_MilliSecs(uint32_t milliseconds); void HSS_SpinDelay_Secs(uint32_t seconds); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_crc16.h000066400000000000000000000027631432224323300216640ustar00rootroot00000000000000#ifndef HSS_CRC16_H #define HSS_CRC16_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - CRC16 calculation. * */ #ifdef __cplusplus extern "C" { #endif #include uint16_t CRC16_calculate(const uint8_t *pInput, size_t numBytes); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_crc32.h000066400000000000000000000031101432224323300216450ustar00rootroot00000000000000#ifndef HSS_CRC32_H #define HSS_CRC32_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - CRC32 calculation. * */ #ifdef __cplusplus extern "C" { #endif #include uint32_t CRC32_calculate(const uint8_t *pInput, size_t numBytes); uint32_t CRC32_calculate_ex(uint32_t seed, uint8_t const *pInput, size_t numBytes); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_debug.h000066400000000000000000000073661432224323300220400ustar00rootroot00000000000000#ifndef HSS_DEBUG_H #define HSS_DEBUG_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - HSS Debugging support * */ /** * \file Debug Logging Functions * \brief Debug Logging Functions */ #ifdef __cplusplus extern "C" { #endif #include "hss_types.h" #if IS_ENABLED(CONFIG_CC_HAS_INTTYPES) # include "inttypes.h" # ifndef PRIu64 # define PRIu64 "llu" # endif #else # define __PRI64_PREFIX "l" # define __PRIPTR_PREFIX "l" # define PRIu64 __PRI64_PREFIX "u" #endif #include "hss_clock.h" typedef enum { HSS_DEBUG_LOG_NORMAL, HSS_DEBUG_LOG_FUNCTION, HSS_DEBUG_LOG_TIMESTAMP, HSS_DEBUG_LOG_ERROR, HSS_DEBUG_LOG_WARN, HSS_DEBUG_LOG_STATUS, HSS_DEBUG_LOG_STATE_TRANSITION, } HSS_Debug_LogLevel_t; void HSS_Debug_Highlight(HSS_Debug_LogLevel_t logLevel); #ifndef __SBI_CONSOLE_H__ int sbi_printf(const char *fmt, ...); void sbi_puts(const char *buf); void sbi_putc(char c); #endif void HSS_Debug_Timestamp(void); # if (IS_ENABLED(CONFIG_LOG_FUNCTION_NAMES)) # define mHSS_FUNCTION \ HSS_Debug_Highlight(HSS_DEBUG_LOG_FUNCTION); \ (void)sbi_printf(" %s(): ", __func__); # else # define mHSS_FUNCTION ; # endif # define mHSS_TIMESTAMP HSS_Debug_Timestamp(); # define mHSS_PUTS sbi_puts # define mHSS_PUTC sbi_putc # define mHSS_FANCY_PRINTF(logLevel, ...) { \ mHSS_TIMESTAMP \ mHSS_FUNCTION \ HSS_Debug_Highlight(HSS_DEBUG_##logLevel); \ sbi_printf(" " __VA_ARGS__); \ HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); \ } # define mHSS_FANCY_PUTS(logLevel, ...) { \ mHSS_TIMESTAMP \ mHSS_FUNCTION \ HSS_Debug_Highlight(HSS_DEBUG_##logLevel); \ sbi_puts(" " __VA_ARGS__); \ HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); \ } # define mHSS_PRINTF sbi_printf # define mHSS_FANCY_PRINTF_EX sbi_printf #ifndef mHSS_DEBUG_PRINTF //# ifdef DEBUG # define mHSS_DEBUG_PRINTF(logLevel, ...) { \ mHSS_TIMESTAMP \ mHSS_FUNCTION \ HSS_Debug_Highlight(HSS_DEBUG_##logLevel); \ sbi_printf(" " __VA_ARGS__); \ HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); \ } # define mHSS_DEBUG_PRINTF_EX sbi_printf # define mHSS_DEBUG_PUTS sbi_puts //# else //# define mHSS_DEBUG_PRINTF(logLevel, ...) (void)(0) //# define mHSS_DEBUG_PRINTF_EX (void) //# define mHSS_DEBUG_PUTS (void) ///# endif #endif #define mDO_PRAGMA(x) _Pragma(#x) #define mTODO(x) mDO_PRAGMA(message ("TODO: " #x)) #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_init.h000066400000000000000000000043741432224323300217110ustar00rootroot00000000000000#ifndef HSS_INIT_H #define HSS_INIT_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Toplevel Init Routines * */ #ifdef __cplusplus extern "C" { #endif void HSS_Init(void); bool HSS_ZeroTIMs(void); bool HSS_ZeroDDR(void); bool HSS_Init_RWDATA_BSS(void); bool HSS_WakeSleepingHarts(void); bool HSS_E51_Banner(void); bool HSS_QueuesInit(void); #if IS_ENABLED(CONFIG_SERVICE_QSPI) # include "qspi_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) # include "mmc_service.h" #endif #if IS_ENABLED(CONFIG_OPENSBI) bool HSS_OpenSBIInit(void); #endif bool HSS_DDRInit(void); bool HSS_DDRPrintSegConfig(void); bool HSS_DDRPrintL2CacheWaysConfig(void); bool HSS_DDRPrintL2CacheWayMasks(void); bool HSS_UARTInit(void); #if IS_ENABLED(CONFIG_USE_LOGO) bool HSS_LogoInit(void); #endif #if IS_ENABLED(CONFIG_USE_IHC) bool HSS_IHCInit(void); void HSS_IHCInit_U54(void); #endif #ifdef CONFIG_USE_PCIE bool HSS_PCIeInit(void); #endif bool HSS_USBInit(void); bool HSS_PDMAInit(void); bool HSS_ResetReasonInit(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_logo_init.h000066400000000000000000000030241432224323300227200ustar00rootroot00000000000000#ifndef HSS_LOGO_INIT_H #define HSS_LOGO_INIT_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Microchip Logo Initialization * */ #ifdef __cplusplus extern "C" { #endif /** * \file HSS Logo Initalization * \brief HSS Logo Initialization */ bool HSS_LogoInit(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_memcpy_via_pdma.h000066400000000000000000000030571432224323300240750ustar00rootroot00000000000000#ifndef HSS_MEMCPY_VIA_PDMA_H #define HSS_MEMCPY_VIA_PDMA_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - memcpy via PDMA * */ #ifdef __cplusplus extern "C" { #endif /** * \file memcpy via PDMA * \brief memcpy via PDMA */ void *memcpy_via_pdma(void *dest, void const *src, size_t num_bytes); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_memtest.h000066400000000000000000000031511432224323300224140ustar00rootroot00000000000000#ifndef HSS_MEMTEST_H #define HSS_MEMTEST_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Simple Memory Tester */ #ifdef __cplusplus extern "C" { #endif /** * \file Simple Memory Tester * \brief Simple Memory Tester */ bool HSS_MemTestDDRFast(void); bool HSS_MemTestDDRFull(void); bool HSS_MemTestDDR_Ex(volatile uint64_t *baseAddr, size_t numBytes); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_progress.h000066400000000000000000000033101432224323300225770ustar00rootroot00000000000000#ifndef HSS_PROGRESS_H #define HSS_PROGRESS_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Progress output utility */ #ifdef __cplusplus extern "C" { #endif /** * \file Progress output utilities for long-running functions * \brief Progress output utilities for long-running functions */ void HSS_ShowProgress(size_t totalNumTasks, size_t numTasksRemaining); bool HSS_ShowTimeout(char const * const msg, uint32_t timeout_sec, uint8_t *pRcvBuf); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_registry.h000066400000000000000000000035611432224323300226130ustar00rootroot00000000000000#ifndef HSS_REGISTRY_H #define HSS_REGISTRY_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Registry of Tables (State Machines, IPI handlers, Init * Functions) * */ /*! * \file HSS Registry * \brief Initalization for any registered tables. */ #ifdef __cplusplus extern "C" { #endif extern const struct IPI_Handler /*@null@*/ ipiRegistry[]; extern struct StateMachine /*@null@*/ * const pGlobalStateMachines[]; extern const struct InitFunction /*@null@*/ globalInitFunctions[]; extern const size_t spanOfIpiRegistry; extern const size_t spanOfPGlobalStateMachines; extern const size_t spanOfGlobalInitFunctions; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_state_machine.h000066400000000000000000000064231432224323300235470ustar00rootroot00000000000000#ifndef MPFS_HSS_STATE_MACHINE_H #define MPFS_HSS_STATE_MACHINE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - State Machine Defines/Types/Declarations * */ /** * \file State Machine * \brief State Machine Defines/Types/Declarations */ #ifdef __cplusplus extern "C" { #endif #include "hss_clock.h" struct StateMachine; typedef int stateType_t; /** * \brief State Descriptor Structure * * A State Descriptor contains all information about a particular state * within a state machine */ struct StateDesc { stateType_t state; const char* const pStateName; void (*state_onEntry)(struct StateMachine *pMyMachine); void (*state_onExit)(struct StateMachine *pMyMachine); void (*state_handler)(struct StateMachine *pMyMachine); }; /** * \brief StateMachine Structure * * A State Machine is a colection of states and some context, and forms * a runnable entity for the superloop state machine engine */ struct StateMachine { stateType_t state; stateType_t prevState; const uint32_t numStates; const char * const pMachineName; HSSTicks_t startTick; HSSTicks_t lastExecutionTick; HSSTicks_t startTime; HSSTicks_t lastExecutionTime; HSSTicks_t maxExecutionTime; stateType_t maxState; HSSTicks_t lastDeltaExecutionTime; uint64_t executionCount; struct StateDesc const * const pStateDescs; bool debugFlag; uint8_t priority; void *pInstanceData; }; #define SM_INVALID_STATE ((stateType_t)-1) void RunStateMachine(struct StateMachine * const pCurrentMachine); void RunStateMachines(const size_t spanOfPStateMachines, struct StateMachine * const pStateMachines[]); /** * \brief Init Function Type */ struct InitFunction { const char * const pName; bool (*handler)(void); int haltOnFailure:1; int restartOnFailure:1; }; /** * \brief Get State Machines loop count */ uint64_t GetStateMachinesExecutionCount(void); #ifdef __cplusplus } #endif void RunInitFunctions(const size_t spanOfInitFunctions, const struct InitFunction initFunctions[]); void DumpStateMachineStats(void); #endif hart-software-services-2022.10/include/hss_sys_setup.h000066400000000000000000000032401432224323300227730ustar00rootroot00000000000000#ifndef HSS_SYS_SETUP_H #define HSS_SYS_SETUP_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - System Setup * */ /*! * \file System Setup * \brief Basic System Setup * */ #ifdef __cplusplus extern "C" { #endif /** * Interface */ bool HSS_Setup_PLIC(void); bool HSS_Setup_MPU(void); bool HSS_Setup_L2Cache(void); bool HSS_Setup_Clocks(void); bool HSS_Setup_PMP(void); bool HSS_Setup_BusErrorUnit(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_types.h000066400000000000000000000152621432224323300221100ustar00rootroot00000000000000#ifndef HSS_TYPES_H #define HSS_TYPES_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - HSS Types * */ /** * \file MPFS HSS Embedded Software - Types * \brief MPFS HSS Embedded Software - Types */ #ifdef __cplusplus extern "C" { #endif #include // ptrdiff_t /* * We'll use the same trick as used by Linux for its Kconfig options... * * With variable arguments to our macro, if our config option is defined, it will cause * the insertion of "0, " as a prefix the arguments to ___IS_ENABLED(CONFIG_), which will * then cause __IS_ENABLED(CONFIG_) itself to resolve to 1, otherwise 0 * */ #define _ARG_SHUFFLE_RIGHT_IF_1 0, #define IS_ENABLED(cfg) _IS_ENABLED(cfg) #define _IS_ENABLED(val) __IS_ENABLED(_ARG_SHUFFLE_RIGHT_IF_##val) #define __IS_ENABLED(shuffle_or_blank) ___IS_ENABLED(shuffle_or_blank 1, 0) #define ___IS_ENABLED(ignored, desiredVal, ...) desiredVal #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define mHSS_BOOT_MAGIC (0xB007C0DEu) #define mHSS_COMPRESSED_MAGIC (0xC08B8355u) #define mHSS_BOOT_VERSION 1u #ifndef CONFIG_OPENSBI # define MIN(A,B) ((A) < (B) ? A : B) # define likely(x) __builtin_expect((x), 1) # define unlikely(x) __builtin_expect((x), 0) # ifndef __ssize_t_defined # define __ssize_t_defined typedef long ssize_t; # endif # include // for size_t # include // for bool, true, false # include #else # ifdef __packed # undef __packed # endif # include "sbi/sbi_types.h" # define true TRUE # define false FALSE #endif /** * \brief HSS Cores Enumeration */ enum HSSHartId { HSS_HART_E51 = 0, HSS_HART_U54_1, HSS_HART_U54_2, HSS_HART_U54_3, HSS_HART_U54_4, HSS_HART_NUM_PEERS, HSS_HART_ALL = HSS_HART_NUM_PEERS }; #define MAX_NUM_HARTS ((unsigned)HSS_HART_NUM_PEERS) #define mHSS_BITMASK_ALL_U54 (0x1Eu) #define BOOT_FLAG_ANCILLIARY_DATA (0x80u) #define BOOT_FLAG_SKIP_OPENSBI (0x40u) #define BOOT_FLAG_ALLOW_COLD_REBOOT (0x20u) #define BOOT_FLAG_ALLOW_WARM_REBOOT (0x10u) #define BOOT_FLAG_SKIP_AUTOBOOT (0x08u) typedef union HSSHartBitmask { unsigned int uint; struct { unsigned int e51:1; unsigned int u54_1:1; unsigned int u54_2:1; unsigned int u54_3:1; unsigned int u54_4:1; } s; } HSSHartBitmask_t; /** * \brief Chunk Descriptor Structure for boot image * * Describes where to copy and how much... * */ #pragma pack(8) struct HSS_BootChunkDesc { enum HSSHartId owner; uintptr_t loadAddr; uintptr_t execAddr; size_t size; uint32_t crc32; }; /** * * \brief Descriptor for U54 Boot Zero-Initialized Chunk * */ struct HSS_BootZIChunkDesc { enum HSSHartId owner; void *execAddr; size_t size; }; /** * \brief Boot Image Structure * * \warning The chunk table *must* be terminated with a size of 0 sentinel! */ #define BOOT_IMAGE_MAX_NAME_LEN (256) // pre crypto-signing, the BootImage format was slightly different, so to ensure // no CRC failures on older images, we provide a legacy structure here purely for sizing struct HSS_BootImage_v0 { uint32_t magic; uint32_t version; size_t headerLength; uint32_t headerCrc; size_t chunkTableOffset; size_t ziChunkTableOffset; struct { uintptr_t entryPoint; uint8_t privMode; uint8_t flags; size_t numChunks; size_t firstChunk; size_t lastChunk; char name[BOOT_IMAGE_MAX_NAME_LEN]; } hart[MAX_NUM_HARTS-1]; // E51 is not counted, only U54s char set_name[BOOT_IMAGE_MAX_NAME_LEN]; size_t bootImageLength; uint8_t pad1[32]; uint8_t pad2[32]; }; struct HSS_Signature { uint8_t digest[48]; // SHA384 uint8_t ecdsaSig[96]; // SECP384R1 }; struct HSS_BootImage { uint32_t magic; uint32_t version; size_t headerLength; uint32_t headerCrc; size_t chunkTableOffset; size_t ziChunkTableOffset; struct { uintptr_t entryPoint; uint8_t privMode; uint8_t flags; size_t numChunks; size_t firstChunk; size_t lastChunk; char name[BOOT_IMAGE_MAX_NAME_LEN]; } hart[MAX_NUM_HARTS-1]; // E51 is not counted, only U54s char set_name[BOOT_IMAGE_MAX_NAME_LEN]; size_t bootImageLength; struct HSS_Signature signature; }; /** * \brief Compressed Image Structure * */ struct HSS_CompressedImage { uint32_t magic; uint32_t version; size_t headerLength; uint32_t headerCrc; uint32_t compressedCrc; uint32_t originalCrc; size_t compressedImageLen; size_t originalImageLen; #if IS_ENABLED(CONFIG_CRYPTO_SIGNING) struct HSS_Signature signature; #else uint8_t pad1[32]; // padding to keep compatibility with older format uint8_t pad2[32]; // padding to keep compatibility with older format #endif }; struct HSS_Storage; typedef bool (* HSS_GetBootImageFnPtr_t)(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage); struct HSS_Storage { char const * const name; HSS_GetBootImageFnPtr_t const getBootImage; bool (* const init)(void); bool (* const readBlock)(void *pDest, size_t srcOffset, size_t byteCount); bool (* const writeBlock)(size_t dstOffset, void *pSrc, size_t byteCount); void (* const getInfo)(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount); void (* const flushWriteBuffer)(void); }; #define mHSS_COMPRESSED_VERSION_DEFLATE 1u #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/hss_version.h000066400000000000000000000032301432224323300224210ustar00rootroot00000000000000#ifndef HSS_VERSION_H #define HSS_VERSION_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - HSS Version * */ /** * \file MPFS HSS Embedded Software - Version * \brief MPFS HSS Embedded Software - Version */ #ifdef __cplusplus extern "C" { #endif #define HSS_VERSION_MAJOR 0 #define HSS_VERSION_MINOR 99 #define HSS_VERSION_PATCH 33 #ifndef VENDOR_STRING # define VENDOR_STRING "-dev-build" #endif #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/mpfs_reg_map.h000066400000000000000000000237571432224323300225360ustar00rootroot00000000000000#ifndef HSS_MPFS_REG_MAP_H #define HSS_MPFS_REG_MAP_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Register Definitions * */ #ifdef __cplusplus extern "C" { #endif #define E51_DTIM_BASE_ADDR (0x01000000u) #define E51_ITIM_BASE_ADDR (0x01800000u) #define U54_1_ITIM_BASE_ADDR (0x01808000u) #define U54_2_ITIM_BASE_ADDR (0x01810000u) #define U54_3_ITIM_BASE_ADDR (0x01818000u) #define U54_4_ITIM_BASE_ADDR (0x01820000u) #define CLINT_BASE_ADDR (0x02000000u) #define CLINT_MSIP_E51_0_OFFSET (0x0000u) #define CLINT_MSIP_U54_1_OFFSET (0x0004u) #define CLINT_MSIP_U54_2_OFFSET (0x0008u) #define CLINT_MSIP_U54_3_OFFSET (0x000Cu) #define CLINT_MSIP_U54_4_OFFSET (0x0010u) #define CLINT_MTIME_OFFSET (0xBFF8u) #define L2_CACHE_CTRL_BASE_ADDR (0x02010000u) #define L2_CACHE_CTRL_CONFIG_OFFSET (0x000u) #define L2_CACHE_CTRL_WAYENABLE_OFFSET (0x008u) #define L2_CACHE_CTRL_WAYMASK0_OFFSET (0x800u) #define L2_CACHE_CTRL_WAYMASK1_OFFSET (0x008u) #define L2_CACHE_CTRL_WAYMASK2_OFFSET (0x810u) #define L2_CACHE_CTRL_WAYMASK3_OFFSET (0x818u) #define L2_CACHE_CTRL_WAYMASK4_OFFSET (0x820u) #define WCB_BASE_ADDR (0x02020000u) #define DMA_CTRL_BASE_ADDR (0x03000000u) #define L2_LIM_BASE_ADDR (0x08000000u) #define L2_ZERODEV_BASE_ADDR (0x0A000000u) #ifndef PLIC_BASE_ADDR # define PLIC_BASE_ADDR (0x0C000000u) #endif #define SYSREGSCB_BASE_ADDR (0x20003000u) #define SYSREGSCB_MSS_STATUS_OFFSET (0x0104u) #define MPU_BASE_ADDR (0x2000E000u) #define MPU_FIC0_OFFSET (0x0000u) #define MPU_FIC1_OFFSET (0x0100u) #define MPU_FIC2_OFFSET (0x0200u) #define MPU_CRYPTO_OFFSET (0x0300u) #define MPU_ETHERNET0_OFFSET (0x0400u) #define MPU_ETHERNET1_OFFSET (0x0500u) #define MPU_USB_OFFSET (0x0600u) #define MPU_MMC_OFFSET (0x0700u) #define MPU_SCB_OFFSET (0x0800u) #define MPU_SEG0_OFFSET (0x0D00u) #define MPU_SEG1_OFFSET (0x0E00u) #define WDOG0_LO_BASE_ADDR (0x20001000u) #define WDOG1_LO_BASE_ADDR (0x20101000u) #define WDOG2_LO_BASE_ADDR (0x20103000u) #define WDOG3_LO_BASE_ADDR (0x20105000u) #define WDOG4_LO_BASE_ADDR (0x20107000u) #define WDOG_REFRESH_OFFSET (0x0000u) #define WDOG_CONTROL_OFFSET (0x0004u) #define WDOG_STATUS_OFFSET (0x0008u) #define WDOG_TIME_OFFSET (0x000Cu) #define WDOG_MSVP_OFFSET (0x0010u) #define WDOG_TRIGGER_OFFSET (0x0014u) #define WDOG_FORCE_OFFSET (0x0018u) #define WDOG_STATUS_DEVRST_MASK (1u << 5) #define WDOG_STATUS_LOCKED_MASK (1u << 4) #define WDOG_STATUS_TRIGGERED_MASK (1u << 3) #define WDOG_STATUS_FORBIDDEN_MASK (1u << 2) #define WDOG_STATUS_WDOG_TRIPPED_MASK (1u << 1) #define WDOG_STATUS_MVSP_TRIPPED_MASK (1u << 0) #define WDOG0_LO_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG0_LO_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG0_LO_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG0_LO_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG0_LO_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG0_LO_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG0_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG1_LO_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG1_LO_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG1_LO_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG1_LO_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG1_LO_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG1_LO_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG1_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG2_LO_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG2_LO_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG2_LO_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG2_LO_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG2_LO_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG2_LO_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG2_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG3_LO_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG3_LO_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG3_LO_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG3_LO_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG3_LO_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG3_LO_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG3_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG4_LO_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG4_LO_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG4_LO_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG4_LO_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG4_LO_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG4_LO_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG4_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG0_HI_BASE_ADDR (0x28001000u) #define WDOG1_HI_BASE_ADDR (0x28101000u) #define WDOG2_HI_BASE_ADDR (0x28103000u) #define WDOG3_HI_BASE_ADDR (0x28105000u) #define WDOG4_HI_BASE_ADDR (0x28107000u) #define WDOG0_HI_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG0_HI_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG0_HI_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG0_HI_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG0_HI_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG0_HI_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG0_HI_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG1_HI_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG1_HI_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG1_HI_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG1_HI_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG1_HI_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG1_HI_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG1_HI_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG2_HI_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG2_LO_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG2_HI_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG2_HI_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG2_LO_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG2_HI_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG2_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG3_LO_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG3_HI_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG3_HI_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG3_LO_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG3_HI_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG3_HI_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG3_HI_FORCE_OFFSET WDOG_FORCE_OFFSET #define WDOG4_HI_REFRESH_OFFSET WDOG_REFRESH_OFFSET #define WDOG4_HI_CONTROL_OFFSET WDOG_CONTROL_OFFSET #define WDOG4_HI_STATUS_OFFSET WDOG_STATUS_OFFSET #define WDOG4_HI_TIME_OFFSET WDOG_TIME_OFFSET #define WDOG4_HI_MSVP_OFFSET WDOG_MSVP_OFFSET #define WDOG4_HI_TRIGGER_OFFSET WDOG_TRIGGER_OFFSET #define WDOG4_LO_FORCE_OFFSET WDOG_FORCE_OFFSET #define mHSS_WriteRegEx(type, block, reg, value) { *(type*)(block##_BASE_ADDR + block##_##reg##_OFFSET) = value; } #define mHSS_WriteRegU8(block, reg, value) mHSS_WriteRegEx(uint8_t, block, reg, value) #define mHSS_WriteRegU16(block, reg, value) mHSS_WriteRegEx(uint16_t, block, reg, value) #define mHSS_WriteRegU32(block, reg, value) mHSS_WriteRegEx(uint32_t, block, reg, value) #define mHSS_WriteRegEx(type, block, reg, value) { *(type*)(block##_BASE_ADDR + block##_##reg##_OFFSET) = value; } #define mHSS_WriteRegU8(block, reg, value) mHSS_WriteRegEx(uint8_t, block, reg, value) #define mHSS_WriteRegU16(block, reg, value) mHSS_WriteRegEx(uint16_t, block, reg, value) #define mHSS_WriteRegU32(block, reg, value) mHSS_WriteRegEx(uint32_t, block, reg, value) #define mHSS_WriteRegU64(block, reg, value) mHSS_WriteRegEx(uint64_t, block, reg, value) #define mHSS_ReadRegEx(type, block, reg) (*(volatile type*)(block##_BASE_ADDR + block##_##reg##_OFFSET)) #define mHSS_ReadRegU8(block, reg) mHSS_ReadRegEx(uint8_t, block, reg) #define mHSS_ReadRegU16(block, reg) mHSS_ReadRegEx(uint16_t, block, reg) #define mHSS_ReadRegU32(block, reg) mHSS_ReadRegEx(uint32_t, block, reg) #define mHSS_ReadRegU64(block, reg) mHSS_ReadRegEx(uint64_t, block, reg) #define mHSS_ReadModWriteRegEx(type, block, reg, mask, value) mHSS_WriteRegEx(type, block, reg, (mHSS_ReadRegEx(type, block, reg) & mask) | (value & mask)) #define mHSS_ReadModWriteRegU8(block, reg, mask, value) mHSS_WriteRegEx(uint8_t, block, reg, (mHSS_ReadRegEx(uint8_t, block, reg) & mask) | (value & mask)) #define mHSS_ReadModWriteRegU16(block, reg, mask, value) mHSS_WriteRegEx(uint16_t, block, reg, (mHSS_ReadRegEx(uint16_t, block, reg) & mask) | (value & mask)) #define mHSS_ReadModWriteRegU32(block, reg, mask, value) mHSS_WriteRegEx(uint32_t, block, reg, (mHSS_ReadRegEx(uint32_t, block, reg) & mask) | (value & mask)) #define mHSS_ReadModWriteRegU64(block, reg, mask, value) mHSS_WriteRegEx(uint64_t, block, reg, (mHSS_ReadRegEx(uint64_t, block, reg) & mask) | (value & mask)) #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/profiling.h000066400000000000000000000035001432224323300220500ustar00rootroot00000000000000#ifndef HSS_PROFILING_H #define HSS_PROFILING_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Function Profiling (Debug) Support * */ /** * \file Profiling Support * \brief Profiling Support */ #ifdef __cplusplus extern "C" { #endif #include "config.h" #include "hss_types.h" #include "hss_debug.h" void __cyg_profile_func_enter (void *pFunc, void *pCaller) __attribute__((no_instrument_function)); void __cyg_profile_func_exit (void *pFunc, void *pCaller) __attribute__((no_instrument_function)); void dump_profile(void) __attribute__((no_instrument_function)); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/u54_handle_ipi.h000066400000000000000000000030111432224323300226450ustar00rootroot00000000000000#ifndef HSS_U54_HANDLE_IPI_H #define HSS_U54_HANDLE_IPI_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - U54 IPI Handler toplevel * */ #ifdef __cplusplus extern "C" { #endif /*! * \file U54 Handle IPI * \brief U54 Handle IPI */ void HSS_U54_Banner(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/u54_state.h000066400000000000000000000036301432224323300217000ustar00rootroot00000000000000#ifndef HSS_U54_STATE_H #define HSS_U54_STATE_H /******************************************************************************* * Copyright 2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - U54 State * */ #ifdef __cplusplus extern "C" { #endif /*! * \file U54 State * \brief U54 State */ enum HSSHartState_t { HSS_State_Idle = 0, HSS_State_Booting, HSS_State_SBIHartInit, HSS_State_SBIWaitForColdboot, HSS_State_Running, HSS_State_Trap, HSS_State_Fatal, }; int HSS_U54_GetState(void); int HSS_U54_GetState_Ex(int hartId); char const * HSS_U54_GetStateName(int hartId); void HSS_U54_SetState(int state); void HSS_U54_SetState_Ex(int hartId, int state); void HSS_U54_DumpStatesIfChanged(void); void HSS_U54_DumpStates(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/include/uart_helper.h000066400000000000000000000032561432224323300224010ustar00rootroot00000000000000#ifndef UART_HELPER_H #define UART_HELPER_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Implementation of UART helper routines */ #ifdef __cplusplus extern "C" { #endif #define HSS_UART_HELPER_MAX_GETLINE 80u int uart_putstring(int hartid, char *p); ssize_t uart_getline(char **pBuffer, size_t *pBufLen); bool uart_getchar(uint8_t *pbuf, int32_t timeout_sec, bool do_sec_tick); void uart_putc(int hartid, const char ch); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/init/000077500000000000000000000000001432224323300172305ustar00rootroot00000000000000hart-software-services-2022.10/init/Makefile000066400000000000000000000037031432224323300206730ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Initialization Routines EXTRA_SRCS-y += \ init/hss_ddr_init.c \ init/hss_boot_init.c \ init/hss_sys_setup.c \ EXTRA_SRCS-y += \ init/hss_usb_init.c EXTRA_SRCS-$(CONFIG_USE_IHC) += \ init/hss_ihc_init.c EXTRA_SRCS-$(CONFIG_USE_PCIE) += \ init/hss_pcie_init.c EXTRA_SRCS-$(CONFIG_USE_PDMA) += \ init/hss_pdma_init.c \ EXTRA_SRCS-$(CONFIG_OPENSBI) += \ init/hss_opensbi_init.c INCLUDES +=\ -Ibaremetal/drivers/mss/mss_usb \ init/hss_ddr_init.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_pdma_init.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_boot_init.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_opensbi_init.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_sys_setup.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_pcie_init.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_usb_init.o: CFLAGS=$(CFLAGS_GCCEXT) init/hss_ihc_init.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/init/hss_boot_init.c000066400000000000000000000427231432224323300222470ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Boot Initalization * \brief Boot Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "hss_boot_service.h" #include "hss_boot_init.h" #include "hss_sys_setup.h" #include "hss_progress.h" #if IS_ENABLED(CONFIG_SERVICE_SPI) # include # define SPI_FLASH_BOOT_ENABLED (CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET != 0xFFFFFFFF) #else # define SPI_FLASH_BOOT_ENABLED 0 #endif #if IS_ENABLED(CONFIG_SERVICE_OPENSBI) # include "opensbi_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI) # include "qspi_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) # include "mmc_service.h" # include "gpt.h" #endif #if (SPI_FLASH_BOOT_ENABLED) # include "mss_sys_services.h" #endif #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_perfctr.h" #include #include #if IS_ENABLED(CONFIG_COMPRESSION) # include "hss_decompress.h" #endif #if IS_ENABLED(CONFIG_CRYPTO_SIGNING) # include "hss_boot_secure.h" #endif #include "hss_boot_pmp.h" #include "hss_atomic.h" // // local module functions #if IS_ENABLED(CONFIG_SERVICE_BOOT) # if !IS_ENABLED(CONFIG_SERVICE_BOOT_USE_PAYLOAD) typedef bool (*HSS_BootImageCopyFnPtr_t)(void *pDest, size_t srcOffset, size_t byteCount); static bool copyBootImageToDDR_(struct HSS_BootImage *pBootImage, char *pDest, size_t srcOffset, HSS_BootImageCopyFnPtr_t pCopyFunction); # endif static void printBootImageDetails_(struct HSS_BootImage const * const pBootImage); static bool tryBootFunction_(struct HSS_Storage *pStorage, HSS_GetBootImageFnPtr_t getBootImageFunction); #endif static bool getBootImageFromQSPI_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage); static bool getBootImageFromMMC_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage); static bool getBootImageFromSpiFlash_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage); static bool getBootImageFromPayload_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage); // // #if IS_ENABLED(CONFIG_SERVICE_QSPI) static struct HSS_Storage qspiStorage_ = { .name = "QSPI", .getBootImage = getBootImageFromQSPI_, .init = HSS_CachedQSPIInit, .readBlock = HSS_CachedQSPI_ReadBlock, .writeBlock = HSS_CachedQSPI_WriteBlock, .getInfo = HSS_CachedQSPI_GetInfo, .flushWriteBuffer = HSS_CachedQSPI_FlushWriteBuffer }; #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) static struct HSS_Storage mmcStorage_ = { .name = "MMC", .getBootImage = getBootImageFromMMC_, .init = HSS_MMCInit, .readBlock = HSS_MMC_ReadBlock, .writeBlock = HSS_MMC_WriteBlockSDMA, .getInfo = HSS_MMC_GetInfo, .flushWriteBuffer = NULL }; #endif #if IS_ENABLED(CONFIG_SERVICE_SPI) static struct HSS_Storage spiStorage_ = { .name = "SPI", .getBootImage = getBootImageFromSpiFlash_, .init = NULL, .readBlock = NULL, .writeBlock = NULL, .getInfo = NULL, .flushWriteBuffer = NULL }; #endif #if IS_ENABLED(CONFIG_SERVICE_BOOT_USE_PAYLOAD) static struct HSS_Storage payloadStorage_ = { .name = "Payload", .getBootImage = getBootImageFromPayload_, .init = NULL, .readBlock = NULL, .writeBlock = NULL, .getInfo = NULL, .flushWriteBuffer = NULL }; #endif static struct HSS_Storage *pStorages[] = { #if IS_ENABLED(CONFIG_SERVICE_QSPI) &qspiStorage_, #endif #if IS_ENABLED(CONFIG_SERVICE_SPI) &spiStorage_, #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) &mmcStorage_, #endif #if IS_ENABLED(CONFIG_SERVICE_BOOT_USE_PAYLOAD) &payloadStorage_, #endif }; static struct HSS_Storage *pDefaultStorage = NULL; #if IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI) || (IS_ENABLED(CONFIG_SERVICE_SPI) && (SPI_FLASH_BOOT_ENABLED)) struct HSS_BootImage bootImage __attribute__((aligned(8))); #elif IS_ENABLED(CONFIG_SERVICE_BOOT_USE_PAYLOAD) // #else # error Unable to determine boot mechanism #endif struct HSS_Storage *HSS_BootGetActiveStorage(void); struct HSS_Storage *HSS_BootGetActiveStorage(void) { struct HSS_Storage *pResult = pDefaultStorage; if (!pResult) { pResult = pStorages[0]; } return pResult; } void HSS_BootListStorageProviders(void) { for (uint32_t i = 0; i < ARRAY_SIZE(pStorages); i++) { mHSS_DEBUG_PRINTF_EX(" - %s\n", pStorages[i]->name); } } bool HSS_BootInit(void) { bool result = true; #if IS_ENABLED(CONFIG_SERVICE_BOOT) mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initializing Boot Image ...\n"); int perf_ctr_index = PERF_CTR_UNINITIALIZED; HSS_PerfCtr_Allocate(&perf_ctr_index, "Boot Image Init"); if (pDefaultStorage) { result = pDefaultStorage->init(); if (result) { result = tryBootFunction_(pDefaultStorage, pDefaultStorage->getBootImage); } } else { for (int i = 0; i < ARRAY_SIZE(pStorages); i++) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Trying to boot via %s ...\n", pStorages[i]->name); if (pStorages[i]->init) { result = pStorages[i]->init(); } else { result = true; } if (result) { result = tryBootFunction_(pStorages[i], pStorages[i]->getBootImage); if (result) { break; } } } } HSS_PerfCtr_Lap(perf_ctr_index); #endif return result; } #if IS_ENABLED(CONFIG_SERVICE_BOOT) bool tryBootFunction_(struct HSS_Storage *pStorage, HSS_GetBootImageFnPtr_t const bootImageFunction) { bool result = false; (void)pStorage; struct HSS_BootImage *pBootImage = NULL; bool decompressedFlag = false; (void)decompressedFlag; result = bootImageFunction(pStorage, &pBootImage); // // check if this image is compressed... // if so, decompress it to DDR // // for now, compression only works with a source already in DDR # if IS_ENABLED(CONFIG_COMPRESSION) if (result && pBootImage->magic == mHSS_COMPRESSED_MAGIC) { decompressedFlag = true; if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Failed to get boot image, cannot decompress\n"); } else if (!pBootImage) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Boot Image NULL, ignoring\n"); result = false; } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Preparing to decompress to DDR ...\n"); void* const pInput = (void*)pBootImage; void * const pOutputInDDR = (void *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR); int outputSize = HSS_Decompress(pInput, pOutputInDDR); mHSS_DEBUG_PRINTF(LOG_NORMAL, "decompressed %d bytes ...\n", outputSize); if (outputSize) { pBootImage = (struct HSS_BootImage *)pOutputInDDR; } else { pBootImage = NULL; } } } # endif if (result) { HSS_Register_Boot_Image(pBootImage); mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s: Boot Image registered ...\n", pStorage->name); } return result; } ///////////////////////////////////////////////////////////////////////////////////////// static void printBootImageDetails_(struct HSS_BootImage const * const pBootImage) { # ifdef BOOT_DEBUG mHSS_DEBUG_PRINTF(LOG_NORMAL, " - set name is >>%s<<\n", pBootImage->set_name); mHSS_DEBUG_PRINTF(LOG_NORMAL, " - magic is %08x\n", pBootImage->magic); mHSS_DEBUG_PRINTF(LOG_NORMAL, " - length is %08x\n", pBootImage->bootImageLength); # endif } #endif #if IS_ENABLED(CONFIG_SERVICE_BOOT) && !IS_ENABLED(CONFIG_SERVICE_BOOT_USE_PAYLOAD) static bool copyBootImageToDDR_(struct HSS_BootImage *pBootImage, char *pDest, size_t srcOffset, HSS_BootImageCopyFnPtr_t pCopyFunction) { bool result = true; printBootImageDetails_(pBootImage); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Copying %lu bytes to 0x%lx\n", pBootImage->bootImageLength, pDest); result = pCopyFunction(pDest, srcOffset, pBootImage->bootImageLength); return result; } #endif static bool getBootImageFromMMC_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage) { bool result = false; #if IS_ENABLED(CONFIG_SERVICE_BOOT) && IS_ENABLED(CONFIG_SERVICE_MMC) assert(ppBootImage); // if we are using MMC, then we need to do an initial copy of the // boot header into our structure, for subsequent use mHSS_DEBUG_PRINTF(LOG_NORMAL, "Preparing to copy from MMC to DDR ...\n"); size_t srcLBAOffset = 0u; assert(pStorage); uint32_t blockSize, eraseSize, blockCount; pStorage->getInfo(&blockSize, &eraseSize, &blockCount); # if (IS_ENABLED(CONFIG_SERVICE_BOOT_MMC_USE_GPT)) { HSS_GPT_t gpt; gpt.lbaSize = blockSize; GPT_Init(&gpt, pStorage); result = GPT_ReadHeader(&gpt); if (result) { size_t srcIndex = 0u; if (GPT_GetBootPartitionIndex(&gpt, &srcIndex)) { mHSS_DEBUG_PRINTF(LOG_WARN, "Using manually set partition index\n"); } else { result = GPT_FindBootSectorIndex(&gpt, &srcIndex, NULL); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT_FindBootSectorIndex() failed\n"); } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Boot Partition found at index %lu\n", srcIndex); } } if (result) { result = GPT_PartitionIdToLBAOffset(&gpt, srcIndex, &srcLBAOffset); } } } if (!result) { mHSS_DEBUG_PRINTF(LOG_WARN, "GPT_PartitionIdToLBAOffset() failed - using offset %lu\n", srcLBAOffset); } else { //mHSS_DEBUG_PRINTF(LOG_WARN, "GPT_PartitionIdToLBAOffset() returned %lu\n", srcLBAOffset); } #endif // // Even if we have GPT enabled and it fails to find a GPT parttion, we'll still // try to boot { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Attempting to read image header (%d bytes) ...\n", sizeof(struct HSS_BootImage)); result = HSS_MMC_ReadBlock(&bootImage, srcLBAOffset * blockSize, sizeof(struct HSS_BootImage)); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "HSS_MMC_ReadBlock() failed\n"); } else { result = HSS_Boot_VerifyMagic(&bootImage); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "HSS_Boot_VerifyMagic() failed\n"); } else { int perf_ctr_index = PERF_CTR_UNINITIALIZED; HSS_PerfCtr_Allocate(&perf_ctr_index, "Boot Image MMC Copy"); result = copyBootImageToDDR_(&bootImage, (char *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR), srcLBAOffset * blockSize, HSS_MMC_ReadBlock); *ppBootImage = (struct HSS_BootImage *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR); HSS_PerfCtr_Lap(perf_ctr_index); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "copyBootImageToDDR_() failed\n"); } } } } #endif return result; } void HSS_BootSelectMMC(void) { #if IS_ENABLED(CONFIG_SERVICE_MMC) mHSS_DEBUG_PRINTF(LOG_NORMAL, "Selecting MMC as boot source ...\n"); pDefaultStorage = &mmcStorage_; #else (void)getBootImageFromMMC_; #endif } static bool getBootImageFromQSPI_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage) { bool result = false; #if IS_ENABLED(CONFIG_SERVICE_BOOT) && IS_ENABLED(CONFIG_SERVICE_QSPI) assert(ppBootImage); // need to do an initial copy of the boot header into our structure, for subsequent use mHSS_DEBUG_PRINTF(LOG_NORMAL, "Preparing to copy from QSPI to DDR ...\n"); size_t srcLBAOffset = 0u; assert(pStorage); uint32_t blockSize, eraseSize, blockCount; pStorage->getInfo(&blockSize, &eraseSize, &blockCount); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Attempting to read image header (%d bytes) ...\n", sizeof(struct HSS_BootImage)); result = HSS_QSPI_ReadBlock(&bootImage, srcLBAOffset * blockSize, sizeof(struct HSS_BootImage)); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "HSS_QSPI_ReadBlock() failed\n"); } else { result = HSS_Boot_VerifyMagic(&bootImage); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "HSS_Boot_VerifyMagic() failed\n"); } else { int perf_ctr_index = PERF_CTR_UNINITIALIZED; HSS_PerfCtr_Allocate(&perf_ctr_index, "Boot Image QSPI Copy"); result = copyBootImageToDDR_(&bootImage, (char *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR), srcLBAOffset * blockSize, HSS_QSPI_ReadBlock); *ppBootImage = (struct HSS_BootImage *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR); HSS_PerfCtr_Lap(perf_ctr_index); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "copyBootImageToDDR_() failed\n"); } } } #endif return result; } void HSS_BootSelectQSPI(void) { #if IS_ENABLED(CONFIG_SERVICE_QSPI) mHSS_DEBUG_PRINTF(LOG_NORMAL, "Selecting QSPI as boot source ...\n"); pDefaultStorage = &qspiStorage_; #else (void)getBootImageFromQSPI_; #endif } static bool getBootImageFromPayload_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage) { bool result = false; (void)pStorage; #if IS_ENABLED(CONFIG_SERVICE_BOOT) && IS_ENABLED(CONFIG_SERVICE_BOOT_USE_PAYLOAD) assert(ppBootImage); extern struct HSS_BootImage _payload_start; *ppBootImage = (struct HSS_BootImage *)&_payload_start; result = HSS_Boot_VerifyMagic(*ppBootImage); printBootImageDetails_(*ppBootImage); #endif return result; } void HSS_BootSelectPayload(void) { #if IS_ENABLED(CONFIG_SERVICE_USE_PAYLOAD) mHSS_DEBUG_PRINTF(LOG_NORMAL, "Selecting Payload as boot source ...\n"); pDefaultStorage = &payloadStorage_; #else (void)getBootImageFromPayload_; #endif } #if IS_ENABLED(CONFIG_SERVICE_BOOT) && IS_ENABLED(CONFIG_SERVICE_SPI) static bool spiFlashReadBlock_(void *dst, size_t offs, size_t count) { int retval = MSS_SYS_spi_copy((uintptr_t)dst, offs, count, /* options */ 3, /* mb_offset */ 0); if (retval) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Failed to read 0x%lx bytes from SPI flash @0x%lx (error code %d)!\n", count, offs, retval); } return (retval == 0); } #endif static bool getBootImageFromSpiFlash_(struct HSS_Storage *pStorage, struct HSS_BootImage **ppBootImage) { bool result = false; (void)pStorage; #if IS_ENABLED(CONFIG_SERVICE_BOOT) && IS_ENABLED(CONFIG_SERVICE_SPI) assert(ppBootImage); size_t srcOffset = CONFIG_SERVICE_BOOT_SPI_FLASH_OFFSET; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Preparing to copy from SPI Flash +0x%lx to DDR ...\n", srcOffset); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Attempting to read image header (%d bytes) ...\n", sizeof(struct HSS_BootImage)); MSS_SYS_select_service_mode(MSS_SYS_SERVICE_POLLING_MODE, NULL); result = spiFlashReadBlock_(&bootImage, srcOffset, sizeof(struct HSS_BootImage)); if (!result) { return false; } result = HSS_Boot_VerifyMagic(&bootImage); if (!result) { return false; } result = copyBootImageToDDR_(&bootImage, (char *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR), srcOffset, spiFlashReadBlock_); *ppBootImage = (struct HSS_BootImage *)(CONFIG_SERVICE_BOOT_DDR_TARGET_ADDR); #endif return result; } void HSS_BootSelectSPI(void) { #if IS_ENABLED(CONFIG_SERVICE_SPI) mHSS_DEBUG_PRINTF(LOG_NORMAL, "Selecting SPI Flash as boot source ...\n"); pDefaultStorage = &spiStorage_; #else (void)getBootImageFromSpiFlash_; #endif } bool HSS_Storage_Init(void); bool HSS_Storage_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount); bool HSS_Storage_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount); void HSS_Storage_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount); void HSS_Storage_FlushWriteBuffer(void); bool HSS_Storage_Init(void) { bool result = true; struct HSS_Storage *pStorage = pDefaultStorage ? pDefaultStorage : pStorages[0]; assert(pStorage); if (pStorage->init) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "initialize %s\n", pStorage->name); result = pStorage->init(); } return result; } bool HSS_Storage_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount) { bool result = true; struct HSS_Storage *pStorage = pDefaultStorage ? pDefaultStorage : pStorages[0]; assert(pStorage); if (pStorage->readBlock) { result = pStorage->readBlock(pDest, srcOffset, byteCount); } return result; } bool HSS_Storage_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount) { struct HSS_Storage *pStorage = pDefaultStorage ? pDefaultStorage : pStorages[0]; assert(pStorage); return pStorage->writeBlock(dstOffset, pSrc, byteCount); } void HSS_Storage_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount) { struct HSS_Storage *pStorage = pDefaultStorage ? pDefaultStorage : pStorages[0]; assert(pStorage); if (pStorage->getInfo) { pStorage->getInfo(pBlockSize, pEraseSize, pBlockCount); } mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s - %u byte pages, %u byte blocks, %u pages\n", pStorage->name, *pBlockSize, *pEraseSize, *pBlockCount); } void HSS_Storage_FlushWriteBuffer(void) { struct HSS_Storage *pStorage = pDefaultStorage ? pDefaultStorage : pStorages[0]; assert(pStorage); if (pStorage->flushWriteBuffer) { pStorage->flushWriteBuffer(); } } hart-software-services-2022.10/init/hss_ddr_init.c000066400000000000000000000175351432224323300220600ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS DDR Initalization * \brief DDR Initialization */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_perfctr.h" #include "hss_clock.h" #include "hss_progress.h" #include #include #if IS_ENABLED(CONFIG_PLATFORM_MPFS) # include "ddr/hw_ddr_segs.h" # include "nwc/mss_nwc_init.h" # include "mss_hal.h" # include "mss_l2_cache.h" #endif #include "hss_init.h" /*! * \brief DDR Training * * The E51 ensures that DDR is setup prior to code download, * and thus perform an DDR training and configuration required to achieve this. * * The intention is to allow as much flexibility as possible in DDR training, * so it is driven by MPFS HSS Embedded Software, with hardware hooks to * perform real-time critical functions. * * TBD: is periodic re-calibration required during operation (e.g. temperature induced * or other) */ #if IS_ENABLED(CONFIG_PLATFORM_MPFS) static const struct segment { char const * const description; uint64_t const baseAddr; } segment[8] = { { "Cached", 0x0080000000lu }, { "Cached", 0x1000000000lu }, { "Non-cached", 0x00c0000000lu }, { "Non-cached", 0x1400000000lu }, { "Non-cached WCB", 0x00d0000000lu }, { "Non-cached WCB", 0x1800000000lu }, { "Trace", 0x0000000000lu }, { "DDR blocker", 0x0000000000lu } }; static const uint32_t seg_regs[2][8] = { { LIBERO_SETTING_SEG0_0, LIBERO_SETTING_SEG0_1, LIBERO_SETTING_SEG0_2, LIBERO_SETTING_SEG0_3, LIBERO_SETTING_SEG0_4, LIBERO_SETTING_SEG0_5, LIBERO_SETTING_SEG0_6, LIBERO_SETTING_SEG0_7 }, { LIBERO_SETTING_SEG1_0, LIBERO_SETTING_SEG1_1, LIBERO_SETTING_SEG1_2, LIBERO_SETTING_SEG1_3, LIBERO_SETTING_SEG1_4, LIBERO_SETTING_SEG1_5, LIBERO_SETTING_SEG1_6, LIBERO_SETTING_SEG1_7 } }; #endif static uint64_t seg_regOffset_to_addrOffset_(uint32_t offset, const int segment_index); static uint64_t seg_regOffset_to_addrOffset_(uint32_t offset, const int segment_index) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) uint64_t result = 0u; if (offset & (1u << 14)) { offset = offset & 0x3FFFu; result = segment[segment_index].baseAddr - ((0x4000lu - offset) << 24); } else { result = segment[segment_index].baseAddr; } return result; #endif } bool HSS_DDRPrintSegConfig(void) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) mHSS_DEBUG_PRINTF(LOG_STATUS, "Segment Configuration:\n"); for (int i = 0; i < 2; i++) { for (int j = 0; j < 8; j++) { if (seg_regs[i][j] & 0xFFFFu) { mHSS_DEBUG_PRINTF_EX( "%14s: SEG%d_%d: offset 0x%010lx, physical DDR 0x%08lx\n", segment[j].description, i, j, segment[j].baseAddr, seg_regOffset_to_addrOffset_(seg_regs[i][j], j)); } } } #endif return true; } bool HSS_DDRPrintL2CacheWaysConfig(void) { mHSS_DEBUG_PRINTF(LOG_STATUS, "L2 Cache Configuration:\n"); const unsigned int way_enable = CACHE_CTRL->WAY_ENABLE + 1u; const unsigned int way_mask = (1u << way_enable) - 1u; const unsigned int cache_ways = __builtin_popcount(CACHE_CTRL->WAY_MASK_E51_DCACHE & way_mask); const unsigned int scratch_ways = way_enable - cache_ways; const unsigned int lim_ways = (unsigned int)(16u - way_enable); assert(way_enable <= 16u); assert(cache_ways <= 16u); mHSS_DEBUG_PRINTF_EX(" L2-Scratchpad: % 2u way%c (%u KiB)\n", scratch_ways, scratch_ways==1u ? ' ':'s', scratch_ways * 128u); mHSS_DEBUG_PRINTF_EX(" L2-Cache: % 2u way%c (%u KiB)\n", cache_ways, cache_ways==1u ? ' ':'s', cache_ways * 128u); mHSS_DEBUG_PRINTF_EX(" L2-LIM: % 2u way%c (%u KiB)\n", lim_ways, lim_ways==1 ? ' ':'s', lim_ways * 128); // sanity check on L2 Size and LIM size... // to ensure Libero and the HSS linker script match extern const uint64_t __l2_start; extern const uint64_t _hss_start; extern const uint64_t _hss_end; const uintptr_t libero_l2_end = (uintptr_t)&__l2_start + (scratch_ways * 128u * 1024u); assert(&_hss_start == &__l2_start); assert((uintptr_t)&_hss_end <= libero_l2_end); return true; } bool HSS_DDRPrintL2CacheWayMasks(void) { struct { char const * const name; uint64_t volatile const * const pWayMask; } wayMaskTable[] = { { .name = "DMA", .pWayMask = &(CACHE_CTRL->WAY_MASK_DMA) }, { .name = "AXI4_SLAVE_PORT_0", .pWayMask = &(CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_0) }, { .name = "AXI4_SLAVE_PORT_1", .pWayMask = &(CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_1) }, { .name = "AXI4_SLAVE_PORT_2", .pWayMask = &(CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_2) }, { .name = "AXI4_SLAVE_PORT_3", .pWayMask = &(CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_3) }, { .name = "E51_ICACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_E51_ICACHE) }, { .name = "U54_1_DCACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_1_DCACHE) }, { .name = "U54_1_ICACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_1_ICACHE) }, { .name = "U54_2_DCACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_2_DCACHE) }, { .name = "U54_2_ICACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_2_ICACHE) }, { .name = "U54_3_DCACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_3_DCACHE) }, { .name = "U54_3_ICACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_3_ICACHE) }, { .name = "U54_4_DCACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_4_DCACHE) }, { .name = "U54_4_ICACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_U54_4_ICACHE) }, { .name = "E51_DCACHE", .pWayMask = &(CACHE_CTRL->WAY_MASK_E51_DCACHE) } }; mHSS_DEBUG_PRINTF(LOG_STATUS, "L2 Cache Way Masks:\n"); for (int i = 0; i < ARRAY_SIZE(wayMaskTable); i++) { assert(wayMaskTable[i].name); assert(wayMaskTable[i].pWayMask); mHSS_DEBUG_PRINTF_EX("% 17s: 0x%x\n", wayMaskTable[i].name, *(wayMaskTable[i].pWayMask)); } return true; } /*! * \brief Hook for DDR Setup */ static size_t ddr_training_progress = 0; #define TYPICAL_DDR_TRAINING_ITERATIONS 5u bool HSS_DDRInit(void) { bool result = true; #if IS_ENABLED(CONFIG_PLATFORM_MPFS) if (!IS_ENABLED(CONFIG_SKIP_DDR)) { const char ddr_training_prefix[] = "DDR training ..."; sbi_printf("%s", ddr_training_prefix); sbi_printf("\n"); int perf_ctr_index = PERF_CTR_UNINITIALIZED; HSS_PerfCtr_Allocate(&perf_ctr_index, "DDR Init"); # define CURSOR_UP "\033[A" HSS_ShowProgress(TYPICAL_DDR_TRAINING_ITERATIONS, TYPICAL_DDR_TRAINING_ITERATIONS); uint8_t retval = mss_nwc_init_ddr(); HSS_ShowProgress(TYPICAL_DDR_TRAINING_ITERATIONS, 0u); if (retval != 0) { sbi_printf(CURSOR_UP "%s Failed\n", ddr_training_prefix); result = false; } else { HSS_PerfCtr_Lap(perf_ctr_index); sbi_printf(CURSOR_UP "%s Passed", ddr_training_prefix); #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) size_t ticks = HSS_PerfCtr_GetTime(perf_ctr_index); size_t millisecs = (ticks + (TICKS_PER_MILLISEC/2)) / TICKS_PER_MILLISEC; sbi_printf(" ( %lu ms)", millisecs); #endif sbi_printf("\n"); } HSS_PerfCtr_Lap(perf_ctr_index); # endif } return result; } void ddr_report_progress(void) // override weak symbol to report training progress... { HSS_ShowProgress(TYPICAL_DDR_TRAINING_ITERATIONS, (ddr_training_progress < TYPICAL_DDR_TRAINING_ITERATIONS) ? TYPICAL_DDR_TRAINING_ITERATIONS - ddr_training_progress : 1); ++ddr_training_progress; return; } hart-software-services-2022.10/init/hss_ihc_init.c000066400000000000000000000065421432224323300220460ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Debug UART Initalization * \brief Debug UART Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "csr_helper.h" #include #include "hss_debug.h" #include "hss_types.h" #include "ssmb_ipi.h" #include "mss_plic.h" #include "miv_ihc.h" #if IS_ENABLED(CONFIG_HSS_USE_IHC) static uint32_t hss_ihc_incoming_(uint32_t remote_hartid, uint32_t *p_message_in, uint32_t message_size, bool is_ack_required, uint32_t *p_message_storage) { return 0u; } static uint32_t u54_ihc_incoming_(uint32_t remote_hartid, uint32_t *p_message_in, uint32_t message_size, bool is_ack_required, uint32_t *p_message_storage) { (void)remote_hartid; (void)message_size; (void)is_ack_required; (void)p_message_storage; assert(p_message_in); bool HSS_U54_ConsumeIntent(enum IPIMessagesEnum msg_type); HSS_U54_ConsumeIntent((enum IPIMessagesEnum)p_message_in[0]); return 0u; } #endif bool HSS_IHCInit(void) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initializing Mi-V IHC\n"); IHC_global_init(); const uint32_t local_hartid = (uint32_t)HSS_HART_E51; IHC_local_context_init(local_hartid); #if IS_ENABLED(CONFIG_HSS_USE_IHC) const bool e51_mp_enable = false; const bool u54_mp_enable = true; const bool ack_disable = false; #endif for (uint32_t remote_hartid = (uint32_t)HSS_HART_U54_1; remote_hartid <= (uint32_t)HSS_HART_U54_4; remote_hartid++) { IHC_local_context_init(remote_hartid); #if IS_ENABLED(CONFIG_HSS_USE_IHC) IHC_local_remote_config(local_hartid, remote_hartid, hss_ihc_incoming_, e51_mp_enable, ack_disable); IHC_local_remote_config(remote_hartid, local_hartid, u54_ihc_incoming_, u54_mp_enable, ack_disable); #endif } return true; } void HSS_IHCInit_U54(void) { #if IS_ENABLED(CONFIG_HSS_USE_IHC) const enum HSSHartId local_hartid = current_hartid(); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initializing PLIC (Mi-V IHC) for u54_%d\n", local_hartid); // enable PLIC interrupt for IHC // the E51 will be calling PLIC_init_on_reset(), so we'll delay here to allow that to complete... // 50mS is sufficient, and won't impact overall boot time as U54s are waiting for E51 anyway... HSS_SpinDelay_MilliSecs(50u); PLIC_init(); __extension__ const PLIC_IRQn_Type ihcia_hart_to_int_table[] = { [ HSS_HART_E51] = 0, [ HSS_HART_U54_1] = IHCIA_hart1_INT, [ HSS_HART_U54_2] = IHCIA_hart2_INT, [ HSS_HART_U54_3] = IHCIA_hart3_INT, [ HSS_HART_U54_4] = IHCIA_hart4_INT, }; switch(local_hartid) { case HSS_HART_U54_1: __attribute__((fallthrough)); /* deliberately fallthrough */ case HSS_HART_U54_2: __attribute__((fallthrough)); /* deliberately fallthrough */ case HSS_HART_U54_3: __attribute__((fallthrough)); /* deliberately fallthrough */ case HSS_HART_U54_4: PLIC_SetPriority(ihcia_hart_to_int_table[local_hartid], 7); PLIC_EnableIRQ(ihcia_hart_to_int_table[local_hartid]); break; case HSS_HART_E51: __attribute__((fallthrough)); /* deliberately fallthrough */ default: break; } #endif } hart-software-services-2022.10/init/hss_logo_init.c000066400000000000000000000174371432224323300222500ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Software Initalization * \brief Full System Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "hss_debug.h" // // A variety of colored pixels are needed - red, white, black // define these as ASCII characters if color output is not enabled // #if IS_ENABLED(CONFIG_COLOR_OUTPUT) # if IS_ENABLED(CONFIG_LOGO_INVERT_COLORS) const char B0_str[] ="\033[48;5;188m "; const char W0_str[] ="\033[0m "; const char r1_str[] ="\033[48;5;217m "; const char r2_str[] ="\033[48;5;210m "; const char r3_str[] ="\033[48;5;203m "; const char r4_str[] ="\033[48;5;196m "; const char b1_str[] ="\033[48;5;188m "; const char b2_str[] ="\033[48;5;145m "; const char b3_str[] ="\033[48;5;102m "; const char b4_str[] ="\033[48;5;59m "; # else const char B0_str[] = "\033[48;5;188m "; const char W0_str[] = "\033[48;5;188m "; const char r1_str[] ="\033[48;5;217m "; const char r2_str[] ="\033[48;5;210m "; const char r3_str[] ="\033[48;5;203m "; const char r4_str[] ="\033[48;5;196m "; const char b1_str[] ="\033[48;5;16m "; const char b2_str[] ="\033[48;5;59m "; const char b3_str[] ="\033[48;5;102m "; const char b4_str[] ="\033[48;5;145m "; # endif const char RST_str[] ="\033[0m"; #else const char B0_str[] =" "; const char W0_str[] =" "; const char r1_str[] ="."; const char r2_str[] ="-"; const char r3_str[] ="x"; const char r4_str[] ="X"; const char b1_str[] =":"; const char b2_str[] ="o"; const char b3_str[] ="0"; const char b4_str[] ="O"; const char RST_str[] =""; #endif enum Color { B0 = 0, W0, r1, r2, r3, r4, b1, b2, b3, b4, RST, CRLF_token, }; const char* tokenStringTable[] = { B0_str, W0_str, r1_str, r2_str, r3_str, r4_str, b1_str, b2_str, b3_str, b4_str, RST_str, "\n", }; // RLE Microchip Logo, built up from our color pixel primitives above... // RLE shrinks the size of this const struct __attribute__((packed)) { uint8_t const count; enum Color const tokenIndex; } rleLogoElements[] = { { 4, W0 }, { 1, r1 }, { 1, r3 }, { 7, r4 }, { 62, W0 }, { 1, RST }, { 1, CRLF_token }, { 3, W0 }, { 1, r2 }, { 9, r4 }, { 1, r3 }, { 61, W0 }, { 1, RST }, { 1, CRLF_token }, { 2, W0 }, { 1, r3 }, { 2, r4 }, { 1, r3 }, { 1, r2 }, { 5, r4 }, { 1, r2 }, { 1, r4 }, { 1, r1 }, { 7, W0 }, { 1, b3 }, { 5, W0 }, { 1, b3 }, { 46, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, { 1, r1 }, { 3, r4 }, { 2, B0 }, { 1, r2 }, { 3, r4 }, { 1, r1 }, { 1, B0 }, { 1, r1 }, { 1, r4 }, { 6, W0 }, { 1, b4 }, { 1, b1 }, { 1, b2 }, { 3, W0 }, { 1, b3 }, { 1, b1 }, { 1, b4 }, { 45, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, { 3, r4 }, { 1, r1 }, { 3, B0 }, { 2, r4 }, { 1, r2 }, { 3, B0 }, { 2, r3 }, { 5, W0 }, { 1, b4 }, { 2, b1 }, { 3, W0 }, { 2, b1 }, { 1, b4 }, { 1, W0 }, { 1, b4 }, { 2, W0 }, { 1, b4 }, { 3, b3 }, { 1, b4 }, { 1, W0 }, { 5, b4 }, { 2, W0 }, { 1, b4 }, { 3, b3 }, { 1, b4 }, { 2, W0 }, { 1, b4 }, { 3, b3 }, { 1, b4 }, { 1, W0 }, { 1, b4 }, { 3, W0 }, { 1, b4 }, { 2, W0 }, { 1, b4 }, { 1, W0 }, { 5, b4 }, { 1, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, r1 }, { 3, r4 }, { 4, B0 }, { 1, r1 }, { 1, r4 }, { 5, B0 }, { 1, r4 }, { 1, r1 }, { 4, W0 }, { 1, b3 }, { 2, b1 }, { 1, b4 }, { 1, W0 }, { 1, b4 }, { 2, b1 }, { 1, b3 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 1, W0 }, { 5, b1 }, { 1, W0 }, { 5, b1 }, { 1, b3 }, { 1, W0 }, { 5, b1 }, { 1, b4 }, { 1, W0 }, { 5, b1 }, { 1, W0 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 5, b1 }, { 1, b3 }, { 1, RST }, { 1, CRLF_token }, { 1, r2 }, { 2, r4 }, { 1, r3 }, { 1, r2 }, { 4, B0 }, { 1, r3 }, { 1, r2 }, { 4, B0 }, { 1, r2 }, { 1, r4 }, { 4, W0 }, { 1, b3 }, { 3, b2 }, { 1, W0 }, { 2, b2 }, { 1, b3 }, { 1, b2 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b1 }, { 5, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 1, b2 }, { 1, b4 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, b4 }, { 1, b1 }, { 5, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 1, b2 }, { 1, RST }, { 1, CRLF_token }, { 1, r3 }, { 1, r4 }, { 1, r1 }, { 1, B0 }, { 1, r4 }, { 5, B0 }, { 1, r4 }, { 5, B0 }, { 1, r4 }, { 1, r2 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 1, b1 }, { 1, b4 }, { 1, b3 }, { 1, b2 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b2 }, { 5, W0 }, { 1, b1 }, { 1, b3 }, { 2, W0 }, { 2, b3 }, { 1, b4 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, b4 }, { 1, b2 }, { 5, W0 }, { 5, b1 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 1, b2 }, { 1, RST }, { 1, CRLF_token }, { 1, r3 }, { 1, r2 }, { 2, B0 }, { 1, r2 }, { 1, r3 }, { 4, B0 }, { 1, r1 }, { 1, r3 }, { 4, B0 }, { 1, r1 }, { 1, r4 }, { 3, W0 }, { 1, b1 }, { 1, b3 }, { 1, W0 }, { 3, b1 }, { 1, W0 }, { 1, b4 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b2 }, { 5, W0 }, { 5, b1 }, { 1, W0 }, { 1, b4 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b3 }, { 1, b4 }, { 1, b2 }, { 5, W0 }, { 1, b1 }, { 1, b3 }, { 2, b4 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 5, b1 }, { 1, b3 }, { 1, RST }, { 1, CRLF_token }, { 1, r1 }, { 4, B0 }, { 1, r4 }, { 1, r1 }, { 4, B0 }, { 1, r3 }, { 1, r2 }, { 4, B0 }, { 1, r3 }, { 3, W0 }, { 1, b1 }, { 1, b4 }, { 1, W0 }, { 1, b3 }, { 1, b1 }, { 1, b3 }, { 1, W0 }, { 1, b4 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 2, b4 }, { 1, b1 }, { 4, b4 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 2, W0 }, { 1, b2 }, { 1, b3 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 2, b4 }, { 1, b1 }, { 1, b3 }, { 1, b4 }, { 1, b1 }, { 4, b4 }, { 1, W0 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b3 }, { 2, b4 }, { 2, W0 }, { 1, RST }, { 1, CRLF_token }, { 5, B0 }, { 1, r3 }, { 1, r4 }, { 4, B0 }, { 1, r1 }, { 1, r4 }, { 5, B0 }, { 3, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 1, b3 }, { 3, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 1, W0 }, { 5, b1 }, { 1, W0 }, { 1, b1 }, { 1, b4 }, { 2, W0 }, { 2, b3 }, { 1, W0 }, { 1, b2 }, { 4, b1 }, { 2, W0 }, { 5, b1 }, { 1, W0 }, { 1, b1 }, { 3, W0 }, { 1, b2 }, { 1, b4 }, { 1, W0 }, { 1, b1 }, { 1, W0 }, { 1, b1 }, { 5, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, { 3, B0 }, { 1, r2 }, { 2, r4 }, { 1, r2 }, { 3, B0 }, { 1, r3 }, { 1, r4 }, { 1, r3 }, {2, B0 }, {1, B0}, { 58, W0 }, { 1, RST }, { 1, CRLF_token }, { 1, W0 }, {1, r1}, { 2, B0 }, { 4, r4 }, { 2, B0 }, { 1, r1 }, { 3, r4 }, { 1, r1 }, {1, B0 }, {1, r1}, { 58, W0 }, { 1, RST }, { 1, CRLF_token }, { 2, W0 }, {1, r2}, { 5, r4 }, { 1, r3 }, { 1, r1 }, { 5, r4 }, {1, r3}, { 59, W0 }, { 1, RST }, { 1, CRLF_token }, { 3, W0 }, { 1, r2 }, { 11, r4 }, { 60, W0 }, { 1, RST }, { 1, CRLF_token }, { 4, W0 }, { 1, r1 }, { 1, r3 }, { 7, r4 }, { 1, r3 }, { 61, W0 }, { 1, RST }, {1, CRLF_token} }; bool HSS_LogoInit(void) { mHSS_PUTS("\n"); int i; // decode and output our RLE Logo for (i = 0; i < ARRAY_SIZE(rleLogoElements); i++) { uint8_t j; for (j = 0u; j < rleLogoElements[i].count; j++) { mHSS_PUTS(tokenStringTable[rleLogoElements[i].tokenIndex]); } } return true; } hart-software-services-2022.10/init/hss_opensbi_init.c000066400000000000000000000011521432224323300227320ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS OpenSBI Initalization * \brief OpenSBI Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include #include #include "csr_helper.h" #include "hss_state_machine.h" #include "opensbi_service.h" #include "hss_debug.h" bool HSS_OpenSBIInit(void) { bool result = true; HSS_OpenSBI_Setup(); return result; } hart-software-services-2022.10/init/hss_pcie_init.c000066400000000000000000000071511432224323300222200ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS PCIe Initalization * \brief PCIe Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "hss_debug.h" #include #include "csr_helper.h" #include "mss_plic.h" #include "mpfs_reg_map.h" // Register Defintions #define PCIE_IRQn (PLIC_F2M_1_INT_OFFSET) // // Will constrain base addr of PCIe to 0x43000000u // and constrain to use Bridge and Ctrl [1] #define PCIE_BASE_ADDR (uintptr_t)0x43000000u #define PCIE1_BRIDGE_BASE_ADDR (PCIE_BASE_ADDR + 0x00008000u) #define PCIE1_BRIDGE_IMASK_LOCAL_OFFSET 0x180u #define PCIE1_BRIDGE_ISTATUS_LOCAL_OFFSET 0x184u #define PCIE1_BRIDGE_IMASK_HOST_OFFSET 0x188u #define PCIE1_BRIDGE_ISTATUS_HOST_OFFSET 0x18Cu #define PCIE1_CTRL_BASE_ADDR (PCIE_BASE_ADDR + 0x0000A000u) #define PCIE1_CTRL_SEC_ERROR_INT_OFFSET 0x28u #define PCIE1_CTRL_SEC_ERROR_INT_MASK_OFFSET 0x2Cu #define PCIE1_CTRL_DED_ERROR_INT_OFFSET 0x30u #define PCIE1_CTRL_DED_ERROR_INT_MASK_OFFSET 0x34u #define PCIE1_CTRL_PCIE_EVENT_INT_OFFSET 0x14c #define MAX_RETRY_COUNT 255u bool HSS_PCIeInit(void) { // Set a priority for pcie hwirq // Set a context threshold for hart 0 // enable PCIe interrupt PLIC_SetPriority(PCIE_IRQn, 1u); PLIC_SetPriority_Threshold(1u); PLIC_EnableIRQ(PCIE_IRQn); // check if an interrupt is pending // if so, attempt to clear (with timeout) uint32_t claim = PLIC_ClaimIRQ(); uint32_t retryCount = 0u; while (claim != 0u) { uint32_t status; // turn off SEC - on ctrl1 // clear out stragglers mHSS_WriteRegU32(PCIE1_CTRL, SEC_ERROR_INT_MASK, 0xFFFFu); status = mHSS_ReadRegU32(PCIE1_CTRL, SEC_ERROR_INT); if (status) { mHSS_WriteRegU32(PCIE1_CTRL, SEC_ERROR_INT, status); } // turn off DED - on ctrl1 mHSS_WriteRegU32(PCIE1_CTRL, DED_ERROR_INT_MASK, 0xFFFFu); status = mHSS_ReadRegU32(PCIE1_CTRL, DED_ERROR_INT); if (status) { mHSS_WriteRegU32(PCIE1_CTRL, DED_ERROR_INT, status); } // turn of PCIe EVENTs - on ctrl1 // Clear outstanding and disable future PCIE_EVENT_INTS status = mHSS_ReadRegU32(PCIE1_CTRL, PCIE_EVENT_INT); if (status & 0x7) { mHSS_WriteRegU32(PCIE1_CTRL, PCIE_EVENT_INT, 0x0070007u); } // turn off LOCAL interrupts - on bridge1 mHSS_WriteRegU32(PCIE1_BRIDGE, IMASK_LOCAL, 0u); status = mHSS_ReadRegU32(PCIE1_BRIDGE, ISTATUS_LOCAL); if (status) { mHSS_WriteRegU32(PCIE1_BRIDGE, ISTATUS_LOCAL, status); } // turn off HOST interrupts - on bridge1 mHSS_WriteRegU32(PCIE1_BRIDGE, IMASK_HOST, 0u); status = mHSS_ReadRegU32(PCIE1_BRIDGE, ISTATUS_HOST); if (status) { mHSS_WriteRegU32(PCIE1_BRIDGE, ISTATUS_HOST, status); } PLIC_CompleteIRQ(claim); if (retryCount < MAX_RETRY_COUNT) { retryCount++; } else { // don't hang around forever - if an interrupt is stubborn - signal failure break; } // check that no further interrupts pending claim = PLIC_ClaimIRQ(); } // disable pcie hwirq // Set a context threshold for hart 0 back to 0 // Set priority for pcie hwirq back to 0 PLIC_DisableIRQ(PCIE_IRQn); PLIC_SetPriority_Threshold(0u); PLIC_SetPriority(PCIE_IRQn, 0u); return (claim == 0u); } hart-software-services-2022.10/init/hss_pdma_init.c000066400000000000000000000011541432224323300222160ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS PDMA Initalization * \brief PDMA Initialization */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include #include "hss_debug.h" #if IS_ENABLED(CONFIG_USE_PDMA) # include "drivers/mss/mss_pdma/mss_pdma.h" #endif bool HSS_PDMAInit(void) { #if IS_ENABLED(CONFIG_USE_PDMA) // initialise PDMA MSS_PDMA_init(); #endif return true; } hart-software-services-2022.10/init/hss_sys_setup.c000066400000000000000000000125661432224323300223210ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file System Setup Functions * \brief Functions for setting up the PMP, MPU, PLIC, IOMUX, PAD I/O, L2 Cache. Clocks * * These functions are used by the boot service, but they can be replaced by * auto-generated code from an external tool, e.g. Libero. * * What needs to be implemented are the following functions: * bool HSS_Setup_PLIC(void); * bool HSS_Setup_MPU(void); * bool HSS_Setup_L2Cache(void); * bool HSS_Setup_Clocks(void); * bool HSS_Setup_PMP(void); */ #include "config.h" #include "hss_types.h" #include "hss_init.h" #include "hss_debug.h" #include #include #include "hss_clock.h" #include "hss_state_machine.h" #include "csr_helper.h" #if IS_ENABLED(CONFIG_PLATFORM_MPFS) # define RISCV_CSR_ENCODING_H # define RISCV_ENCODING_H # include "mss_sysreg.h" # include "mss_plic.h" # include "mss_util.h" # include "mss_mpu.h" # include "mss_l2_cache.h" # include "nwc/mss_io_config.h" # include "system_startup.h" #endif #include "hss_memcpy_via_pdma.h" #include "mpfs_reg_map.h" #include "hss_sys_setup.h" /******************************************************************************/ /****************************************************************************/ // // Setup Functions // /*! * \brief PLIC Setup and Configuration * * The RISC-V Platform-Level Interrupt Controller (PLIC) allows * broadcasting of interrupts to one or more Harts within a Core Complex. * * The operation of the PLIC is suited to SMP operation: An interrupt * source occurs to PLIC and then any available processor can conceivable * claim it unless its configuration is locked down. * * This obviously doesn't work well if the processors are in AMP * configuration and we are trying to * maintain hardware separation. * Therefore, PolarFire SoC can secure PLIC configuration through the * use of RISC-V PMP registers. * * Furthermore, MPRs allow assignment of each of 160 interrupts going to * the PLIC to one of two hardware contexts. This assignment can be * configured by E51 at boot time and is then locked until subsequent * reset. */ bool HSS_Setup_PLIC(void) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) __disable_all_irqs(); PLIC_init_on_reset(); #endif return true; } /*! * \brief MPU Setup and Configuration * * The E51 ensures that hardware separate is ensured before the U54 code starts running. * To do this, it needs to partition memory and peripheral access, based on configuration * information provided at build time. * * The MSS MPUs are memory mapped and can be setup once by the E51. They are then locked * until subsequent system reboot. The MPRs allow assignment of peripheral resources to * one of two separate hardware contexts. */ bool HSS_Setup_MPU(void) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) mpu_configure(); #endif return true; } /*! * \brief L2Cache and Scratchpad Setup * * The E51 is responsible for configuring the cache controller, including locking of ways and * configuring between L2 Cache and Scratchpad for real-time AMP needs, based on configuration * information provided as a Libero output. */ bool HSS_Setup_L2Cache(void) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) config_l2_cache(); #endif return true; } /*! * \brief Clock Configuration * * Setup clock enables and soft resets * */ bool HSS_Setup_Clocks(void) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) static const uint32_t hss_subblk_clock_Config = 0xFFFFFFFFu; const uint32_t hss_soft_reset_Config = SYSREG->SOFT_RESET_CR & ~( SOFT_RESET_CR_SGMII_MASK | SOFT_RESET_CR_CFM_MASK | SOFT_RESET_CR_ATHENA_MASK | SOFT_RESET_CR_FIC3_MASK | SOFT_RESET_CR_FIC2_MASK | SOFT_RESET_CR_FIC1_MASK | SOFT_RESET_CR_FIC0_MASK | SOFT_RESET_CR_DDRC_MASK | SOFT_RESET_CR_GPIO2_MASK | SOFT_RESET_CR_GPIO1_MASK | SOFT_RESET_CR_GPIO0_MASK | SOFT_RESET_CR_QSPI_MASK | SOFT_RESET_CR_RTC_MASK | SOFT_RESET_CR_FPGA_MASK | SOFT_RESET_CR_USB_MASK | SOFT_RESET_CR_CAN1_MASK | SOFT_RESET_CR_CAN0_MASK | SOFT_RESET_CR_I2C1_MASK | SOFT_RESET_CR_I2C0_MASK | SOFT_RESET_CR_SPI1_MASK | SOFT_RESET_CR_SPI0_MASK | SOFT_RESET_CR_MMUART4_MASK | SOFT_RESET_CR_MMUART3_MASK | SOFT_RESET_CR_MMUART2_MASK | SOFT_RESET_CR_MMUART1_MASK | SOFT_RESET_CR_MMUART0_MASK | SOFT_RESET_CR_TIMER_MASK | SOFT_RESET_CR_MMC_MASK | SOFT_RESET_CR_MAC1_MASK | SOFT_RESET_CR_MAC0_MASK | SOFT_RESET_CR_ENVM_MASK); SYSREG->SOFT_RESET_CR = 0x3FFFFFFEu; // everything but ENVM SYSREG->SOFT_RESET_CR = hss_soft_reset_Config; SYSREG->SUBBLK_CLOCK_CR = hss_subblk_clock_Config; SYSREG->FABRIC_RESET_CR = FABRIC_RESET_CR_ENABLE_MASK; #endif return true; } /*! * \brief Bus Error Unit * * Setup bus error unit */ bool HSS_Setup_BusErrorUnit(void) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) (void)init_bus_error_unit(); #endif return true; } hart-software-services-2022.10/init/hss_usb_init.c000066400000000000000000000026251432224323300220720ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS USB Initalization * \brief USB Initialization */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include #include #undef ROUNDUP #undef ROUNDDOWN #include "mss_hal.h" #include "mss_assert.h" #include "flash_drive_app.h" #include "mss_plic.h" #include "uart_helper.h" #include "usbdmsc_service.h" #include "hss_init.h" #include "mpfs_reg_map.h" #include "mss_usb_core_regs.h" #define MSS_USB_BASE_ADDR (uintptr_t)(USB_BASE) #define MSS_USB_ADDR_UPPER_OFFSET 0x3FCu bool HSS_USBInit(void) { // To allow the USB DMA engine to support the MSS 38-bit address bus, an additional // configuration register is provided using one of the spare USB configuration addresses // (0x3FC). Logic is added in wrapper layer around the USB core detects a write or read to this // address, masks the select to the core, and sets a local register for the upper address lines // Address Register Bits Function // 0x202013fc ADDR_UPPER 5:0 Set the upper 6-bits of the Address bus for DMA // operations. SYSREG->SOFT_RESET_CR &= ~ (1u << 16u); mHSS_WriteRegU32(MSS_USB, ADDR_UPPER, 0x10u); return true; } hart-software-services-2022.10/modules/000077500000000000000000000000001432224323300177355ustar00rootroot00000000000000hart-software-services-2022.10/modules/Kconfig000066400000000000000000000002021432224323300212320ustar00rootroot00000000000000source "modules/compression/Kconfig" source "modules/crypto/Kconfig" source "modules/debug/Kconfig" source "modules/ssmb/Kconfig" hart-software-services-2022.10/modules/Makefile000066400000000000000000000025001432224323300213720ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Modules include modules/compression/Makefile include modules/crypto/Makefile include modules/debug/Makefile include modules/misc/Makefile include modules/ssmb/Makefile hart-software-services-2022.10/modules/compression/000077500000000000000000000000001432224323300222765ustar00rootroot00000000000000hart-software-services-2022.10/modules/compression/Kconfig000066400000000000000000000007011432224323300235770ustar00rootroot00000000000000menu "Compression" config COMPRESSION bool "Compression support" depends on SERVICE_BOOT default y help This feature enables support for compression of boot images If you don't know what to do here, say Y. config COMPRESSION_MINIZ bool "miniz (DEFLATE)" depends on COMPRESSION default y help This feature enables support for miniz compression, a fast lossless compression library implementing DEFLATE. endmenu hart-software-services-2022.10/modules/compression/LICENSE000066400000000000000000000022211432224323300233000ustar00rootroot00000000000000miniz Copyright 2013-2014 RAD Game Tools and Valve Software Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hart-software-services-2022.10/modules/compression/Makefile000066400000000000000000000027111432224323300237370ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Compression Utilities SRCS-$(CONFIG_COMPRESSION) += \ modules/compression/hss_decompress.c \ SRCS-$(CONFIG_COMPRESSION_MINIZ) += \ thirdparty/miniz/miniz.c \ INCLUDES +=\ -I./modules/compression \ -I./thirdparty/miniz \ thirdparty/miniz/miniz.o: CFLAGS+=-DMINIZ_NO_STDIO -DMINIZ_NO_TIME hart-software-services-2022.10/modules/compression/hss_decompress.c000066400000000000000000000063301432224323300254650ustar00rootroot00000000000000/****************************************************************************************** * * MPFS HSS Embedded Software * * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /*\! *\file Decompression Wrapper *\brief Decompression Wrapper */ #include "config.h" #include "hss_types.h" #include "miniz.h" #include "hss_crc32.h" #include "hss_debug.h" #include "hss_decompress.h" #include "hss_progress.h" #include int HSS_Decompress(const void* pInputBuffer, void* pOutputBuffer) { int result = 0; struct HSS_CompressedImage compressedImageHdr = *(struct HSS_CompressedImage *)pInputBuffer; if (compressedImageHdr.magic != mHSS_COMPRESSED_MAGIC) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Compressed Image is missing magic value (%08x vs %08x)\n", compressedImageHdr.magic, mHSS_COMPRESSED_MAGIC); } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Compressed Image Length is %lu\n", compressedImageHdr.compressedImageLen); uint32_t originalCrc = compressedImageHdr.headerCrc; compressedImageHdr.headerCrc = 0; uint32_t compressedCrc = CRC32_calculate((const uint8_t *)&compressedImageHdr, sizeof(struct HSS_CompressedImage)); if (originalCrc != compressedCrc) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Compressed Image failed CRC check\n"); } else { const uint8_t *pByteOffset = pInputBuffer; pByteOffset += sizeof(struct HSS_CompressedImage); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Decompressing from %p to %p\n", pByteOffset, pOutputBuffer); size_t decompressedOutputSize = (size_t)compressedImageHdr.originalImageLen; result = mz_uncompress( (void *)pOutputBuffer, &decompressedOutputSize, (const void *)pByteOffset, (int)compressedImageHdr.compressedImageLen); } } return result; } #include void *malloc(size_t size) { mHSS_DEBUG_PRINTF(LOG_ERROR, "malloc() stub invoked...\n"); (void)size; return NULL; } void free(void *ptr) { mHSS_DEBUG_PRINTF(LOG_ERROR, "free() stub invoked...\n"); (void)ptr; } hart-software-services-2022.10/modules/compression/hss_decompress.h000066400000000000000000000027561432224323300255020ustar00rootroot00000000000000#ifndef HSS_COMPRESS_H #define HSS_COMPRESS_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Decompression * */ #if defined (__cplusplus) extern "C" { #endif int HSS_Decompress(const void* pInputBuffer, void* pOutputBuffer); #if defined (__cplusplus) } #endif #endif hart-software-services-2022.10/modules/crypto/000077500000000000000000000000001432224323300212555ustar00rootroot00000000000000hart-software-services-2022.10/modules/crypto/Kconfig000066400000000000000000000017561432224323300225710ustar00rootroot00000000000000menu "Crypto" config CRYPTO_SIGNING bool "Cryptographic Signing support" depends on SERVICE_BOOT default y help This feature enables support for signing of boot images If you don't know what to do here, say Y. menu "Signing Configuration" visible if CRYPTO_SIGNING config CRYPTO_SIGNING_KEY_PUBLIC depends on CRYPTO_SIGNING string "Enter path to X.509 DER Public Key" help This option specifies the ECC SECP384R1 public key (DER binary format) to use. choice prompt "Crypto Library" default CRYPTO_LIBECC config CRYPTO_LIBECC bool "libecc (SHA2 and ECDSA P-384)" depends on CRYPTO_SIGNING help This feature enables support for the libecc library for SHA2 hashing and ECDSA P-384 code signing. config CRYPTO_USER_CRYPTO bool "User Crypto (SHA2 and ECDSA P-384)" depends on CRYPTO_SIGNING help This feature enables support for the UserCrypto core for SHA384 hashing and ECDSA P-384 code signing. endchoice endmenu endmenu hart-software-services-2022.10/modules/crypto/LICENSE000066400000000000000000000067551432224323300222770ustar00rootroot00000000000000libTomCrypt license ==================== The LibTom license This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to libecc License =============== The files in this project are provided under a dual BSD/GPLv2 license. When using or redistributing this software, you may do so under either license. GPLv2 License summary --------------------- Copyright (C) 2017 All rights reserved. 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BSD License ----------- Copyright (C) 2017 All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. hart-software-services-2022.10/modules/crypto/Makefile000066400000000000000000000232341432224323300227210ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Compression Utilities INCLUDES +=\ -I./modules/crypto \ # # Boot Image Signing # ifdef CONFIG_CRYPTO_SIGNING x509-ec-sepc384r1-public.h: $(subst $\",,$(CONFIG_CRYPTO_SIGNING_KEY_PUBLIC)) tools/secure-boot/der_to_c_header.py $< x509-ec-secp384r1-public.h # # libecc # ifdef CONFIG_CRYPTO_LIBECC SRCS-$(CONFIG_CRYPTO_LIBECC) += \ modules/crypto/hss_crypto_libecc.c \ modules/crypto/random.c \ thirdparty/libecc/src/curves/aff_pt.c \ thirdparty/libecc/src/curves/aff_pt_edwards.c \ thirdparty/libecc/src/curves/aff_pt_montgomery.c \ thirdparty/libecc/src/curves/curves.c \ thirdparty/libecc/src/curves/ec_edwards.c \ thirdparty/libecc/src/curves/ec_montgomery.c \ thirdparty/libecc/src/curves/ec_params.c \ thirdparty/libecc/src/curves/ec_shortw.c \ thirdparty/libecc/src/curves/prj_pt.c \ thirdparty/libecc/src/curves/prj_pt_monty.c \ thirdparty/libecc/src/fp/fp_add.c \ thirdparty/libecc/src/fp/fp.c \ thirdparty/libecc/src/fp/fp_montgomery.c \ thirdparty/libecc/src/fp/fp_mul.c \ thirdparty/libecc/src/fp/fp_mul_redc1.c \ thirdparty/libecc/src/fp/fp_pow.c \ thirdparty/libecc/src/fp/fp_rand.c \ thirdparty/libecc/src/fp/fp_sqrt.c \ thirdparty/libecc/src/hash/hash_algs.c \ thirdparty/libecc/src/hash/hmac.c \ thirdparty/libecc/src/hash/sha224.c \ thirdparty/libecc/src/hash/sha256.c \ thirdparty/libecc/src/hash/sha3-224.c \ thirdparty/libecc/src/hash/sha3-256.c \ thirdparty/libecc/src/hash/sha3-384.c \ thirdparty/libecc/src/hash/sha3-512.c \ thirdparty/libecc/src/hash/sha384.c \ thirdparty/libecc/src/hash/sha3.c \ thirdparty/libecc/src/hash/sha512-224.c \ thirdparty/libecc/src/hash/sha512-256.c \ thirdparty/libecc/src/hash/sha512_core.c \ thirdparty/libecc/src/hash/sha512.c \ thirdparty/libecc/src/hash/shake256.c \ thirdparty/libecc/src/hash/shake.c \ thirdparty/libecc/src/hash/sm3.c \ thirdparty/libecc/src/hash/streebog.c \ thirdparty/libecc/src/nn/nn_add.c \ thirdparty/libecc/src/nn/nn.c \ thirdparty/libecc/src/nn/nn_div.c \ thirdparty/libecc/src/nn/nn_logical.c \ thirdparty/libecc/src/nn/nn_modinv.c \ thirdparty/libecc/src/nn/nn_mul.c \ thirdparty/libecc/src/nn/nn_mul_redc1.c \ thirdparty/libecc/src/nn/nn_rand.c \ thirdparty/libecc/src/sig/decdsa.c \ thirdparty/libecc/src/sig/ecdsa_common.c \ thirdparty/libecc/src/sig/ecdsa.c \ thirdparty/libecc/src/sig/ecfsdsa.c \ thirdparty/libecc/src/sig/ecgdsa.c \ thirdparty/libecc/src/sig/eckcdsa.c \ thirdparty/libecc/src/sig/ec_key.c \ thirdparty/libecc/src/sig/ecosdsa.c \ thirdparty/libecc/src/sig/ecrdsa.c \ thirdparty/libecc/src/sig/ecsdsa_common.c \ thirdparty/libecc/src/sig/ecsdsa.c \ thirdparty/libecc/src/sig/eddsa.c \ thirdparty/libecc/src/sig/sig_algs.c \ thirdparty/libecc/src/sig/sm2.c \ thirdparty/libecc/src/utils/utils.c \ INCLUDES +=\ -I./thirdparty/libecc/src/ \ LIBECC_OVERRIDE_FLAGS=-DWITH_LIBECC_CONFIG_OVERRIDE -DWITH_CURVE_SECP384R1 -DWITH_HASH_SHA384 -DWITH_HASH_SHA512 -DWITH_HASH_SHA512_256 -DWITH_SIG_ECDSA -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA) -ffunction-sections -fdata-sections modules/crypto/hss_crypto_libecc.o: x509-ec-sepc384r1-public.h modules/crypto/hss_crypto_libecc.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/external_deps/rand.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/aff_pt.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/aff_pt_edwards.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/aff_pt_montgomery.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/curves.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/ec_edwards.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/ec_montgomery.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/ec_params.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/ec_shortw.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/prj_pt.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/curves/prj_pt_monty.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_add.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_montgomery.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_mul.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_mul_redc1.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_pow.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_rand.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/fp/fp_sqrt.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/hash_algs.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/hmac.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha224.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha256.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha3-224.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha3-256.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha3-384.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha3-512.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha384.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha3.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha512-224.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha512-256.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha512_core.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sha512.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/shake256.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/shake.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/sm3.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/hash/streebog.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_add.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_div.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_logical.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_modinv.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_mul.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_mul_redc1.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/nn/nn_rand.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/decdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecdsa_common.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecfsdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecgdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/eckcdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ec_key.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecosdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecrdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecsdsa_common.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/ecsdsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/eddsa.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/sig_algs.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/sig/sm2.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) thirdparty/libecc/src/utils/utils.o: CFLAGS=$(LIBECC_OVERRIDE_FLAGS) $(CFLAGS_GCCEXT) endif # # User Crypto # ifdef CONFIG_CRYPTO_USER_CRYPTO SRCS-$(CONFIG_CRYPTO_USER_CRYPTO) += \ modules/crypto/hss_crypto_cal.c modules/crypto/hss_crypto_cal.o: x509-ec-sepc384r1-public.h modules/crypto/hss_crypto_cal.o: CFLAGS=$(CFLAGS_GCCEXT) endif endif hart-software-services-2022.10/modules/crypto/hss_crypto.h000066400000000000000000000030641432224323300236260ustar00rootroot00000000000000#ifndef HSS_CRYPTO_H #define HSS_CRYPTO_H /******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Image Signing Crypto * */ #if defined (__cplusplus) extern "C" { #endif bool HSS_Crypto_Verify_ECDSA_P384(const size_t siglen, uint8_t sigBuffer[siglen], const size_t dataBufSize, uint8_t dataBuf[dataBufSize]); #if defined (__cplusplus) } #endif #endif hart-software-services-2022.10/modules/crypto/hss_crypto_cal.c000066400000000000000000000134011432224323300244340ustar00rootroot00000000000000/****************************************************************************************** * * MPFS HSS Embedded Software * * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /*\! *\file Decompression Wrapper *\brief Decompression Wrapper */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_crypto.h" #include #include #include "calini.h" #include "calenum.h" #include "hash.h" static void crypto_init_(void) { static bool initialized = false; if (!initialized) { SATR retval = CALIni(); assert(retval == SATR_SUCCESS); initialized = true; } } // Required constants const SATUINT32_t P384_Gx[] = { 0x72760ab7, 0x3a545e38, 0xbf55296c, 0x5502f25d, 0x82542a38, 0x59f741e0, 0x8ba79b98, 0x6e1d3b62, 0xf320ad74, 0x8eb1c71e, 0xbe8b0537, 0xaa87ca22 }; const SATUINT32_t P384_Gy[] = { 0x90ea0e5f, 0x7a431d7c, 0x1d7e819d, 0x0a60b1ce, 0xb5f0b8c0, 0xe9da3113, 0x289a147c, 0xf8f41dbd, 0x9292dc29, 0x5d9e98bf, 0x96262c6f, 0x3617de4a }; const SATUINT32_t P384_b[] = { 0xd3ec2aef, 0x2a85c8ed, 0x8a2ed19d, 0xc656398d, 0x5013875a, 0x0314088f, 0xfe814112, 0x181d9c6e, 0xe3f82d19, 0x988e056b, 0xe23ee7e4, 0xb3312fa7 }; const SATUINT32_t P384_n[] = { 0xccc52973, 0xecec196a, 0x48b0a77a, 0x581a0db2, 0xf4372ddf, 0xc7634d81, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const SATUINT32_t P384_npc[] = { 0x333ad68d, 0x1313e695, 0xb74f5885, 0xa7e5f24d, 0x0bc8d220, 0x389cb27e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001 }; bool HSS_Crypto_Verify_ECDSA_P384(const size_t siglen, uint8_t sigBuffer[siglen], const size_t dataBufSize, uint8_t dataBuf[dataBufSize]) { bool result = false; SATR retval; crypto_init_(); // // X5.09 ASN.1 DER keys are of the format // // offset/len: description // // bytes 30 76 => // 0/118: SEQUENCE { // // bytes 30 10 06 07 2A 86 48 CE 3D 02 01 => // 2/ 16: SEQUENCE { // // bytes 06 05 2B 81 04 00 22 => // 4/ 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) // 13/ 5: OBJECT IDENTIFIER secp384r1 (1 3 132 0 34) // : } // // 03 bytes 02 00 04 xxxx => // 20/ 98: BIT STRING // : 04 (this means the key is uncompressed) // 24/ 96: xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : } // # include "x509-ec-secp384r1-public.h" const char x509_asn1_ec_der_p384_root[] = { 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, }; if (strncmp(x509_asn1_ec_der_p384_root, SECP384R1_ECDSA_public_key, ARRAY_SIZE(x509_asn1_ec_der_p384_root))) { mHSS_DEBUG_PRINTF(LOG_ERROR, "invalid signing certificate type\n"); result = false; } else { #define SHA384_DIGEST_SIZE 48 #define P384_MOD 0 uint8_t hashBuffer[SHA384_DIGEST_SIZE]; retval = CALHash(SATHASHTYPE_SHA384, dataBuf, dataBufSize, hashBuffer); if (retval == SATR_SUCCESS) { retval = CALPKTrfRes(SAT_TRUE); uint32_t u32SigBuffer[96/sizeof(uint32_t)]; memcpy(u32SigBuffer, sigBuffer, 96); uint32_t u32PubKeyBuffer[96/sizeof(uint32_t)]; memcpy(u32PubKeyBuffer, &(x509_asn1_ec_der_p384_root[24]), 96); if (retval == SATR_SUCCESS) { // signature is composed of (r, s) uint32_t *sigR = &(u32SigBuffer[0]), *sigS = &(u32SigBuffer[96/(sizeof(uint32_t)*2)]); // public key, after 24-byte header, is composed of (x, y) uint32_t *pubKeyX = &(u32PubKeyBuffer[0]), *pubKeyY = &(u32PubKeyBuffer[96/(sizeof(uint32_t)*2)]); retval = CALECDSAVerify((const uint32_t *)hashBuffer, P384_Gx, P384_Gy, pubKeyX, pubKeyY, sigR, sigS, P384_b, P384_MOD, SAT_NULL, P384_n, P384_npc, SHA384_DIGEST_SIZE, SAT_FALSE); if (retval == SATR_SUCCESS) { retval = CALPKTrfRes(SAT_TRUE); if (retval == SATR_SUCCESS) { result = true; } } } } } return result; } hart-software-services-2022.10/modules/crypto/hss_crypto_libecc.c000066400000000000000000000122041432224323300251160ustar00rootroot00000000000000/****************************************************************************************** * * MPFS HSS Embedded Software * * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /*\! *\file Image Signing Crypto *\brief Image Signing Crypto */ #include "config.h" #include "hss_types.h" #undef CONFIG_CC_HAS_INTTYPES #include "hss_debug.h" #include "hss_crypto.h" #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wredundant-decls" #include "libsig.h" #pragma GCC diagnostic pop #define ECDSA_P384_SIG_LEN ((384u/8)*2) bool HSS_Crypto_Verify_ECDSA_P384(const size_t siglen, uint8_t sigBuffer[siglen], const size_t dataBufSize, uint8_t dataBuf[dataBufSize]) { bool result = false; assert(siglen == ECDSA_P384_SIG_LEN); // // X5.09 ASN.1 DER keys are of the format // // offset/len: description // // bytes 30 76 => // 0/118: SEQUENCE { // // bytes 30 10 06 07 2A 86 48 CE 3D 02 01 => // 2/ 16: SEQUENCE { // // bytes 06 05 2B 81 04 00 22 => // 4/ 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) // 13/ 5: OBJECT IDENTIFIER secp384r1 (1 3 132 0 34) // : } // // 03 bytes 02 00 04 xxxx => // 20/ 98: BIT STRING // : 04 (this means the key is uncompressed) // 24/ 96: xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx // : } // // From the perspective of libecc, these are Affine keys. # define X509_ASN1_DER_KEY_OFFSET (24) # include "x509-ec-secp384r1-public.h" const char x509_asn1_ec_der_p384_root[] = { 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, }; if (strncmp(x509_asn1_ec_der_p384_root, SECP384R1_ECDSA_public_key, ARRAY_SIZE(x509_asn1_ec_der_p384_root))) { mHSS_DEBUG_PRINTF(LOG_ERROR, "invalid signing certificate type\n"); result = false; } else { uint8_t const * const aDataBuf = 0u; const uint16_t aDataBufSize = 0u; uint8_t const curve_name[] = "SECP384R1"; const ec_str_params *p_str_params = ec_get_curve_params_by_name(&curve_name[0], ARRAY_SIZE(curve_name)); ec_pub_key pub_key; ec_params params; uint8_t u8siglen; import_params(¶ms, p_str_params); int retval = ec_get_sig_len(¶ms, ECDSA, SHA384, (uint8_t*)&u8siglen); if (retval) { mHSS_DEBUG_PRINTF(LOG_ERROR, "ec_get_sig_len returned %d\n", retval); result = false; } else { uint8_t crv_name_len = ARRAY_SIZE(curve_name); retval = ec_check_curve_type_and_name(SECP384R1, params.curve_name, crv_name_len); if (retval) { mHSS_DEBUG_PRINTF(LOG_ERROR, "ec_check_curve_type_and_name returned %d\n", retval); result = false; } else { retval = ec_pub_key_import_from_aff_buf(&pub_key, ¶ms, (const uint8_t *)&SECP384R1_ECDSA_public_key[X509_ASN1_DER_KEY_OFFSET], ARRAY_SIZE(SECP384R1_ECDSA_public_key) - X509_ASN1_DER_KEY_OFFSET, ECDSA); if (retval) { mHSS_DEBUG_PRINTF(LOG_ERROR, "ec_pub_key_import_from_aff_buf returned %d\n", retval); result = false; } else { int libecc_result = ec_verify(sigBuffer, u8siglen, &pub_key, dataBuf, dataBufSize, ECDSA, SHA384, aDataBuf, aDataBufSize); result = (libecc_result == 0) ? true : false; } } } } return result; } hart-software-services-2022.10/modules/crypto/random.c000066400000000000000000000030021432224323300226740ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Device Serial Number * \brief Device Serial Number */ #include "config.h" #include "hss_types.h" #include #include #include #include #include "hss_debug.h" #include #define NONCE_CHUNK_SIZE (32u) static uint8_t nonce_buffer[NONCE_CHUNK_SIZE]; static int get_random_chunk_(unsigned char *buf, unsigned short len) { uint16_t retVal; int result = 0; retVal = MSS_SYS_nonce_service(nonce_buffer, 0u); if (MSS_SYS_SUCCESS == retVal) { memcpy(buf, nonce_buffer, len); } else { mHSS_FANCY_PRINTF(LOG_ERROR, "Couldn't read random number (%u)\n", retVal); result = 1; } return result; } int get_random(unsigned char *buf, unsigned short len); int get_random(unsigned char *buf, unsigned short len) { int result = 0; off_t offset = 0u; MSS_SYS_select_service_mode(MSS_SYS_SERVICE_POLLING_MODE, NULL); memset(nonce_buffer, 0, ARRAY_SIZE(nonce_buffer)); ssize_t slen = (ssize_t)len; while (!result && (slen > NONCE_CHUNK_SIZE)) { result = get_random_chunk_(&buf[offset], NONCE_CHUNK_SIZE); slen = slen - NONCE_CHUNK_SIZE; } if (!result && (slen > 0)) { result = get_random_chunk_(&buf[offset], slen); } return result; } hart-software-services-2022.10/modules/crypto/random.h000066400000000000000000000033671432224323300227170ustar00rootroot00000000000000#ifndef RANDOM_H #define RANDOM_H /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ void srandom(unsigned x); char * initstate(unsigned seed, char *arg_state, size_t n); char * setstate(const char *arg_state); long random(void); #endif hart-software-services-2022.10/modules/debug/000077500000000000000000000000001432224323300210235ustar00rootroot00000000000000hart-software-services-2022.10/modules/debug/Kconfig000066400000000000000000000053451432224323300223350ustar00rootroot00000000000000menu "Debug Options" config DEBUG_LOG_STATE_TRANSITIONS bool "Debug State Transitions" default y help This feature enables debug output for all state machine transitions. If you do not know what to do here, say Y. config DEBUG_LOOP_TIMES bool "Debug Loop Times" default y help This feature enables output for loop timings via debug UART (mmuart0). If you do not know what to do here, say Y. config DEBUG_LOOP_TIMES_THRESHOLD int "Output loop times every threshold cycles" default 2500000 depends on DEBUG_LOOP_TIMES help If CONFIG_DEBUG_LOOP_TIMES is enabled, specify how often (in loop cycles) loop timings diagnostics should be dumped out via the debug UART. config DEBUG_IPI_STATS bool "Debug IPI Statistics" default n help This feature enables output for IPI statistics via debug UART If you do not know what to do here, say N. config DEBUG_CHUNK_DOWNLOADS bool "Debug chunk downloads" depends on SERVICE_BOOT default n help This feature enables logging of each chunk copy. If you do not know what to do here, say N. config DEBUG_MSCGEN_IPI bool "Output mscgen compatible traces of IPI messages" depends on SERVICE_BOOT default n help This feature enables logging of IPIs in a format to help generate mscgen traces. If you do not know what to do here, say N. config DEBUG_PROFILING_SUPPORT bool "Output periodic function timings" depends on DEBUG_LOOP_TIMES default n help This feature enables periodic output of function timings. If you do not know what to do here, say N. config DEBUG_PROFILING_MAX_NUM_FUNCTIONS int "Determine the maximum number of functions to track" default 128 depends on DEBUG_PROFILING_SUPPORT help This feature configures how many functions to trace during profiling. config DEBUG_PERF_CTRS bool "Performance Counters" depends on SERVICE_TINYCLI default N help This feature enables performance counters to track wallclock time spent in various activities, such as DDR training, memory tests, MMC init, boot, etc. If you do not know what to do here, say N. config DEBUG_PERF_CTRS_NUM int "Determine how many performance counters are enabled" default 16 depends on DEBUG_PERF_CTRS help This feature configures how many performance counters are enabled. config DEBUG_RESET_REASON bool "Enable parsing of RESET_SR reset reason register" default N help This feature enables parsing and output of the reset reason on the HSS console. This may be useful to debug unexpected system reboots. If you do not know what to do here, say N. endmenu hart-software-services-2022.10/modules/debug/Makefile000066400000000000000000000032731432224323300224700ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Optional profiling hooks # EXTRA_SRCS-y += \ modules/debug/hss_debug.c \ modules/debug/hss_perfctr.c \ EXTRA_SRCS-$(CONFIG_DEBUG_PROFILING_SUPPORT) += \ modules/debug/profiling.c \ OPT-$(CONFIG_DEBUG_PROFILING_SUPPORT) += \ -finstrument-functions \ -finstrument-functions-exclude-function-list=g5soc_init_mutex,ee_printf,CSR_GetHartId,CSR_GetTime,ee_vsprintf,uart_send_string_mmuart_ex,g5soc_release_mutex,take_loop,CSR_GetTickCount,ee_puts INCLUDES +=\ -Imodules/debug/ \ modules/debug/profiling.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/modules/debug/hss_debug.c000066400000000000000000000037611432224323300231410ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Debug logging * \brief Debug logging */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_clock.h" #include void HSS_Debug_Timestamp(void) { HSS_Debug_Highlight(HSS_DEBUG_LOG_TIMESTAMP); (void)sbi_printf("[%" PRIu64, HSS_GetTime() / ONE_SEC); (void)sbi_printf(".%05" PRIu64 "]", HSS_GetTime() % ONE_SEC); } void HSS_Debug_Highlight(HSS_Debug_LogLevel_t logLevel) { #if IS_ENABLED(CONFIG_COLOR_OUTPUT) static const char fancyTimestampHighlight[] = "\033[32m"; static const char fancyFunctionHighlight[] = "\033[33m"; static const char fancyErrorHighlight[] = "\033[1;31m"; static const char fancyWarnHighlight[] = "\033[1;33m"; static const char fancyStatusHighlight[] = "\033[1;32m"; static const char fancyNormalHighlight[] = "\033[0m"; static const char fancyStateTransitionHighlight[] = "\033[1;34m"; char const * pHighlight; switch (logLevel) { default: __attribute__((fallthrough)); // deliberate fallthrough case HSS_DEBUG_LOG_NORMAL: pHighlight = fancyNormalHighlight; break; case HSS_DEBUG_LOG_FUNCTION: pHighlight = fancyFunctionHighlight; break; case HSS_DEBUG_LOG_TIMESTAMP: pHighlight = fancyTimestampHighlight; break; case HSS_DEBUG_LOG_ERROR: pHighlight = fancyErrorHighlight; break; case HSS_DEBUG_LOG_WARN: pHighlight = fancyWarnHighlight; break; case HSS_DEBUG_LOG_STATUS: pHighlight = fancyStatusHighlight; break; case HSS_DEBUG_LOG_STATE_TRANSITION: pHighlight = fancyStateTransitionHighlight; break; } mHSS_PUTS(pHighlight); #else (void)logLevel; #endif } hart-software-services-2022.10/modules/debug/hss_perfctr.c000066400000000000000000000064711432224323300235210ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Debug logging * \brief Debug logging */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_clock.h" #include "hss_perfctr.h" #include #include #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) struct { int index; char const * pName; bool isAllocated; HSSTicks_t startTime; HSSTicks_t lapTime; } perfCtrs[CONFIG_DEBUG_PERF_CTRS_NUM]; #endif bool HSS_PerfCtr_Allocate(int *pIdx, char const * pName) { bool result = false; #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) if ((*pIdx >= 0) && (*pIdx < ARRAY_SIZE(perfCtrs))) { if ((perfCtrs[*pIdx].isAllocated) && (perfCtrs[*pIdx].pName == pName)) { //mHSS_DEBUG_PRINTF(LOG_WARN, "found already allocated perf ctr for >>%s<<\n", pName); result = true; } } else { assert(pIdx); *pIdx = PERF_CTR_UNINITIALIZED; for (int index = 0; index < ARRAY_SIZE(perfCtrs); index++) { if (!perfCtrs[index].isAllocated) { perfCtrs[index].isAllocated = true; perfCtrs[index].pName = pName; result = true; perfCtrs[index].startTime = HSS_GetTime(); *pIdx = index; break; } } if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "failed to allocate perf ctr for >>%s<<\n", pName); } } #endif return result; } void HSS_PerfCtr_Deallocate(int index) { if (index != PERF_CTR_UNINITIALIZED) { #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) assert(index < ARRAY_SIZE(perfCtrs)); if ((index >= 0) && (perfCtrs[index].isAllocated)) { perfCtrs[index].isAllocated = false; perfCtrs[index].pName = NULL; } #endif } } void HSS_PerfCtr_Start(int index) { if (index != PERF_CTR_UNINITIALIZED) { #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) assert(index < ARRAY_SIZE(perfCtrs)); if (index >= 0) { perfCtrs[index].startTime = HSS_GetTime(); } #endif } } void HSS_PerfCtr_Lap(int index) { if (index != PERF_CTR_UNINITIALIZED) { #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) assert(index < ARRAY_SIZE(perfCtrs)); if (index >= 0) { perfCtrs[index].lapTime = HSS_GetTime(); } #endif } } HSSTicks_t HSS_PerfCtr_GetTime(int index) { HSSTicks_t result = 0u; if (index != PERF_CTR_UNINITIALIZED) { #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) assert(index < ARRAY_SIZE(perfCtrs)); if (index >= 0) { result = perfCtrs[index].lapTime - perfCtrs[index].startTime; } #endif } return result; } void HSS_PerfCtr_DumpAll(void) { #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) for (int i = 0; i < ARRAY_SIZE(perfCtrs); i++) { if (perfCtrs[i].isAllocated) { size_t ticks = HSS_PerfCtr_GetTime(i); size_t millisecs = (ticks + (TICKS_PER_MILLISEC/2)) / TICKS_PER_MILLISEC; mHSS_DEBUG_PRINTF(LOG_NORMAL, "% 8lu ms (% 8lu ticks) - %s\n", millisecs, ticks, perfCtrs[i].pName ? perfCtrs[i].pName : "(null)"); } } #endif } hart-software-services-2022.10/modules/debug/hss_perfctr.h000066400000000000000000000013701432224323300235170ustar00rootroot00000000000000#ifndef HSS_PERF_CTR_H #define HSS_PERF_CTR_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Performance Counter * \brief Performance Counter */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_clock.h" #include bool HSS_PerfCtr_Allocate(int *pIdx, char const * name) __attribute__((nonnull(1))); void HSS_PerfCtr_Deallocate(int index); void HSS_PerfCtr_Start(int index); void HSS_PerfCtr_Lap(int index); HSSTicks_t HSS_PerfCtr_GetTime(int index); void HSS_PerfCtr_DumpAll(void); #define PERF_CTR_UNINITIALIZED -1 #endif hart-software-services-2022.10/modules/debug/profiling.c000066400000000000000000000050231432224323300231600ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Code Profiling * \brief Code Profiling */ #include "config.h" #include "hss_types.h" #include "csr_helper.h" #include struct Node { void *pFunc; uint64_t entryTime; uint64_t timeCount; } functionNode[CONFIG_DEBUG_PROFILING_MAX_NUM_FUNCTIONS] = { 0 }; size_t allocationCount = 0u; extern void g5soc_init_mutex(volatile uint32_t * p_mutex); extern void g5soc_take_mutex(volatile uint32_t * p_mutex); extern void g5soc_release_mutex(volatile uint32_t * p_mutex); volatile uint32_t profiling_mutex = 0u; #define mATOMIC_ENTER g5soc_take_mutex(&profiling_mutex); #define mATOMIC_EXIT g5soc_release_mutex(&profiling_mutex); void __attribute__((no_instrument_function)) __cyg_profile_func_enter (void *pFunc, void *pCaller) { enum HSSHartId const myHartId = current_hartid(); (void) pCaller; if (myHartId != 0) { return; } assert(pFunc != NULL); struct Node *pNode = NULL; size_t i; for (i = 0u; i < allocationCount; i++) { if (functionNode[i].pFunc == pFunc) { pNode = &(functionNode[i]); break; } } if (!pNode) { assert(allocationCount < ARRAY_SIZE(functionNode)); pNode = &(functionNode[allocationCount]); allocationCount++; mATOMIC_ENTER; pNode->pFunc = pFunc; pNode->timeCount = 0lu; mATOMIC_EXIT; } if (pNode) { mATOMIC_ENTER; pNode->entryTime = CSR_GetTickCount(); mATOMIC_EXIT; } return; } void __attribute__((no_instrument_function)) __cyg_profile_func_exit (void *pFunc, void *pCaller) { enum HSSHartId const myHartId = current_hartid(); (void) pCaller; assert(pFunc != NULL); if (myHartId != 0) { return; } size_t i; for (i = 0u; i < allocationCount; i++) { if (functionNode[i].pFunc == pFunc) { mATOMIC_ENTER; functionNode[i].timeCount += (CSR_GetTickCount() - functionNode[i].entryTime); mATOMIC_EXIT; break; } } return; } void __attribute__((no_instrument_function)) dump_profile(void); void __attribute__((no_instrument_function)) dump_profile(void) { size_t i; for (i = 0u; i < allocationCount; i++) { mHSS_DEBUG_PRINTF_EX("PROFILE: %p, %lu\n", functionNode[i].pFunc, functionNode[i].timeCount); } } hart-software-services-2022.10/modules/misc/000077500000000000000000000000001432224323300206705ustar00rootroot00000000000000hart-software-services-2022.10/modules/misc/Makefile000066400000000000000000000042201432224323300223260ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Miscellaneous Functionality EXTRA_SRCS-y += \ modules/misc/assert.c \ modules/misc/csr_helper.c \ modules/misc/c_stubs.c \ modules/misc/hss_crc16.c \ modules/misc/hss_crc32.c \ modules/misc/hss_memcpy_via_pdma.c \ modules/misc/hss_progress.c \ modules/misc/device_serial_number.c \ # modules/misc/ee_printf.c \ # modules/misc/vsnprintf.c \ EXTRA_SRCS-$(CONFIG_TINYCLI) += \ modules/misc/hss_tinycli.c \ EXTRA_SRCS-$(CONFIG_MEMTEST) += \ modules/misc/hss_memtest.c \ EXTRA_SRCS-$(CONFIG_CC_STACKPROTECTOR_STRONG) += \ modules/misc/stack_guard.c INCLUDES +=\ modules/misc/c_stubs.o: CFLAGS=$(CFLAGS_GCCEXT) modules/misc/vsnprintf.o: CFLAGS=$(CFLAGS_GCCEXT) modules/misc/assert.o: CFLAGS=$(CFLAGS_GCCEXT) modules/misc/ee_printf.o: CFLAGS=$(CFLAGS_GCCEXT) modules/misc/csr_helper.o: CFLAGS=$(CFLAGS_GCCEXT) modules/misc/hss_memcpy_via_pdma.o: CFLAGS=$(CFLAGS_GCCEXT) modules/misc/stack_guard.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/modules/misc/assert.c000066400000000000000000000023711432224323300223400ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file assert implementation * \brrief Local assert */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include /*! * \brief Local implemention of assert fail */ __attribute__ ((__noreturn__)) void __assert_func(const char *__file, unsigned int __line, const char *__function, const char *__assertion); __attribute__ ((__noreturn__)) void __assert_func(const char *__file, unsigned int __line, const char *__function, const char *__assertion) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s:%d: %s() Assertion failed:\n\t%s\n", __file, __line, __function, __assertion); #ifndef __riscv exit(1); #else while(1); #endif } __attribute__ ((__noreturn__)) void __assert_fail(const char *__file, unsigned int __line, const char *__function, const char *__assertion); __attribute__ ((__noreturn__)) void __assert_fail(const char *__file, unsigned int __line, const char *__function, const char *__assertion) { __assert_func(__file, __line, __function, __assertion); } hart-software-services-2022.10/modules/misc/c_stubs.c000066400000000000000000000154451432224323300225070ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * This file contains trivial C standard library routines for the * Hart Software Services, to allow it link without external dependencies. * */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include #include #include #include #include #include #include "csr_helper.h" #define MAX_TEXT_LENGTH 256 __attribute__((weak)) size_t strnlen(const char *s, size_t count) { size_t result = 0; while (count && *s) { ++result; ++s; } return result; } __attribute__((weak,used)) void *memcpy(void * restrict dest, const void * restrict src, size_t n) { // no overlaps allowed!! char *cDest = (char*)dest; char *cSrc = (char*)src; // no overlaps allowed!! { if (cDest > cSrc) { assert((cSrc + n -1) < cDest); } else { assert((cDest + n -1) < cSrc); } } #ifndef CONFIG_OPENSBI while (n--) { *cDest = *cSrc; ++cDest; ++cSrc; } return (dest); #else return sbi_memcpy(dest, src, n); #endif } __attribute__((weak)) int memcmp(const void * restrict s1, const void * restrict s2, size_t n) { #ifndef CONFIG_OPENSBI int result; const unsigned char *temp1 = s1; const unsigned char *temp2 = s2; while (n > 0 && (*temp1 == *temp2)) { temp1++; temp2++; n--; } if (n > 0) { result = *temp1 - *temp2; } else { result = 0; } return result; #else return sbi_memcmp(s1, s2, n); #endif } __attribute__((weak)) void *memset(void *dest, int c, size_t n) { #ifndef CONFIG_OPENSBI char *cDest = (char*)dest; while (n--) { *cDest = (char)c; ++cDest } return (dest); #else return sbi_memset(dest, c, n); #endif } __attribute__((weak)) size_t strlen(const char *s) { #ifndef CONFIG_OPENSBI size_t result = 0; while (*s) { ++s ++result } return result; #else return sbi_strlen(s); #endif } //#endif /***********************************************************************/ int tolower(int __c); // ctypes.h __attribute__((weak)) int tolower(int __c) { if ((__c > ('A'-1)) && (__c < ('Z'+1))) { __c -= ('A'-'a'); } return __c; } __attribute__((weak)) int strncasecmp(const char *s1, const char *s2, size_t n) { int result = 0; while ((*s1 != 0) && (*s2 != 0) && n) { int c1 = tolower((unsigned char)*s1); int c2 = tolower((unsigned char)*s2); //if (c1 == c2) { // ++s1 // ++s2 // continue; //} else if (c1 < c2) { result = -1; break; } else if (c1 > c2) { result = 1; break; } ++s1; ++s2; --n; } if (n && !result) { if ((*s1) && !(*s2)) { result = 1; } if ((*s2) && !(*s1)) { result = -1; } } return result; } __attribute__((weak)) char *strtok_r(char *str, const char *delim, char **saveptr) { char *result = NULL; if (*saveptr == NULL) { *saveptr = str; } if (**saveptr == 0) { *saveptr = NULL; result = NULL; } else { result = *saveptr; } if (result != NULL) { while (**saveptr != 0) { const char *pDelim = delim; while (*pDelim != 0) { if (**saveptr == *pDelim) { **saveptr = 0; *saveptr = *saveptr + 1; return result; } ++pDelim; } *saveptr = *saveptr + 1; } } return result; } __attribute__((weak)) int strncmp(const char *s1, const char *s2, size_t n) { int result = 0; assert(s1); assert(s2); for (size_t i = 0u; i < n; i++) { if (*s1 < *s2) { result = -1; break; } else if (*s1 > *s2) { result = 1; break; } else /* if (*s1 == *s2) */ { result = 0; } ++s1; ++s2; } return result; } int64_t __bswapdi2(int64_t a); __attribute__((weak)) int64_t __bswapdi2(int64_t a) { int64_t result; result = ((a & 0xFF) << 56) | ((a & 0xFF00) << 40) | ((a & 0xFF0000) << 24) | ((a & 0xFF000000) << 8) | ((a & 0xFF00000000) >> 8) | ((a & 0xFF0000000000) >> 24) | ((a & 0xFF000000000000) >> 40) | ((a & 0xFF00000000000000) >> 56); return result; } __attribute__((weak)) uint64_t strtoul(const char * restrict nptr, char ** restrict endptr, int base) { size_t count = 0; uint64_t result = 0u; bool done = false; assert(nptr); do { const char digit = *nptr; switch (digit) { case '-': continue; case '0'...'9': result *= base; result += digit - '0'; break; case 'a'...'f': result *= base; result += 10u + digit - 'a'; break; case 'A'...'F': result *= base; result += 10u + digit - 'A'; break; case 'x': if ((count != 1) || (base != 16)) { done = true; } break; default: done = true; break; } ++count; ++nptr; } while (!done); if (endptr) { *endptr = (char *)nptr; } return result; } // // We use the GCC intrinsic __builtin_popcount() to count cache way bits set // if we don't have an implementation for __popcountdi2, we'll use the weakly // bound one here, which does some common bit tricks int64_t __popcountdi2(int64_t n); __attribute__((weak, used)) int64_t __popcountdi2(int64_t n) { n = n - ((n >> 1) & 0x5555555555555555ul); n = ((n >> 2) & 0x3333333333333333ul) + (n & 0x3333333333333333ul); n = ((n >> 4) + n) & 0x0f0f0f0f0f0f0f0ful; n = ((n >> 32) + n); // & 0x00000000fffffffful; n = ((n >> 16) + n); // & 0x000000000000fffful; n = ((n >> 8) + n) & 0x000000000000007ful; return n; } // // fortify wrappers, if needed... // void * __memcpy_chk(void *dest, const void *src, size_t n, size_t os); __attribute__((weak)) void * __memcpy_chk(void *dest, const void *src, size_t n, size_t os) { void * result = NULL; (void)os; result = memcpy(dest, src, n); return result; } void * __memset_chk (void *s, int c, size_t n, size_t os); __attribute__((weak)) void * __memset_chk (void *s, int c, size_t n, size_t os) { void * result = NULL; (void)os; result = memset(s, c, n); return result; } hart-software-services-2022.10/modules/misc/csr_helper.c000066400000000000000000000023431432224323300231640ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file CSR Helper * \brief CSR Helper */ #include "config.h" #include "hss_types.h" #include "csr_helper.h" #include "ssmb_ipi.h" #include "hss_debug.h" #include "mpfs_reg_map.h" #include HSSTicks_t CSR_GetTickCount(void) { HSSTicks_t tickCount; tickCount = csr_read(mcycle); return tickCount; } HSSTicks_t CSR_GetTime(void) { HSSTicks_t time; time = mHSS_ReadRegU64(CLINT, MTIME); return time; } void CSR_ClearMSIP(void) { int hartid = current_hartid(); switch (hartid) { case HSS_HART_U54_1: mHSS_WriteRegU32(CLINT, MSIP_U54_1, 0u); break; case HSS_HART_U54_2: mHSS_WriteRegU32(CLINT, MSIP_U54_2, 0u); break; case HSS_HART_U54_3: mHSS_WriteRegU32(CLINT, MSIP_U54_3, 0u); break; case HSS_HART_U54_4: mHSS_WriteRegU32(CLINT, MSIP_U54_4, 0u); break; default: mHSS_DEBUG_PRINTF(LOG_NORMAL, "Unknown hart ID %u\n", hartid); assert(0 == 1); break; } } hart-software-services-2022.10/modules/misc/device_serial_number.c000066400000000000000000000027601432224323300252070ustar00rootroot00000000000000/******************************************************************************* * Copyright 2017-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Device Serial Number * \brief Device Serial Number */ #include "config.h" #include "hss_types.h" #include #include "hss_debug.h" #include "hss_version.h" #include "csr_helper.h" #include "device_serial_number.h" #include "mss_sys_services.h" /****************************************************************************/ #include static uint8_t serial_num_buffer[50]; static bool result = false; bool Device_Serial_Number_Init(void) { MSS_SYS_select_service_mode( MSS_SYS_SERVICE_POLLING_MODE, NULL); memset(serial_num_buffer, 0, ARRAY_SIZE(serial_num_buffer)); if (MSS_SYS_SUCCESS == MSS_SYS_get_serial_number(serial_num_buffer, 0u /*mb_offset??*/)) { mHSS_FANCY_PRINTF(LOG_STATUS, "Serial Number: \n"); // move to boards... for (int i = 0; i < ARRAY_SIZE(serial_num_buffer); i++) { mHSS_PRINTF("%02x", serial_num_buffer[i]); } mHSS_PRINTF("\n"); result = true; } else { mHSS_FANCY_PRINTF(LOG_ERROR, "Couldn't read Serial Number\n"); } return result; } bool Get_Device_Serial_Number(uint8_t **ppBuffer, size_t* pLen) { assert(ppBuffer); assert(pLen); *ppBuffer = &(serial_num_buffer[0]); *pLen = ARRAY_SIZE(serial_num_buffer); return result; } hart-software-services-2022.10/modules/misc/hss_crc16.c000066400000000000000000000014371432224323300226340ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file CRC16 calculation * \brief CRC16 calculation */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_crc16.h" uint16_t CRC16_calculate(const uint8_t *pInput, size_t numBytes) { uint16_t result = 0u; int i; while (numBytes--) { result = result ^ (*pInput << 8); pInput++; for (i = 0; i < 8; i++) { if (result & 0x8000u) { result = (result << 1) ^ 0x1021u; } else { result = result << 1; } } } return result; } hart-software-services-2022.10/modules/misc/hss_crc32.c000066400000000000000000000131031432224323300226230ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file CRC32 calculation * \brief CRC32 calculation */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_crc32.h" #if IS_ENABLED(CONFIG_CRC32_USE_PRECALC_TABLE) static const uint32_t precalcTable_[256] = { 0x00000000u, 0x77073096u, 0xEE0E612Cu, 0x990951BAu, 0x076DC419u, 0x706AF48Fu, 0xE963A535u, 0x9E6495A3u, 0x0EDB8832u, 0x79DCB8A4u, 0xE0D5E91Eu, 0x97D2D988u, 0x09B64C2Bu, 0x7EB17CBDu, 0xE7B82D07u, 0x90BF1D91u, 0x1DB71064u, 0x6AB020F2u, 0xF3B97148u, 0x84BE41DEu, 0x1ADAD47Du, 0x6DDDE4EBu, 0xF4D4B551u, 0x83D385C7u, 0x136C9856u, 0x646BA8C0u, 0xFD62F97Au, 0x8A65C9ECu, 0x14015C4Fu, 0x63066CD9u, 0xFA0F3D63u, 0x8D080DF5u, 0x3B6E20C8u, 0x4C69105Eu, 0xD56041E4u, 0xA2677172u, 0x3C03E4D1u, 0x4B04D447u, 0xD20D85FDu, 0xA50AB56Bu, 0x35B5A8FAu, 0x42B2986Cu, 0xDBBBC9D6u, 0xACBCF940u, 0x32D86CE3u, 0x45DF5C75u, 0xDCD60DCFu, 0xABD13D59u, 0x26D930ACu, 0x51DE003Au, 0xC8D75180u, 0xBFD06116u, 0x21B4F4B5u, 0x56B3C423u, 0xCFBA9599u, 0xB8BDA50Fu, 0x2802B89Eu, 0x5F058808u, 0xC60CD9B2u, 0xB10BE924u, 0x2F6F7C87u, 0x58684C11u, 0xC1611DABu, 0xB6662D3Du, 0x76DC4190u, 0x01DB7106u, 0x98D220BCu, 0xEFD5102Au, 0x71B18589u, 0x06B6B51Fu, 0x9FBFE4A5u, 0xE8B8D433u, 0x7807C9A2u, 0x0F00F934u, 0x9609A88Eu, 0xE10E9818u, 0x7F6A0DBBu, 0x086D3D2Du, 0x91646C97u, 0xE6635C01u, 0x6B6B51F4u, 0x1C6C6162u, 0x856530D8u, 0xF262004Eu, 0x6C0695EDu, 0x1B01A57Bu, 0x8208F4C1u, 0xF50FC457u, 0x65B0D9C6u, 0x12B7E950u, 0x8BBEB8EAu, 0xFCB9887Cu, 0x62DD1DDFu, 0x15DA2D49u, 0x8CD37CF3u, 0xFBD44C65u, 0x4DB26158u, 0x3AB551CEu, 0xA3BC0074u, 0xD4BB30E2u, 0x4ADFA541u, 0x3DD895D7u, 0xA4D1C46Du, 0xD3D6F4FBu, 0x4369E96Au, 0x346ED9FCu, 0xAD678846u, 0xDA60B8D0u, 0x44042D73u, 0x33031DE5u, 0xAA0A4C5Fu, 0xDD0D7CC9u, 0x5005713Cu, 0x270241AAu, 0xBE0B1010u, 0xC90C2086u, 0x5768B525u, 0x206F85B3u, 0xB966D409u, 0xCE61E49Fu, 0x5EDEF90Eu, 0x29D9C998u, 0xB0D09822u, 0xC7D7A8B4u, 0x59B33D17u, 0x2EB40D81u, 0xB7BD5C3Bu, 0xC0BA6CADu, 0xEDB88320u, 0x9ABFB3B6u, 0x03B6E20Cu, 0x74B1D29Au, 0xEAD54739u, 0x9DD277AFu, 0x04DB2615u, 0x73DC1683u, 0xE3630B12u, 0x94643B84u, 0x0D6D6A3Eu, 0x7A6A5AA8u, 0xE40ECF0Bu, 0x9309FF9Du, 0x0A00AE27u, 0x7D079EB1u, 0xF00F9344u, 0x8708A3D2u, 0x1E01F268u, 0x6906C2FEu, 0xF762575Du, 0x806567CBu, 0x196C3671u, 0x6E6B06E7u, 0xFED41B76u, 0x89D32BE0u, 0x10DA7A5Au, 0x67DD4ACCu, 0xF9B9DF6Fu, 0x8EBEEFF9u, 0x17B7BE43u, 0x60B08ED5u, 0xD6D6A3E8u, 0xA1D1937Eu, 0x38D8C2C4u, 0x4FDFF252u, 0xD1BB67F1u, 0xA6BC5767u, 0x3FB506DDu, 0x48B2364Bu, 0xD80D2BDAu, 0xAF0A1B4Cu, 0x36034AF6u, 0x41047A60u, 0xDF60EFC3u, 0xA867DF55u, 0x316E8EEFu, 0x4669BE79u, 0xCB61B38Cu, 0xBC66831Au, 0x256FD2A0u, 0x5268E236u, 0xCC0C7795u, 0xBB0B4703u, 0x220216B9u, 0x5505262Fu, 0xC5BA3BBEu, 0xB2BD0B28u, 0x2BB45A92u, 0x5CB36A04u, 0xC2D7FFA7u, 0xB5D0CF31u, 0x2CD99E8Bu, 0x5BDEAE1Du, 0x9B64C2B0u, 0xEC63F226u, 0x756AA39Cu, 0x026D930Au, 0x9C0906A9u, 0xEB0E363Fu, 0x72076785u, 0x05005713u, 0x95BF4A82u, 0xE2B87A14u, 0x7BB12BAEu, 0x0CB61B38u, 0x92D28E9Bu, 0xE5D5BE0Du, 0x7CDCEFB7u, 0x0BDBDF21u, 0x86D3D2D4u, 0xF1D4E242u, 0x68DDB3F8u, 0x1FDA836Eu, 0x81BE16CDu, 0xF6B9265Bu, 0x6FB077E1u, 0x18B74777u, 0x88085AE6u, 0xFF0F6A70u, 0x66063BCAu, 0x11010B5Cu, 0x8F659EFFu, 0xF862AE69u, 0x616BFFD3u, 0x166CCF45u, 0xA00AE278u, 0xD70DD2EEu, 0x4E048354u, 0x3903B3C2u, 0xA7672661u, 0xD06016F7u, 0x4969474Du, 0x3E6E77DBu, 0xAED16A4Au, 0xD9D65ADCu, 0x40DF0B66u, 0x37D83BF0u, 0xA9BCAE53u, 0xDEBB9EC5u, 0x47B2CF7Fu, 0x30B5FFE9u, 0xBDBDF21Cu, 0xCABAC28Au, 0x53B39330u, 0x24B4A3A6u, 0xBAD03605u, 0xCDD70693u, 0x54DE5729u, 0x23D967BFu, 0xB3667A2Eu, 0xC4614AB8u, 0x5D681B02u, 0x2A6F2B94u, 0xB40BBE37u, 0xC30C8EA1u, 0x5A05DF1Bu, 0x2D02EF8Du }; #else // We can save space in eNVM (when compressed) // by calculating the CRC32 table on the fly once static bool precalc_initialized_ = false; static uint32_t precalcTable_[256] = { 0u, }; static void CRC32_genTable_(void); static void CRC32_genTable_(void) { uint32_t crc; uint8_t i; // Polynomial defining this crc (except x^32): // static const char p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 }; // Generate xor pattern from polynomial (0xedb88320) // uint32_t xor_pattern = 0u; // for (i = 0; i < ARRAY_SIZE(p); i++) { // xor_pattern |= 1ul << (31 - p[i]); // } const uint32_t xor_pattern = 0xEDB88320u; // Compute table of CRC's for (i = 1; i /* < 256 */; i++) { crc = i; for (uint8_t bit = 8u; bit; bit--) { crc = crc & 1 ? (crc >> 1) ^ xor_pattern : crc >> 1; } precalcTable_[i] = crc; } } #endif #define CRC32_MASK (0xFFFFFFFFu) #define CRC32_SEED (CRC32_MASK) static inline uint32_t CRC32_updateByte(uint32_t crc32, const uint8_t byte) { uint32_t index; index = (crc32 ^ byte) & 0xFF; crc32 = (crc32 >> 8) ^ precalcTable_[index]; return crc32 & CRC32_MASK; } uint32_t CRC32_calculate(uint8_t const *pInput, size_t numBytes) { uint32_t crc32 = 0u; return CRC32_calculate_ex(crc32, pInput, numBytes); } uint32_t CRC32_calculate_ex(uint32_t seed, uint8_t const *pInput, size_t numBytes) { uint32_t crc32 = ~seed; #if !IS_ENABLED(CONFIG_CRC32_USE_PRECALC_TABLE) if (!precalc_initialized_) { precalc_initialized_ = true; CRC32_genTable_(); } #endif if (pInput != NULL) { while (numBytes--) { crc32 = CRC32_updateByte(crc32, *pInput); ++pInput; } } return ~crc32; } hart-software-services-2022.10/modules/misc/hss_memcpy_via_pdma.c000066400000000000000000000061031432224323300250430ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Boot Driver API * \brief API functions for booting firmware service * */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_memcpy_via_pdma.h" #include #include #if IS_ENABLED(CONFIG_USE_PDMA) #include "drivers/mss/mss_pdma/mss_pdma.h" static char const * const pdmaErrorTable[] = { [ MSS_PDMA_ERROR_INVALID_SRC_ADDR ] = "Invalid source address", [ MSS_PDMA_ERROR_INVALID_DEST_ADDR ] = "Invalid destination address", [ MSS_PDMA_ERROR_TRANSACTION_IN_PROGRESS ] = "Transaction in progress", [ MSS_PDMA_ERROR_INVALID_CHANNEL_ID ] = "Invalid Channel ID", [ MSS_PDMA_ERROR_INVALID_NEXTCFG_WSIZE ] = "Invalid Write Size", [ MSS_PDMA_ERROR_INVALID_NEXTCFG_RSIZE ] = "Invalid Read Size", [ MSS_PDMA_ERROR_LAST_ID ] = "Last ID" }; #endif static void *do_memcpy_via_pdma_(void * restrict dest, void const * restrict src, size_t num_bytes); static void *do_memcpy_via_pdma_(void * restrict dest, void const * restrict src, size_t num_bytes) { void *result = NULL; #if IS_ENABLED(CONFIG_USE_PDMA) // num_bytes must be multiple of 16 or more if (!(num_bytes & 0xFu)) { uint8_t pdma_error_code = 0u; mss_pdma_channel_config_t pdma_config_ch0 = { .src_addr = (size_t)src, .dest_addr = (size_t)dest, .num_bytes = num_bytes, .enable_done_int = 0, .enable_err_int = 0, .force_order = 0, .repeat = 0u }; pdma_error_code = MSS_PDMA_setup_transfer(MSS_PDMA_CHANNEL_0, &pdma_config_ch0); if (pdma_error_code == 0) { pdma_error_code = MSS_PDMA_start_transfer(MSS_PDMA_CHANNEL_0); if (pdma_error_code == 0) { while (!MSS_PDMA_get_transfer_complete_status(MSS_PDMA_CHANNEL_0)) { ; } MSS_PDMA_clear_transfer_complete_status(MSS_PDMA_CHANNEL_0); } } if (pdma_error_code != 0) { if (pdma_error_code < ARRAY_SIZE(pdmaErrorTable)) { mHSS_DEBUG_PRINTF(LOG_ERROR, "PDMA Error: %s\n", pdmaErrorTable[pdma_error_code]); } } else { result = dest; } } #endif if (!result) { // fall back to traditional memcpy() result = memcpy(dest, src, num_bytes); } return result; } void *memcpy_via_pdma(void *dest, void const *src, size_t num_bytes) { // no overlaps allowed!! { char *cDest = (char *)dest; char const *cSrc = (char const *)src; if (cDest > cSrc) { assert((cSrc + num_bytes -1) < cDest); } else { assert((cDest + num_bytes -1) < cSrc); } } //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Copy from %p to %p (%x bytes)\n", src, dest, num_bytes); return do_memcpy_via_pdma_(dest, src, num_bytes); } hart-software-services-2022.10/modules/misc/hss_memtest.c000066400000000000000000000202401432224323300233650ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Simple Memory Tester * \brief Simple Memory Tester * * Simple memory tester, based on * Barr, Michael. "Software-Based Memory Testing," Embedded Systems Programming, * July 2000, pp. 28-40. * * The original source code for these memory tests is in the public domain and is available at * https://barrgroup.com/resources/free-source-code-memory-tests-c */ #include "config.h" #include #include "hss_types.h" #include "hss_debug.h" #include "hss_memtest.h" #include "hss_progress.h" #include "uart_helper.h" #include "hss_perfctr.h" // Walking Ones test of the Data Bus wiring static uint64_t HSS_MemTestDataBus(volatile uint64_t *address) { uint64_t pattern; uint64_t result = 0u; for (pattern = 1u; pattern != 0u; pattern <<=1) { *address = pattern; if (*address != pattern) { result = pattern; break; } } return result; } // Walking Ones test of the Address Bus wiring static void log_error_(const int count, volatile void *ptr, const uint64_t value, const uint64_t expected) { mHSS_FANCY_PRINTF(LOG_ERROR, "%d: 0x%016p==0x%016llx vs expected 0x%016llx\n", count, ptr, value, expected); } static uint64_t* HSS_MemTestAddressBus(volatile uint64_t *baseAddr, const size_t numBytes) { const size_t numWords = numBytes / sizeof(uint64_t); const size_t addrMask = numWords - 1u; size_t offset; size_t testOffset; uint64_t* result = NULL; uint8_t rx_char; const uint64_t pattern = (uint64_t)0xAAAAAAAAAAAAAAAAu; const uint64_t antiPattern = (uint64_t)0x5555555555555555u; // Walking up address bus, setting cells to pattern for (offset = 1u; (offset & addrMask) != 0u; offset <<= 1) { baseAddr[offset] = pattern; if (uart_getchar(&rx_char, 0, false) && ((rx_char == '\003') || (rx_char == '\033'))) { goto do_return; } } testOffset = 0u; baseAddr[0] = antiPattern; // Walking up address bus, verifying set cells for (offset = 1u; (offset & addrMask) != 0u; offset <<= 1) { if (baseAddr[offset] != pattern) { log_error_(1, baseAddr + offset, baseAddr[offset], pattern); result = ((uint64_t *)&baseAddr[offset]); break; } if (uart_getchar(&rx_char, 0, false) && ((rx_char == '\003') || (rx_char == '\033'))) { goto do_return; } } baseAddr[0] = pattern; // Walking up address bus, setting cells to antipattern if (result == NULL) { for (testOffset = 1u; (testOffset & addrMask) != 0u; testOffset <<= 1) { baseAddr[testOffset] = antiPattern; // ensure that the base isn't affected if (baseAddr[0] != pattern) { log_error_(2, baseAddr + offset, baseAddr[offset], pattern); result = ((uint64_t *)&baseAddr[testOffset]); break; } if (result == NULL) { // walk up the address bus, ensuring that no other address is affected for (offset = 1u; (offset & addrMask) != 0u; offset <<= 1) { if ((baseAddr[offset] != pattern) && (offset != testOffset)) { log_error_(3, baseAddr + offset, baseAddr[offset], pattern); result = ((uint64_t *)&baseAddr[testOffset]); offset = 0u; testOffset = 0u; // terminate loops break; } } } // if okay, write the pattern back and move on if (result == NULL) { baseAddr[testOffset] = pattern; } if (uart_getchar(&rx_char, 0, false) && ((rx_char == '\003') || (rx_char == '\033'))) { goto do_return; } } } do_return: return result; } static uint64_t *HSS_MemTestDevice(volatile uint64_t *baseAddr, size_t numBytes) { size_t offset; size_t numWords = numBytes / sizeof(uint64_t); uint64_t* result = NULL; uint64_t pattern; uint64_t antiPattern; uint8_t rx_char; // write pattern to every cell mHSS_FANCY_PRINTF(LOG_NORMAL, "Write Seed Pattern to all cells\n"); for (pattern = 1u, offset = 0u; offset < numWords; pattern++, offset++) { baseAddr[offset] = pattern; HSS_ShowProgress(numWords, numWords - offset); if (uart_getchar(&rx_char, 0, false) && ((rx_char == '\003') || (rx_char == '\033'))) { goto do_return; } } HSS_ShowProgress(numWords, 0u); // clear progress indicator // check each location for pass, and ... mHSS_FANCY_PRINTF(LOG_NORMAL, "First Pass: Check each location\n"); for (pattern = 1u, offset = 0u; offset < numWords; pattern++, offset++) { if (baseAddr[offset] != pattern) { log_error_(4, baseAddr + offset, baseAddr[offset], pattern); result = ((uint64_t *)&baseAddr[offset]); offset = numWords; break; } // if okay, invert the pattern if (result == NULL) { antiPattern = ~pattern; baseAddr[offset] = antiPattern; } HSS_ShowProgress(numWords, numWords - offset); if (uart_getchar(&rx_char, 0, false) && ((rx_char == '\003') || (rx_char == '\033'))) { goto do_return; } } HSS_ShowProgress(numWords, 0u); // clear progress indicator // check each location for the inverted pattern mHSS_FANCY_PRINTF(LOG_NORMAL, "Second Pass: Check each location\n"); if (result == NULL) { for (pattern = 1u, offset = 0u; offset < numWords; pattern++, offset++) { antiPattern = ~pattern; if (baseAddr[offset] != antiPattern) { log_error_(5, baseAddr + offset, baseAddr[offset], pattern); result = ((uint64_t *)&baseAddr[offset]); break; } HSS_ShowProgress(numWords, numWords - offset); if (uart_getchar(&rx_char, 0, false) && ((rx_char == '\003') || (rx_char == '\033'))) { goto do_return; } } } do_return: HSS_ShowProgress(numWords, 0u); // clear progress indicator return result; } // // // #define mMiB_IN_BYTES (1024llu * 1024llu) #include "ddr_service.h" bool HSS_MemTestDDRFast(void) { bool result = true; mHSS_FANCY_PRINTF(LOG_NORMAL, "DDR-Lo size is % 4lu MiB\n", (uint32_t)(HSS_DDR_GetSize()/mMiB_IN_BYTES)); static int perf_ctr_index_mem32 = PERF_CTR_UNINITIALIZED; static int perf_ctr_index_mem64 = PERF_CTR_UNINITIALIZED; HSS_PerfCtr_Allocate(&perf_ctr_index_mem32, "MemTest(DDR32)"); if ((HSS_MemTestDataBus((uint64_t *)HSS_DDR_GetStart()) != 0u) || (HSS_MemTestAddressBus((uint64_t *)HSS_DDR_GetStart(), HSS_DDR_GetSize()) != NULL)) { result = false; } HSS_PerfCtr_Lap(perf_ctr_index_mem32); mHSS_FANCY_PRINTF(LOG_NORMAL, "DDR-Hi size is % 4lu MiB\n", (uint32_t)(HSS_DDRHi_GetSize()/mMiB_IN_BYTES)); HSS_PerfCtr_Allocate(&perf_ctr_index_mem64, "MemTest(DDR64)"); if ((HSS_MemTestDataBus((uint64_t *)HSS_DDRHi_GetStart()) != 0u) || (HSS_MemTestAddressBus((uint64_t *)HSS_DDRHi_GetStart(), HSS_DDRHi_GetSize()) != NULL)) { result = false; } HSS_PerfCtr_Lap(perf_ctr_index_mem64); return result; } bool HSS_MemTestDDRFull(void) { bool result = HSS_MemTestDDRFast(); if (result) { if (HSS_MemTestDevice((uint64_t *)HSS_DDR_GetStart(), HSS_DDR_GetSize()) != NULL) { mHSS_FANCY_PRINTF(LOG_ERROR, "FAILED!\n"); result = false; } } return result; } bool HSS_MemTestDDR_Ex(volatile uint64_t *baseAddr, size_t numBytes) { bool result = true; if ((HSS_MemTestDataBus(baseAddr) != 0u) || (HSS_MemTestAddressBus(baseAddr, numBytes) != NULL) || (HSS_MemTestDevice(baseAddr, numBytes) != NULL)) { mHSS_FANCY_PRINTF(LOG_ERROR, "FAILED!\n"); result = false; } return result; } hart-software-services-2022.10/modules/misc/hss_progress.c000066400000000000000000000035371432224323300235650ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Progress output utility for long-running functions * \brief Progress output utility for long-running functions * */ #include "config.h" #include "hss_types.h" #include "uart_helper.h" #include "hss_debug.h" #include "hss_progress.h" void HSS_ShowProgress(size_t totalNumTasks, size_t numTasksRemaining) { static uint32_t oldProgressPercent = 101u; uint32_t progressPercent = (uint32_t)(((totalNumTasks - numTasksRemaining) * 100u) / totalNumTasks); if (progressPercent == 100u) { mHSS_PUTS(" \r"); } else if (oldProgressPercent != progressPercent) { mHSS_PRINTF(" % 3u%%", progressPercent); mHSS_PUTS(" ["); const uint8_t scale = 2u; uint8_t done = progressPercent/scale; uint8_t toDo = (100u)/scale - done; for (uint8_t i = 0u; i < done; i++) { mHSS_PUTS("\033[48;5;11m \033[0m"); } for (uint8_t i = 0u; i < toDo; i++) { mHSS_PUTC('.'); } mHSS_PUTS("]\r"); oldProgressPercent = progressPercent; } } bool HSS_ShowTimeout(char const * const msg, uint32_t timeout_sec, uint8_t *pRcvBuf) { bool keyPressedFlag = false; mHSS_PUTS(msg); mHSS_PRINTF("Timeout in %u second%s\n", timeout_sec, timeout_sec == 1 ? "" : "s"); mHSS_PUTC('.'); if (uart_getchar(pRcvBuf, timeout_sec, true)) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Character %u pressed\n", *pRcvBuf); if (*pRcvBuf != 27) { // ESC => done keyPressedFlag = true; } } mHSS_PUTS("\n"); return keyPressedFlag; } hart-software-services-2022.10/modules/misc/stack_guard.c000066400000000000000000000026431432224323300233300ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Stack Checking guard functions * \brief Stack Checking guard functions */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" const unsigned long __stack_chk_guard = 0xDEAD0BAD; void __stack_chk_guard_setup(void); void __stack_chk_fail(void); __attribute__((weak)) void __stack_chk_guard_setup(void) { //__stack_chk_guard is already set-up as 0xDEAD0BAD } __attribute__((weak)) void __stack_chk_fail(void) { // Print a canary to know that we've had stack corruption... // // to help debug this, it might help to disable the print statement // once stack corruption is detected... mHSS_DEBUG_PUTS("__stack_chk_fail(): stack corruption detected!!\n"); asm("ebreak"); } #ifdef __linux // if using the Linux compiler, we might need __memset_chk() also #include // for memset void* __memset_chk(void *dst, int c, size_t len, size_t dstlen); __attribute__((weak)) void* __memset_chk(void *dst, int c, size_t len, size_t dstlen) { void * result = NULL; if (dstlen < len) { mHSS_DEBUG_PUTS("__memset_chk(): dstlen < len!!\n"); asm("ebreak"); } else { result = memset(dst, c, len); } return result; } #endif hart-software-services-2022.10/modules/misc/strlen.c000066400000000000000000000011321432224323300223400ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! \file strlen \brief Local trivial implementation of strlen */ #include "config.h" #include /*! * \brief Calculate length of string * * Returns number of bytes in a string, excluding the null terminator. */ size_t strlen (const char *string) { size_t result = 0; while (*string) { string++; result++; } return result; } hart-software-services-2022.10/modules/ssmb/000077500000000000000000000000001432224323300207015ustar00rootroot00000000000000hart-software-services-2022.10/modules/ssmb/Kconfig000066400000000000000000000016311432224323300222050ustar00rootroot00000000000000menu "SSMB Options" config HSS_USE_IHC bool "IHC Support" default y depends on USE_IHC help This feature enables support for signalling to the E51 monitor core via IHC. The alternative is to use a shared memory buffer and IPIs for signalling. If you don't know what to do here, say Y. config IPI_MAX_NUM_QUEUE_MESSAGES int "Maximum number of outstanding IPI queue messages" default 128 help This feature determines the maximum number of queue messages supported for IPIs from different harts. config IPI_FIXED_BASE bool "Fix IPI Base address" default n help Use a fixed base address for the IPI-based Secure Signalling Message Bus. If you don't know what to do here, say N. config IPI_BASE_ADDR hex "Base address for IPI Queueus" default 0xC0000000 depends on IPI_FIXED_BASE help Specify the fixed base address for the IPI-based Secure Signalling Message Bus. endmenu hart-software-services-2022.10/modules/ssmb/Makefile000066400000000000000000000023421432224323300223420ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Secure Software Messaging Bus over IPIs # include modules/ssmb/ipi/Makefile hart-software-services-2022.10/modules/ssmb/ipi/000077500000000000000000000000001432224323300214625ustar00rootroot00000000000000hart-software-services-2022.10/modules/ssmb/ipi/Makefile000066400000000000000000000025041432224323300231230ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Secure Software Messaging Bus over IPIs SRCS-y += \ modules/ssmb/ipi/ssmb_ipi.c \ INCLUDES +=\ -Imodules/ssmb/ipi \ modules/ssmb/ipi/ssmb_ipi.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/modules/ssmb/ipi/ssmb_ipi.c000066400000000000000000000530101432224323300234320ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file SSMB Core * \brief SSMB Core Definitions */ #include "config.h" #include "hss_types.h" #ifndef CONFIG_OPENSBI # ifdef __riscv # include # include # endif #else #endif #include "ssmb_ipi.h" #include "hss_debug.h" #include "mpfs_reg_map.h" #include "csr_helper.h" #include "hss_state_machine.h" #include "hss_registry.h" #include "hss_atomic.h" #if IS_ENABLED(CONFIG_HSS_USE_IHC) # include "miv_ihc.h" #endif #include #include ///////////////////////////////////////////////////////////////////////////// // IPI queues - to be placed at well known address in memory and PMP protected #define SIZE_OF_IPI_QUEUES (sizeof(struct IPI_Outbox_Queue) * IPI_OUTBOX_NUM_QUEUES) #define SIZE_OF_IPI_COMPLETES (sizeof(struct IPI_Complete) * IPI_MAX_NUM_OUTSTANDING_COMPLETES) #define IPI_VERSION (0x0101u) ///////////////////////////////////////////////////////////////////////////// struct IPI_Data { uint32_t ipi_version; struct IPI_Outbox_Queue ipi_queues[IPI_OUTBOX_NUM_QUEUES]; struct IPI_Complete ipi_completes[IPI_MAX_NUM_OUTSTANDING_COMPLETES]; struct { TxId_t last[IPI_OUTBOX_NUM_QUEUES]; TxId_t shadow[IPI_OUTBOX_NUM_QUEUES]; } txId_per_queue; TxId_t my_transaction_id[MAX_NUM_HARTS]; struct { size_t message_allocs; size_t message_delivers; size_t message_frees; size_t consume_intents; size_t ipi_sends; //size_t msg_types[IPI_MSG_NUM_MSG_TYPES]; } mpfs_ipi_privateData[MAX_NUM_HARTS]; }; #define IPI_SIZE sizeof(struct IPI_Data) #if IS_ENABLED(CONFIG_IPI_FIXED_BASE_ADDR) static struct IPI_Data *ipi_data = (struct IPI_Data *)CONFIG_IPI_FIXED_BASE_ADDR; # define IPI_DATA (*ipi_data) #else static struct IPI_Data ipi_data_array; static struct IPI_Data *ipi_data = (struct IPI_Data *)&ipi_data_array; # define IPI_DATA (*ipi_data) #endif #if IS_ENABLED(CONFIG_DEBUG_MSCGEN_IPI) __extension__ static const char * const hartName[] = { // MAX_NUM_HARTS [ HSS_HART_E51 ] = "E51", [ HSS_HART_U54_1 ] = "U54_1", [ HSS_HART_U54_2 ] = "U54_2", [ HSS_HART_U54_3 ] = "U54_3", [ HSS_HART_U54_4 ] = "U54_4" }; __extension__ static const char * const ipiName[] = { // IPI_MSG_NUM_MSG_TYPES [ IPI_MSG_NO_MESSAGE ] = "IPI_MSG_NO_MESSAGE", [ IPI_MSG_BOOT_REQUEST ] = "IPI_MSG_BOOT_REQUEST", [ IPI_MSG_PMP_SETUP ] = "IPI_MSG_PMP_SETUP", [ IPI_MSG_SPI_XFER ] = "IPI_MSG_SPI_XFER", [ IPI_MSG_NET_RXPOLL ] = "IPI_MSG_NET_RXPOLL", [ IPI_MSG_NET_TX ] = "IPI_MSG_NET_TX", [ IPI_MSG_SCATTERGATHER_DMA ] = "IPI_MSG_SCATTERGATHER_DMA", [ IPI_MSG_WDOG_INIT ] = "IPI_MSG_WDOG_INIT", [ IPI_MSG_GPIO_SET ] = "IPI_MSG_GPIO_SET", [ IPI_MSG_UART_TX ] = "IPI_MSG_UART_TX", [ IPI_MSG_UART_POLL_RX ] = "IPI_MSG_UART_POLL_RX", [ IPI_MSG_POWERMODE ] = "IPI_MSG_POWERMODE", [ IPI_MSG_ACK_PENDING ] = "IPI_MSG_ACK_PENDING", [ IPI_MSG_ACK_COMPLETE ] = "IPI_MSG_ACK_COMPLETE", [ IPI_MSG_HALT ] = "IPI_MSG_HALT", [ IPI_MSG_CONTINUE ] = "IPI_MSG_CONTINUE", [ IPI_MSG_GOTO ] = "IPI_MSG_GOTO", [ IPI_MSG_OPENSBI_INIT ] = "IPI_MSG_OPENSBI_INIT" }; #endif ///////////////////////////////////////////////////////////////////////////// // // @brief Dump IPI Debug Statistics and Counters // void IPI_DebugDumpStats(void) { #if IS_ENABLED(CONFIG_DEBUG_IPI_STATS) || IS_ENABLED(CONFIG_SERVICE_TINYCLI) enum HSSHartId myHartId = current_hartid(); for (myHartId = HSS_HART_E51; myHartId < HSS_HART_NUM_PEERS; myHartId++) { mHSS_DEBUG_PRINTF(LOG_STATUS, "hartId: %u\n", myHartId); mHSS_DEBUG_PRINTF(LOG_STATUS, "message_allocs: %" PRIu64 "\n", IPI_DATA.mpfs_ipi_privateData[myHartId].message_allocs); mHSS_DEBUG_PRINTF(LOG_STATUS, "message_delivers: %" PRIu64 "\n", IPI_DATA.mpfs_ipi_privateData[myHartId].message_delivers); mHSS_DEBUG_PRINTF(LOG_STATUS, "message_frees: %" PRIu64 "\n", IPI_DATA.mpfs_ipi_privateData[myHartId].message_allocs); mHSS_DEBUG_PRINTF(LOG_STATUS, "consume_intents: %" PRIu64 "\n", IPI_DATA.mpfs_ipi_privateData[myHartId].consume_intents); mHSS_DEBUG_PRINTF(LOG_STATUS, "ipi_sends: %" PRIu64 "\n\n", IPI_DATA.mpfs_ipi_privateData[myHartId].ipi_sends); } #endif } // // @brief Given a source hart and target hart, calculate the queue index which // represents its message traffic. // // The calculation logic here may be a little confusing, but in essence what it is // doing is mapping queue direction to index as follows: // // @verbatim // E51->U54_1 => 0, E51->U54_2 => 1, E51->U54_3 => 2, E51->U54_4 => 3 // U54_1->E51 => 4, U54_1->U54_2 => 5, U54_1->U54_3 => 6, U54_1->U54_4 => 7 // U54_2->E51 => 8, U54_2->U54_1 => 9, U54_2->U54_3 => 10, U54_2->U54_4 => 11 // U54_3->E51 => 12, U54_3->U54_1 => 13, U54_3->U54_2 => 14, U54_3->U54_4 => 15 // U54_4->E51 => 16, U54_4->U54_1 => 17, U54_4->U54_2 => 18, U54_4->U53_4 => 19 // @endverbatim // // @param source [in] source hart from where the traffic will originate // @param target [in] target hart to where the traffic will be sent // @return uint32_t representing queue index // inline uint32_t IPI_CalculateQueueIndex(enum HSSHartId source, enum HSSHartId target) { uint32_t index = (source * 4u) + target; if (target > source) { index--; } return index; } // // @brief Get pending count of IPI messages on a particular queue // @param queueIndex [in] target queue // @return uint32_t representing the count of active messages // uint32_t IPI_GetQueuePendingCount(uint32_t queueIndex) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "called - queueIndex is %u, count is %u\n", queueIndex, // IPI_DATA.ipi_queues[queueIndex].count); return (IPI_DATA.ipi_queues[queueIndex].count); } // @brief Send an IPI to a particular target hart // @param target [in] target hart to send an IPI to // @return bool indicating success // static bool clint_set_MSIP(enum HSSHartId const target, uint32_t value) { bool result = true; switch (target) { case HSS_HART_E51: mHSS_WriteRegU32(CLINT, MSIP_E51_0, value); break; case HSS_HART_U54_1: mHSS_WriteRegU32(CLINT, MSIP_U54_1, value); break; case HSS_HART_U54_2: mHSS_WriteRegU32(CLINT, MSIP_U54_2, value); break; case HSS_HART_U54_3: mHSS_WriteRegU32(CLINT, MSIP_U54_3, value); break; case HSS_HART_U54_4: mHSS_WriteRegU32(CLINT, MSIP_U54_4, value); break; default: assert((target >= HSS_HART_E51) && (target <= HSS_HART_U54_4)); result = false; } return result; } bool CLINT_Raise_MSIP(enum HSSHartId const target) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "sending IPI to %u\n", target); bool result = clint_set_MSIP(target, 1u); if (result) { IPI_DATA.mpfs_ipi_privateData[target].ipi_sends++; } return result; } // @brief Clear the MSIP bit of a particular target hart // @param target [in] target hart to send an IPI to // void CLINT_Clear_MSIP(enum HSSHartId const target) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "clearing IPI on %u\n", target); (void)clint_set_MSIP(target, 0u); } // // @brief Given a source hart and target hart, find a pointer to the first message in its queue // @param source [in] source hart from where the traffic will originate // @param target [in] target hart to where the traffic will be sent // @return IPI_Outbox_Msg * pointer to first message in the queue // inline struct IPI_Outbox_Msg *IPI_DirectionToFirstMsgInQueue(enum HSSHartId source, enum HSSHartId target) { assert(target < HSS_HART_NUM_PEERS); assert(target != source); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Resolved (%d, %d) to index %u\n", source, target, index); //mHSS_DEBUG_PRINTF(WARN, "WARNING: queue %u is %u\n", index, // IPI_DATA.ipi_queues[index].count); uint32_t index = IPI_CalculateQueueIndex(source, target); struct IPI_Outbox_Msg *pMsgResult = &(IPI_DATA.ipi_queues[index].msgQ[0]); return pMsgResult; } // // @brief Given a source hart and target hart, find a pointer to the first message in its queue // @param target [in] target hart to where the traffic will be sent // @param message [in] HSS Message Type // @param transaction_id [in] Transaction Identifier // @param immediate_arg [in] Optional uint32_t immediate argument // @param p_extended_buffer_in_ddr [in] Optional pointer to extended buffer in memory // @param p_ancilliar_buffer_in_ddr [in] Optional pointer to ancilliary buffer in memory // @return bool indicating message was sent okay // bool IPI_Send(enum HSSHartId target, enum IPIMessagesEnum message, TxId_t transaction_id, uint32_t immediate_arg, void const *p_extended_buffer_in_ddr, void const *p_ancilliary_buffer_in_ddr) { bool result = false; uint32_t i = 0u; //mHSS_DEBUG_PRINTF(LOG_NORMAL, "called with message type of %u to %d\n", message, target); // find where to put the message uint32_t index = IPI_CalculateQueueIndex(current_hartid(), target); struct IPI_Outbox_Msg *pMsg = &(IPI_DATA.ipi_queues[index].msgQ[0]); bool space_available = false; assert(pMsg != NULL); for (i = 0u; i < IPI_MAX_NUM_QUEUE_MESSAGES; i++) { if (pMsg->msg_type == IPI_MSG_NO_MESSAGE) { space_available = true; break; } else { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "pMsg: %p, index: %u, msg_type: %u\n", pMsg, i, pMsg->msg_type); } pMsg++; } if (space_available) { pMsg->msg_type = message; pMsg->transaction_id = transaction_id; pMsg->p_extended_buffer_in_ddr = (void *)p_extended_buffer_in_ddr; pMsg->p_ancilliary_buffer_in_ddr = (void *)p_ancilliary_buffer_in_ddr; pMsg->immediate_arg = immediate_arg; IPI_DATA.txId_per_queue.last[index] = transaction_id; #if IS_ENABLED(CONFIG_HSS_USE_IHC) const uint32_t hss_message[] = { (uint32_t)message, (uint32_t)transaction_id, 0x0, 0x0 }; uint32_t tx_status = IHC_tx_message_from_hart((IHC_CHANNEL)target, (uint32_t *)&hss_message); if (tx_status == MESSAGE_SENT) { result = true; } #else result = CLINT_Raise_MSIP(target); #endif } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "No space in queue!!!!!!\n"); } #if IS_ENABLED(CONFIG_DEBUG_MSCGEN_IPI) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "::mscgen: %s->%s %s %u %u %p %p\n", hartName[current_hartid()], hartName[target], ipiName[message], transaction_id, immediate_arg, p_extended_buffer_in_ddr, p_ancilliary_buffer_in_ddr); } #endif return result; } // // @brief Polled incoming IPI queues and counts messages // @param target [in] target hart to where the traffic will be sent // @param message [in] HSS Message Type // @param transaction_id [in] Transaction Identifier // @param immediate_arg [in] Optional uint32_t immediate argument // @param p_extended_buffer_in_ddr [in] Optional pointer to extended buffer in memory // @return bool indicating queue messages have changed // bool IPI_PollReceive(union HSSHartBitmask hartMask) { bool result = false; uint32_t i; (void)hartMask; enum HSSHartId const myHartId = current_hartid(); for (i = 0u; i < MAX_NUM_HARTS; i++) { #if IS_ENABLED(CONFIG_HSS_USE_IHC) IHC_message_present_poll(); __sync_synchronize(); #endif if (i == myHartId) { continue; } // don't handle messages if to my own hartid if (!((1u << i) & hartMask.uint)) { continue; } // only look at selected harts // myHartId => target, i => source uint32_t const index = IPI_CalculateQueueIndex(i, myHartId); if (IPI_DATA.txId_per_queue.shadow[index] == IPI_DATA.txId_per_queue.last[index]) { // nothing new since last time, so continue continue; } else { IPI_DATA.txId_per_queue.shadow[index] = IPI_DATA.txId_per_queue.last[index]; uint32_t countPerQueue = 0u; uint32_t j; for (j = 0u; j < IPI_MAX_NUM_QUEUE_MESSAGES; j++) { if (IPI_DATA.ipi_queues[index].msgQ[j].msg_type != IPI_MSG_NO_MESSAGE) { result = true; // incoming message to handle countPerQueue++; //if (result) { mHSS_DEBUG_PRINTF(NLOG_ORMAL, "q(%u)/msg(%u): received IPI (type %d)" // "\n", index, j, IPI_DATA.ipi_queues[index].msgQ[j].msg_type); } } } IPI_DATA.ipi_queues[index].count = countPerQueue; result = true; } } return result; } bool IPI_ConsumeIntent(enum HSSHartId source, enum IPIMessagesEnum msg_type) { bool intentFound = false; enum HSSHartId const myHartId = current_hartid(); //uint32_t index = IPI_CalculateQueueIndex(source, myHartId); //if (IPI_GetQueuePendingCount(index)) { { // find appropriate starting point uint32_t const index = IPI_CalculateQueueIndex(source, myHartId); struct IPI_Outbox_Msg *pMsg = &(IPI_DATA.ipi_queues[index].msgQ[0]); IPI_handlerFunction pHandler = NULL; assert(pMsg != NULL); // search for handler function... uint32_t j=0u; // direct look-up for speed into the table // to make this safer, we'll ensure its within range, and we'll also // assert that it is the correct handler type... { assert(msg_type < spanOfIpiRegistry); assert(msg_type == ipiRegistry[msg_type].msg_type); if ((msg_type < spanOfIpiRegistry) && (msg_type == ipiRegistry[msg_type].msg_type)) { pHandler = ipiRegistry[msg_type].handler; } } // check the queue for a message of the required type for (j = 0u; j < IPI_MAX_NUM_QUEUE_MESSAGES; j++) { if (pMsg->msg_type == msg_type) { #if IS_ENABLED(CONFIG_DEBUG_MSCGEN_IPI) mHSS_DEBUG_PRINTF(LOG_NORMAL, "::mscgen: %s->%s %s %u %u %p %p\n", hartName[source], hartName[current_hartid()], ipiName[msg_type], pMsg->transaction_id, pMsg->immediate_arg, pMsg->p_extended_buffer_in_ddr, pMsg->p_ancilliary_buffer_in_ddr); #endif if (!pHandler) { // ensure we don't fill up queue with unhandlable messages mHSS_DEBUG_PRINTF(LOG_ERROR, "no handler found for IPI of type %u, force clearing\n", msg_type); pMsg->msg_type = IPI_MSG_NO_MESSAGE; } else { intentFound = true; break; } } pMsg++; } // if we found the intent we were looking for, and also have a valid handler for it // process the intent and generate any return ACK packets to the peer if necessary // if (pHandler && intentFound) { enum IPIStatusCode result; assert(pHandler != NULL); IPI_DATA.mpfs_ipi_privateData[current_hartid()].consume_intents++; result = (*pHandler)(pMsg->transaction_id, source, pMsg->immediate_arg, pMsg->p_extended_buffer_in_ddr, pMsg->p_ancilliary_buffer_in_ddr); switch (pMsg->msg_type) { case IPI_MSG_ACK_COMPLETE: break; case IPI_MSG_ACK_PENDING: break; default: switch (result) { case IPI_SUCCESS: //mHSS_DEBUG_PRINTF(LOG_NORMAL, "sending ACK_COMPLETE on txId %u\n", // pMsg->transaction_id); IPI_Send(source, IPI_MSG_ACK_COMPLETE, pMsg->transaction_id, IPI_SUCCESS, NULL, NULL); break; case IPI_PENDING: IPI_Send(source, IPI_MSG_ACK_PENDING, pMsg->transaction_id, IPI_PENDING, NULL, NULL); break; default: case IPI_FAIL: IPI_Send(source, IPI_MSG_ACK_COMPLETE, pMsg->transaction_id, IPI_FAIL, NULL, NULL); break; case IPI_IDLE: // nothing to do - for example, state machine might want to send response // itself, or no response break; } } pMsg->msg_type = IPI_MSG_NO_MESSAGE; } } if (!intentFound) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "did not find IPI of type %u\n", msg_type); } return intentFound; } #if IS_ENABLED(CONFIG_IPI_FIXED_BASE_ADDR) extern unsigned long _hss_start, _hss_end; static bool check_if_ipi_queues_overlap_hss(void) { return (((char *)CONFIG_IPI_FIXED_BASE_ADDR + IPI_SIZE) >= (char *)&_hss_start) && ((char *)CONFIG_IPI_FIXED_BASE_ADDR <= (char *)&_hss_end); } #endif bool IPI_QueuesInit(void) { #if IS_ENABLED(CONFIG_DEBUG_MSCGEN_IPI) assert(ARRAY_SIZE(hartName) == MAX_NUM_HARTS); assert(ARRAY_SIZE(ipiName) == IPI_MSG_NUM_MSG_TYPES); #endif #if IS_ENABLED(CONFIG_IPI_FIXED_BASE_ADDR) mHSS_DEBUG_PRINTF(LOG_NORMAL, "IPI Queues: %p to %p\n", (char *)CONFIG_IPI_FIXED_BASE_ADDR, (char*)CONFIG_IPI_FIXED_BASE_ADDR + IPI_SIZE); assert(check_if_ipi_queues_overlap_hss() == false); #endif mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initializing IPI Queues (%lu bytes @ %p)...\n", sizeof(struct IPI_Data), (void *)&IPI_DATA); memset((void *)ipi_data, 0, sizeof(struct IPI_Data)); for (unsigned int i = 0u; i < MAX_NUM_HARTS; i++) { IPI_DATA.my_transaction_id[i] = 1u; } IPI_DATA.ipi_version = IPI_VERSION; return true; } bool IPI_MessageAlloc(uint32_t *indexOut) { uint32_t index; bool result = false; assert(indexOut != NULL); for (index = 0u; index < IPI_MAX_NUM_OUTSTANDING_COMPLETES; index++) { if (!IPI_DATA.ipi_completes[index].used) { IPI_DATA.ipi_completes[index].used = true; IPI_DATA.ipi_completes[index].transaction_id = IPI_DATA.my_transaction_id[current_hartid()];; IPI_DATA.ipi_completes[index].status = IPI_PENDING; IPI_DATA.my_transaction_id[current_hartid()]++; result = true; *indexOut = index; break; } } if (result) { IPI_DATA.mpfs_ipi_privateData[current_hartid()].message_allocs++; } return result; } bool IPI_MessageDeliver(uint32_t index, enum HSSHartId target, enum IPIMessagesEnum message, uint32_t immediate_arg, void const *p_extended_buffer_in_ddr, void const *p_ancilliary_buffer_in_ddr) { bool result = false; assert(index < IPI_MAX_NUM_OUTSTANDING_COMPLETES); if ((index < IPI_MAX_NUM_OUTSTANDING_COMPLETES) && (IPI_DATA.ipi_completes[index].used)) { result = IPI_Send(target, message, IPI_DATA.ipi_completes[index].transaction_id, immediate_arg, p_extended_buffer_in_ddr, p_ancilliary_buffer_in_ddr); } if (result) { IPI_DATA.mpfs_ipi_privateData[current_hartid()].message_delivers++; } return result; } bool IPI_MessageCheckIfComplete(uint32_t index) { bool result = false; assert(index <= IPI_MAX_NUM_OUTSTANDING_COMPLETES); if (index == IPI_MAX_NUM_OUTSTANDING_COMPLETES) { result = true; } else if ((index < IPI_MAX_NUM_OUTSTANDING_COMPLETES) && (IPI_DATA.ipi_completes[index].used)) { switch (IPI_DATA.ipi_completes[index].status) { case IPI_PENDING: result = false; break; case IPI_SUCCESS: __attribute__((fallthrough)); // deliberate fallthrough case IPI_IDLE: __attribute__((fallthrough)); // deliberate fallthrough case IPI_FAIL: __attribute__((fallthrough)); // deliberate fallthrough default: result = true; break; } } return result; } bool IPI_MessageUpdateStatus(TxId_t transaction_id, enum IPIStatusCode status) { bool result = false; uint32_t index; for (index = 0u; index < IPI_MAX_NUM_OUTSTANDING_COMPLETES; index++) { if (IPI_DATA.ipi_completes[index].transaction_id == transaction_id) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "index is %u, TxId is %u, status is %d\n", // index, transaction_id, status); IPI_DATA.ipi_completes[index].status = status; result = true; break; } } return result; } void IPI_MessageFree(uint32_t index) { assert(IPI_DATA.ipi_completes[index].used); IPI_DATA.ipi_completes[index].used = false; IPI_DATA.mpfs_ipi_privateData[current_hartid()].message_frees++; //mHSS_DEBUG_PRINTF(LOG_NORMAL, "index is %u, TxId is %u\n", index, // IPI_DATA.ipi_completes[index].transaction_id); } TxId_t IPI_DebugGetTxId(void) { return IPI_DATA.my_transaction_id[current_hartid()]; } enum IPIStatusCode IPI_ACK_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { (void)source; (void)immediate_arg; (void)p_extended_buffer_in_ddr; (void)p_ancilliary_buffer_in_ddr; //mHSS_DEBUG_PRINTF(LOG_NORMAL, "freeing IPI\n"); IPI_MessageUpdateStatus(transaction_id, IPI_IDLE); // free the IPI return IPI_SUCCESS; } hart-software-services-2022.10/modules/ssmb/ipi/ssmb_ipi.h000066400000000000000000000131371432224323300234450ustar00rootroot00000000000000#ifndef HSS_SSMB_IPI_H #define HSS_SSMB_IPI_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Secure Software Message Bus IPI * */ /** * \file Secure Software Message Bus IPI * \brief SSMB Core Types/Defines/Declarations */ #ifdef __cplusplus extern "C" { #endif #include "config.h" #include "hss_types.h" #define IPI_MAX_NUM_QUEUE_MESSAGES ((unsigned long)CONFIG_IPI_MAX_NUM_QUEUE_MESSAGES) #define IPI_MAX_NUM_OUTSTANDING_COMPLETES (IPI_MAX_NUM_QUEUE_MESSAGES * (HSS_HART_NUM_PEERS-1u)) /** * \brief IPI Outbox Enumeration */ enum IPIOutboxEnum { IPI_OUTBOX_E51_TO_U54_1, IPI_OUTBOX_E51_TO_U54_2, IPI_OUTBOX_E51_TO_U54_3, IPI_OUTBOX_E51_TO_U54_4, IPI_OUTBOX_U54_1_TO_E51, IPI_OUTBOX_U54_1_TO_U54_2, IPI_OUTBOX_U54_1_TO_U54_3, IPI_OUTBOX_U54_1_TO_U54_4, IPI_OUTBOX_U54_2_TO_E51, IPI_OUTBOX_U54_2_TO_U54_1, IPI_OUTBOX_U54_2_TO_U54_3, IPI_OUTBOX_U54_2_TO_U54_4, IPI_OUTBOX_U54_3_TO_E51, IPI_OUTBOX_U54_3_TO_U54_1, IPI_OUTBOX_U54_3_TO_U54_2, IPI_OUTBOX_U54_3_TO_U54_4, IPI_OUTBOX_U54_4_TO_E51, IPI_OUTBOX_U54_4_TO_U54_1, IPI_OUTBOX_U54_4_TO_U54_2, IPI_OUTBOX_U54_4_TO_U54_3, IPI_OUTBOX_NUM_QUEUES }; #define IPI_PEER_CORE_TO_OFFSET(x) (x - HSS_HART_U54_1) /** * \brief IPI Message Types Enumeration */ enum IPIMessagesEnum { IPI_MSG_NO_MESSAGE, IPI_MSG_BOOT_REQUEST, IPI_MSG_PMP_SETUP, IPI_MSG_SPI_XFER, IPI_MSG_NET_RXPOLL, IPI_MSG_NET_TX, IPI_MSG_SCATTERGATHER_DMA, IPI_MSG_WDOG_INIT, IPI_MSG_GPIO_SET, IPI_MSG_UART_TX, IPI_MSG_UART_POLL_RX, IPI_MSG_POWERMODE, IPI_MSG_ACK_PENDING, IPI_MSG_ACK_COMPLETE, IPI_MSG_HALT, IPI_MSG_CONTINUE, IPI_MSG_GOTO, IPI_MSG_OPENSBI_INIT, IPI_MSG_NUM_MSG_TYPES, }; /** * \brief IPI Return Codes Type Enumeration */ enum IPIStatusCode { IPI_FAIL, IPI_SUCCESS, IPI_PENDING, IPI_IDLE, }; /** * \brief IPI Transaction Id Type */ typedef uint32_t TxId_t; typedef enum IPIStatusCode (*IPI_handlerFunction)(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); /** * \brief IPI Outbox Message Structure */ struct IPI_Outbox_Msg { enum IPIMessagesEnum msg_type; TxId_t transaction_id; uint32_t immediate_arg; void *p_extended_buffer_in_ddr; void *p_ancilliary_buffer_in_ddr; }; /** * \brief IPI Outbox Queue Structure */ struct IPI_Outbox_Queue { struct IPI_Outbox_Msg msgQ[IPI_MAX_NUM_QUEUE_MESSAGES]; uint32_t count; }; struct IPI_Complete { bool used; TxId_t transaction_id; enum IPIStatusCode status; }; /** * \brief IPI Handler Descriptor * * Maps message type to handler function pointer */ struct IPI_Handler { enum IPIMessagesEnum msg_type; IPI_handlerFunction handler; }; // ------------------------------------------------------------------------ // PUBLIC API // bool IPI_Send(enum HSSHartId target, enum IPIMessagesEnum message, TxId_t transaction_id, uint32_t immediate_arg, void const *p_extended_buffer_in_ddr, void const *p_ancilliary_buffer_in_ddr); bool IPI_PollReceive(union HSSHartBitmask hartMask); bool IPI_QueuesInit(void); bool IPI_ConsumeIntent(enum HSSHartId source, enum IPIMessagesEnum msg_type); uint32_t IPI_GetQueuePendingCount(uint32_t queueIndex); bool IPI_MessageAlloc(uint32_t *indexOut); bool IPI_MessageDeliver(uint32_t index, enum HSSHartId target, enum IPIMessagesEnum message, uint32_t immediate_arg, void const *p_extended_buffer_in_ddr, void const *p_ancilliary_buffer_in_ddr); bool IPI_MessageUpdateStatus(TxId_t transaction_id, enum IPIStatusCode status); bool IPI_MessageCheckIfComplete(uint32_t index); void IPI_MessageFree(uint32_t index); TxId_t IPI_DebugGetTxId(void); void IPI_DebugDumpStats(void); struct IPI_Outbox_Msg *IPI_DirectionToFirstMsgInQueue(enum HSSHartId source, enum HSSHartId target); uint32_t IPI_CalculateQueueIndex(enum HSSHartId source, enum HSSHartId target); /* handler for ACKs and PENDINGs */ enum IPIStatusCode IPI_ACK_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); /* helpers for setting and clearing MSIP */ bool CLINT_Raise_MSIP(enum HSSHartId const target); void CLINT_Clear_MSIP(enum HSSHartId const target); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/000077500000000000000000000000001432224323300201105ustar00rootroot00000000000000hart-software-services-2022.10/services/Kconfig000066400000000000000000000011341432224323300214120ustar00rootroot00000000000000menu "Services" source "services/beu/Kconfig" source "services/boot/Kconfig" source "services/crypto/Kconfig" source "services/ddr/Kconfig" source "services/goto/Kconfig" source "services/ipi_poll/Kconfig" source "services/mmc/Kconfig" source "services/opensbi/Kconfig" source "services/powermode/Kconfig" source "services/qspi/Kconfig" source "services/scrub/Kconfig" source "services/sgdma/Kconfig" source "services/spi/Kconfig" source "services/tinycli/Kconfig" source "services/uart/Kconfig" source "services/usbdmsc/Kconfig" source "services/wdog/Kconfig" source "services/ymodem/Kconfig" endmenu hart-software-services-2022.10/services/Makefile000066400000000000000000000033421432224323300215520ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Services include services/beu/Makefile include services/boot/Makefile include services/crypto/Makefile include services/ddr/Makefile include services/goto/Makefile include services/ipi_poll/Makefile include services/mmc/Makefile include services/opensbi/Makefile include services/powermode/Makefile include services/qspi/Makefile include services/scrub/Makefile include services/sgdma/Makefile include services/spi/Makefile include services/tinycli/Makefile include services/uart/Makefile include services/usbdmsc/Makefile include services/wdog/Makefile include services/ymodem/Makefile hart-software-services-2022.10/services/beu/000077500000000000000000000000001432224323300206635ustar00rootroot00000000000000hart-software-services-2022.10/services/beu/Kconfig000066400000000000000000000003131432224323300221630ustar00rootroot00000000000000config SERVICE_BEU bool "Bus Error Unit support" default n help This feature enables support for E51-delegated Bus Error Unit monitoring. If you do not know what to do here, say Y. hart-software-services-2022.10/services/beu/Makefile000066400000000000000000000024261432224323300223270ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Bus Error Unit Monitor Service SRCS-$(CONFIG_SERVICE_BEU) += \ services/beu/beu_service.c \ INCLUDES +=\ -I./services/beu \ hart-software-services-2022.10/services/beu/beu_service.c000066400000000000000000000152551432224323300233320ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file BEU Monitor State Machine * \brief E51-Assisted BEU Monitor */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_boot_pmp.h" #include "ssmb_ipi.h" #include #include #include "hss_memcpy_via_pdma.h" #include "beu_service.h" #include "sbi_bitops.h" #include "mss_hart_ints.h" #ifndef BIT # define BIT(nr) (1UL << (nr)) #endif static void beu_init_handler(struct StateMachine * const pMyMachine); static void beu_monitoring_handler(struct StateMachine * const pMyMachine); /*! * \brief BEU Driver States */ enum BeuStatesEnum { BEU_INITIALIZATION, BEU_MONITORING, BEU_NUM_STATES = BEU_MONITORING+1 }; /*! * \brief BEU Driver State Descriptors */ static const struct StateDesc beu_state_descs[] = { { (const stateType_t)BEU_INITIALIZATION, (const char *)"init", NULL, NULL, &beu_init_handler }, { (const stateType_t)BEU_MONITORING, (const char *)"monitoring", NULL, NULL, &beu_monitoring_handler }, }; /*! * \brief BEU Driver State Machine */ struct StateMachine beu_service = { .state = (stateType_t)BEU_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)BEU_NUM_STATES, .pMachineName = (const char *)"beu_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = beu_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = NULL }; // BEU Events: // // +-------+-----------------------------------------------------| // | Cause | Meaning | // +-------+-----------------------------------------------------| // | 0 | No error | // | 1 | Reserved | // | 2 | Instruction cache or ITM correctable error | // | 3 | ITIM uncorrectable ECC error | // | 4 | Reserved | // | 5 | Load or store TileLink bus error | // | 6 | Data cache correctable ECC error | // | 7 | Data cache uncorrectalbe ECC error | // +-------+-----------------------------------------------------| // enum BEU_Event_Cause { BEU_EVENT_NO_ERROR = 0, BEU_EVENT_RESEVERD1 = 1, BEU_EVENT_ITIM_CORRECTABLE = 2, BEU_EVENT_ITIM_UNCORRECTABLE = 3, BEU_EVENT_RESERVED2 = 4, BEU_EVENT_TILELINK_BUS_ERROR = 5, BEU_EVENT_DATA_CACHE_CORRECTABLE = 6, BEU_EVENT_DATA_CACHE_UNCORRECTABLE = 7, MAX_BEU_CAUSES = BEU_EVENT_DATA_CACHE_UNCORRECTABLE + 1 }; char const * const BEU_Event_Name[] = { [BEU_EVENT_NO_ERROR] = "No error", [BEU_EVENT_RESEVERD1] = "Reserved", [BEU_EVENT_ITIM_CORRECTABLE] = "Instruction cache or ITM correctable error", [BEU_EVENT_ITIM_UNCORRECTABLE] = "ITIM uncorrectable ECC error", [BEU_EVENT_RESERVED2] = "Reserved", [BEU_EVENT_TILELINK_BUS_ERROR] = "Load or store TileLink bus error", [BEU_EVENT_DATA_CACHE_CORRECTABLE] = "Data cache correctable ECC error", [BEU_EVENT_DATA_CACHE_UNCORRECTABLE] = "Data cache uncorrectable ECC error" }; const uint64_t BEU_ENABLE_MASK = (BIT(BEU_EVENT_ITIM_CORRECTABLE) | BIT(BEU_EVENT_ITIM_UNCORRECTABLE) | BIT(BEU_EVENT_TILELINK_BUS_ERROR) | BIT(BEU_EVENT_DATA_CACHE_CORRECTABLE) | BIT(BEU_EVENT_DATA_CACHE_UNCORRECTABLE)); const uint64_t BEU_ENABLE_UNCORRECTABLE_MASK = (BIT(BEU_EVENT_ITIM_UNCORRECTABLE) | BIT(BEU_EVENT_DATA_CACHE_UNCORRECTABLE)); static struct { const enum BEU_Event_Cause bit_position; char const * const pName; size_t counter; } beu_stats_[] = { { BEU_EVENT_ITIM_CORRECTABLE, BEU_Event_Name[BEU_EVENT_ITIM_CORRECTABLE], 0llu }, { BEU_EVENT_ITIM_UNCORRECTABLE, BEU_Event_Name[BEU_EVENT_ITIM_UNCORRECTABLE], 0llu }, { BEU_EVENT_TILELINK_BUS_ERROR, BEU_Event_Name[BEU_EVENT_TILELINK_BUS_ERROR], 0llu }, { BEU_EVENT_DATA_CACHE_CORRECTABLE, BEU_Event_Name[BEU_EVENT_DATA_CACHE_CORRECTABLE], 0llu }, { BEU_EVENT_DATA_CACHE_UNCORRECTABLE, BEU_Event_Name[BEU_EVENT_DATA_CACHE_UNCORRECTABLE], 0llu } }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void beu_init_handler(struct StateMachine * const pMyMachine) { for (enum HSSHartId hartid = HSS_HART_E51; hartid <= HSS_HART_U54_4; hartid++) { BEU->regs[hartid].ACCRUED = 0llu; BEU->regs[hartid].VALUE = 0llu; BEU->regs[hartid].ENABLE = (unsigned long long)BEU_ENABLE_MASK; } pMyMachine->state++; } ///////////////// static void beu_monitoring_handler(struct StateMachine * const pMyMachine) { (void)pMyMachine; static uint64_t shadow_accrued_[MAX_NUM_HARTS] = { 0llu, }; static uint64_t shadow_value_[MAX_NUM_HARTS] = { 0llu, }; for (enum HSSHartId hartid = HSS_HART_E51; hartid <= HSS_HART_U54_4; hartid++) { uint64_t accrued = BEU->regs[hartid].ACCRUED; uint64_t value = BEU->regs[hartid].VALUE; if (accrued & BEU_ENABLE_MASK) { if (accrued & BEU_ENABLE_UNCORRECTABLE_MASK) { if ((BEU->regs[hartid].ENABLE) && (value == shadow_value_[hartid])) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Uncorrectable errors: u54_%d - error %llu at %p\n", hartid, accrued, value); } // hart has experienced fatal error, so stop checking for BEU errors for this hart... BEU->regs[hartid].ENABLE = 0llu; } else { (void)(shadow_accrued_[hartid]); // reference to avoid compiler warning... } for (size_t i = 0u; i < ARRAY_SIZE(beu_stats_); i++) { if (accrued & BIT(beu_stats_[i].bit_position)) { beu_stats_[i].counter++; BEU->regs[hartid].ACCRUED &= ~(BIT(beu_stats_[i].bit_position)); } } shadow_accrued_[hartid] = accrued; shadow_value_[hartid] = value; } } } ///////////////// void HSS_BEU_DumpStats(void) { for (size_t i = 0u; i < ARRAY_SIZE(beu_stats_); i++) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "% 45s: %" PRIu64 "\n", beu_stats_[i].pName, beu_stats_[i].counter); } } hart-software-services-2022.10/services/beu/beu_service.h000066400000000000000000000032251432224323300233310ustar00rootroot00000000000000#ifndef HSS_BEU_SERVICE_H #define HSS_BEU_SERVICE_H /******************************************************************************* * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Bus Error Unit Service API * */ /*! * \file Bus Error Unit API * \brief Bus Error Unit State Machine API function declarations */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" extern struct StateMachine beu_service; void HSS_BEU_DumpStats(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/boot/000077500000000000000000000000001432224323300210535ustar00rootroot00000000000000hart-software-services-2022.10/services/boot/Kconfig000066400000000000000000000030511432224323300223550ustar00rootroot00000000000000config SERVICE_BOOT bool "Enable booting" default y select SERVICE_OPENSBI select SERVICE_DDR help This feature enables support for bootstrapping the U54 application harts. This is enabled by default. menu "Boot Service" visible if SERVICE_BOOT config SERVICE_BOOT_SPI_FLASH_OFFSET hex "Copy payload from SPI FLASH at offset" default 0x400 depends on SERVICE_SPI help This feature specifies the offset in SPI Flash where a boot image is stored. config SERVICE_BOOT_USE_PAYLOAD bool "Use Payload file" default n depends on SERVICE_BOOT help This feature enables booting a directly contained payload. config SERVICE_BOOT_CUSTOM_FLOW bool "Use Custom Boot Flow" default n depends on SERVICE_BOOT help This feature enables custom booting flow where all HARTs will jump to same entry point in M-mode. config SERVICE_BOOT_DDR_TARGET_ADDR hex "Target Base address for BOOT to DDR copy" default 0xA0000000 depends on SERVICE_BOOT help This feature specifies a scratch address for EMMC/QSPI decompression config SERVICE_BOOT_MMC_USE_GPT bool "Use GPT with MMC" default SERVICE_BOOT && SERVICE_MMC && y depends on SERVICE_MMC help If CONFIG_SERVICE_MMC is enabled, then for MMC boots this option enables parsing of a GUID Partition Table (GPT) in search of the boot image starting sector.. endmenu hart-software-services-2022.10/services/boot/Makefile000066400000000000000000000030111432224323300225060ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # U54 Boot Strapping Service SRCS-$(CONFIG_SERVICE_BOOT) += \ services/boot/hss_boot_service.c \ services/boot/hss_boot_pmp.c \ services/boot/gpt.c \ SRCS-$(CONFIG_CRYPTO_SIGNING) += \ services/boot/hss_boot_secure.c \ INCLUDES +=\ -I./services/boot \ services/boot/hss_boot_service.o: CFLAGS=$(CFLAGS_GCCEXT) services/boot/hss_boot_pmp.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/boot/gpt.c000066400000000000000000000425311432224323300220160ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file GUID Partition Table (GPT) Routines * \brief GUID Partition Table (GPT) Routines */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "hss_crc32.h" #include "gpt.h" #include #include #undef GPT_DEBUG //#define GPT_DEBUG // // local modules function pointer types typedef bool (*ReadBlockFnPtr_t)(void *pDest, size_t srcOffset, size_t byteCount); typedef bool (*CheckIfGUIDMatchFnPtr_t)(HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry, HSS_GPT_GUID_t const * const pGUID2); static ReadBlockFnPtr_t readBlockFnPtr; // // local module function prototypes static bool CheckIfGUIDMatch_(HSS_GPT_GUID_t const * const pGUID1, HSS_GPT_GUID_t const * const pGUID2); static bool CheckIfTypeIdMatch_(HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry, HSS_GPT_GUID_t const * const pGUID); static bool CheckIfUniqueIdMatch_(HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry, HSS_GPT_GUID_t const * const pGUID); static bool FindPartitionById_(HSS_GPT_t const * const pGpt, HSS_GPT_GUID_t const * const pGUID, size_t * const pPartitionIndex, CheckIfGUIDMatchFnPtr_t pCheckIfMatchFunc, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut); //////////////////////////////////////////////////////////////////////////////////////////////////// // // Debug Routines // #ifdef GPT_DEBUG static const HSS_GPT_GUID_t nullGUID = { .data1 = 0u, .data2 = 0u, .data3 = 0u, .data4 = 0u }; #endif // // // void GPT_DumpHeaderInfo(HSS_GPT_t *pGpt) { #ifdef GPT_DEBUG HSS_GPT_Header_t const * const pGptHeader = &(pGpt->h.header); assert(pGptHeader != NULL); mHSS_DEBUG_PRINTF(LOG_STATUS, "Signature: %c%c%c%c%c%c%c%c (%016lx)\n", pGptHeader->s.c[0], pGptHeader->s.c[1], pGptHeader->s.c[2], pGptHeader->s.c[3], pGptHeader->s.c[4], pGptHeader->s.c[5], pGptHeader->s.c[6], pGptHeader->s.c[7], pGptHeader->s.signature); mHSS_DEBUG_PRINTF(LOG_STATUS, "Revision: 0x%08x\n", pGptHeader->revision); mHSS_DEBUG_PRINTF(LOG_STATUS, "Header Size: 0x%08x\n", pGptHeader->headerSize); mHSS_DEBUG_PRINTF(LOG_STATUS, "Header CRC: 0x%08x\n", pGptHeader->headerCrc32); mHSS_DEBUG_PRINTF(LOG_STATUS, "Current LBA: 0x%016lx\n", pGptHeader->currentLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "Backup LBA: 0x%016lx\n", pGptHeader->backupLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "First Usable LBA: 0x%016lx\n", pGptHeader->firstUsableLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "Last Usable LBA: 0x%016lx\n", pGptHeader->lastUsableLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "Disk GUID: %08x-%04x-%04x-%016lx\n", pGptHeader->diskGUID.data1, pGptHeader->diskGUID.data2, pGptHeader->diskGUID.data3, __builtin_bswap64(pGptHeader->diskGUID.data4)); mHSS_DEBUG_PRINTF(LOG_STATUS, "Starting LBA: 0x%016lx\n", pGptHeader->partitionEntriesStartingLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "Num. Partitions: 0x%08x\n", pGptHeader->numPartitions); mHSS_DEBUG_PRINTF(LOG_STATUS, "Size of Partition: 0x%08x\n", pGptHeader->sizeOfPartitionEntry); mHSS_DEBUG_PRINTF(LOG_STATUS, "Partition Entries CRC: 0x%08x\n", pGptHeader->partitionEntriesArrayCrc32); #else (void)pGpt; #endif } // // // void GPT_DumpPartitionInfo(HSS_GPT_t const * const pGpt, HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry) { #ifdef GPT_DEBUG assert(pGpt != NULL); assert(pGptPartitionEntry != NULL); mHSS_DEBUG_PRINTF(LOG_STATUS, "Type GUID: %08x-%04x-%04x-%016lx\n", pGptPartitionEntry->partitionTypeGUID.data1, pGptPartitionEntry->partitionTypeGUID.data2, pGptPartitionEntry->partitionTypeGUID.data3, pGptPartitionEntry->partitionTypeGUID.data4); mHSS_DEBUG_PRINTF(LOG_STATUS, "Unique GUID: %08x-%04x-%04x-%016lx\n", pGptPartitionEntry->uniquePartitionGUID.data1, pGptPartitionEntry->uniquePartitionGUID.data2, pGptPartitionEntry->uniquePartitionGUID.data3, pGptPartitionEntry->uniquePartitionGUID.data4); mHSS_DEBUG_PRINTF(LOG_STATUS, "First LBA: %016lx\n", pGptPartitionEntry->firstLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "Last LBA: %016lx\n", pGptPartitionEntry->lastLBA); mHSS_DEBUG_PRINTF(LOG_STATUS, "Attributes: %016lx\n", pGptPartitionEntry->attributes); #endif } //////////////////////////////////////////////////////////////////////////////////////////////////// // // // bool bootPartitionIndexValid = false; size_t bootPartitionIndex = 0u; void GPT_SetBootPartitionIndex(HSS_GPT_t *pGpt, size_t index) { assert(pGpt); /*pGpt->*/bootPartitionIndexValid = true; /*pGpt->*/bootPartitionIndex = index; } // // // bool GPT_GetBootPartitionIndex(HSS_GPT_t *pGpt, size_t *pIndex) { assert(pGpt); assert(pIndex); if (/*pGpt->*/bootPartitionIndexValid) { *pIndex = /*pGpt->*/bootPartitionIndex; } return /*pGpt->*/bootPartitionIndexValid; } // // // bool GPT_ValidateHeader(HSS_GPT_t *pGpt) { bool result = true; assert(pGpt != NULL); HSS_GPT_Header_t * const pGptHeader = &(pGpt->h.header); result = (!strncmp(pGptHeader->s.c, (char *)GPT_EXPECTED_SIGNATURE, 8)); if (!result) { //mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT signature not as expected\n"); } else { result = (pGptHeader->revision == GPT_EXPECTED_REVISION); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT header revision is %08x vs expected %08x\n", pGptHeader->revision, GPT_EXPECTED_REVISION); } else { uint32_t origChecksum = pGptHeader->headerCrc32; pGptHeader->headerCrc32 = 0u; uint32_t checksum = CRC32_calculate((const uint8_t *)pGptHeader, pGptHeader->headerSize); pGptHeader->headerCrc32 = origChecksum; result = (checksum == origChecksum); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT header CRC32 is %08x vs expected %08x\n", checksum, origChecksum); } else { result = (pGptHeader->currentLBA == 1u); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT current LBA is %lu vs expected %u\n", pGptHeader->currentLBA, 1u); } else { result = (pGptHeader->partitionEntriesStartingLBA == 2u); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT starting LBA of array of partition entries is %lu" " vs expected %u\n", pGptHeader->currentLBA, 2u); } } } } } if (result) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Validated GPT Header ...\n"); pGpt->headerValid = true; } return result; } // // // bool GPT_ReadHeader(HSS_GPT_t *pGpt) { assert(pGpt != NULL); assert(readBlockFnPtr != NULL); bool result = false; result = readBlockFnPtr(pGpt->h.buffer, 1u * pGpt->lbaSize, pGpt->lbaSize); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Unable to read block for LBA 1\n"); } else { result = GPT_ValidateHeader(pGpt); } return result; } // // // static HSS_GPT_PartitionEntry_t const * ReadPartitionEntryIntoBuffer_(HSS_GPT_t const * const pGpt, size_t lbaIndex, size_t partitionIndex) { assert(readBlockFnPtr != NULL); assert(pGpt!= NULL); HSS_GPT_Header_t const * const pGptHeader = &(pGpt->h.header); uint8_t const * const pLBABuffer = pGpt->lbaBuffer; HSS_GPT_PartitionEntry_t *pResult = NULL; bool retVal = false; const size_t offset = (pGptHeader->sizeOfPartitionEntry * partitionIndex) - ((lbaIndex - pGptHeader->partitionEntriesStartingLBA) * pGpt->lbaSize); retVal = readBlockFnPtr((void *)pLBABuffer, lbaIndex * pGpt->lbaSize, pGpt->lbaSize); if (!retVal) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Unable to read block for LBA %lu (partition entry %lu)\n", lbaIndex, partitionIndex); } else { if (offset >= pGpt->lbaSize) { retVal = readBlockFnPtr((void *)(pLBABuffer + pGpt->lbaSize), (lbaIndex + 1u) * pGpt->lbaSize, pGpt->lbaSize); if (!retVal) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Unable to read block for LBA %lu (partition entry %lu)\n", lbaIndex, partitionIndex); } } } if (retVal) { pResult = (HSS_GPT_PartitionEntry_t *)(pLBABuffer + offset); } return pResult;; } // // // static bool CheckIfGUIDMatch_(HSS_GPT_GUID_t const * const pGUID1, HSS_GPT_GUID_t const * const pGUID2) { bool result = false; result = ((pGUID1->data1 == pGUID2->data1) && (pGUID1->data2 == pGUID2->data2) && (pGUID1->data3 == pGUID2->data3) && (pGUID1->data4 == pGUID2->data4)); return result; } // // // static bool CheckIfTypeIdMatch_(HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry, HSS_GPT_GUID_t const * const pGUID) { bool result = false; #ifdef GPT_DEBUG mHSS_DEBUG_PRINTF(LOG_NORMAL, " - Unique GUID: %08x-%04x-%04x-%016lx\n", pGUID->data1, pGUID->data2, pGUID->data3, __builtin_bswap64(pGUID->data4)); HSS_GPT_GUID_t const * pDbgGUID = &(pGptPartitionEntry->partitionTypeGUID); mHSS_DEBUG_PRINTF(LOG_NORMAL, " - Type GUID: %08x-%04x-%04x-%016lx\n", pDbgGUID->data1, pDbgGUID->data2, pDbgGUID->data3, __builtin_bswap64(pDbgGUID->data4)); #endif result = CheckIfGUIDMatch_(&(pGptPartitionEntry->partitionTypeGUID), pGUID); return result; } // // // static bool CheckIfUniqueIdMatch_(HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry, HSS_GPT_GUID_t const * const pGUID) { bool result = false; result = CheckIfGUIDMatch_(&(pGptPartitionEntry->uniquePartitionGUID), pGUID); return result; } // // // bool GPT_PartitionIdToLBAOffset(HSS_GPT_t const * const pGpt, size_t partitionIndex, size_t * const pFirstLBA) { bool result = false; assert(pGpt != NULL); assert(pFirstLBA != NULL); HSS_GPT_Header_t const * const pGptHeader = &(pGpt->h.header); const size_t lbaIndex = pGptHeader->partitionEntriesStartingLBA + ((partitionIndex * pGptHeader->sizeOfPartitionEntry) / pGpt->lbaSize); HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry = ReadPartitionEntryIntoBuffer_(pGpt, lbaIndex, partitionIndex); result = partitionIndex < pGptHeader->numPartitions; if (result) { *pFirstLBA = pGptPartitionEntry->firstLBA; } return result; } // // // bool GPT_ReadPartitionEntryByIndex(HSS_GPT_t const * const pGpt, size_t const partitionIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut) { bool result = false; assert(pGpt != NULL); assert(ppGptPartitionEntryOut != NULL); // Read Partition Entries HSS_GPT_Header_t const * const pGptHeader = &(pGpt->h.header); const size_t lbaIndex = pGptHeader->partitionEntriesStartingLBA + ((partitionIndex * pGptHeader->sizeOfPartitionEntry) / pGpt->lbaSize); *ppGptPartitionEntryOut = ReadPartitionEntryIntoBuffer_(pGpt, lbaIndex, partitionIndex); result = (*ppGptPartitionEntryOut != NULL); return result; } // // // static bool FindPartitionById_(HSS_GPT_t const * const pGpt, HSS_GPT_GUID_t const * const pGUID, size_t * const pPartitionIndex, CheckIfGUIDMatchFnPtr_t pCheckIfMatchFunc, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut) { bool result = false; assert(pGpt != NULL); assert(pGUID != NULL); assert(pPartitionIndex != NULL); assert(pCheckIfMatchFunc != NULL); HSS_GPT_Header_t const * const pGptHeader = &(pGpt->h.header); // // Read Partition Entries for (size_t partitionIndex = 0u; partitionIndex < pGptHeader->numPartitions; partitionIndex++) { HSS_GPT_PartitionEntry_t const * pPartitionEntry; assert(GPT_ReadPartitionEntryByIndex(pGpt, partitionIndex, &pPartitionEntry)); // if we've passed the starting LBA of this parameter into the search, we already know // about it so look for another... if (partitionIndex < *pPartitionIndex) { #ifdef GPT_DEBUG mHSS_DEBUG_PRINTF(LOG_NORMAL, "Skipping partition %lu\n", partitionIndex); #endif continue; } result = pCheckIfMatchFunc(pPartitionEntry, pGUID); if (result) { #ifdef GPT_DEBUG mHSS_DEBUG_PRINTF(LOG_NORMAL, "Located partition for GUID %08x-%04x-%04x-%016lx\n", pGUID->data1, pGUID->data2, pGUID->data3, __builtin_bswap64(pGUID->data4)); #endif *pPartitionIndex = partitionIndex; if (ppGptPartitionEntryOut) { *ppGptPartitionEntryOut = pPartitionEntry; } break; } } if (!result && (!*pPartitionIndex)) { // didn't find a partition and we were searching for the second or subsequent mHSS_DEBUG_PRINTF(LOG_ERROR, "Unable to find partition for GUID %08x-%04x-%04x-%016lx\n", pGUID->data1, pGUID->data2, pGUID->data3, __builtin_bswap64(pGUID->data4)); } return result; } // // // bool GPT_FindPartitionByTypeId(HSS_GPT_t const * const pGpt, HSS_GPT_GUID_t const * const pGUID, size_t * const pPartitionIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut) { return FindPartitionById_(pGpt, pGUID, pPartitionIndex, CheckIfTypeIdMatch_, ppGptPartitionEntryOut); } // // // bool GPT_FindPartitionByUniqueId(HSS_GPT_t const * const pGpt, HSS_GPT_GUID_t const * const pGUID, size_t * const pPartitionIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut) { return FindPartitionById_(pGpt, pGUID, pPartitionIndex, CheckIfUniqueIdMatch_, ppGptPartitionEntryOut); } // // // bool GPT_ValidatePartitionEntries(HSS_GPT_t *pGpt) { bool result = true; uint32_t rollingCrc = 0u; assert(pGpt != NULL); HSS_GPT_Header_t const * const pGptHeader = &(pGpt->h.header); // // Read Partition Entries for (size_t partitionIndex = 0; partitionIndex < pGptHeader->numPartitions; partitionIndex++) { const size_t lbaIndex = pGptHeader->partitionEntriesStartingLBA + ((partitionIndex * pGptHeader->sizeOfPartitionEntry) / pGpt->lbaSize); HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry = ReadPartitionEntryIntoBuffer_(pGpt, lbaIndex, partitionIndex); if (!pGptPartitionEntry) { result = false; break; } #ifdef GPT_DEBUG if ((CheckIfGUIDMatch_(&nullGUID, &(pGptPartitionEntry->uniquePartitionGUID))) || (CheckIfGUIDMatch_(&nullGUID, &(pGptPartitionEntry->uniquePartitionGUID)))) { // skip debug output if null } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Found partition:\n"); HSS_GPT_GUID_t const * pGUID = &(pGptPartitionEntry->uniquePartitionGUID); mHSS_DEBUG_PRINTF(LOG_NORMAL, " - Unique GUID: %08x-%04x-%04x-%016lx\n", pGUID->data1, pGUID->data2, pGUID->data3, __builtin_bswap64(pGUID->data4)); pGUID = &(pGptPartitionEntry->partitionTypeGUID); mHSS_DEBUG_PRINTF(LOG_NORMAL, " - Type GUID: %08x-%04x-%04x-%016lx\n", pGUID->data1, pGUID->data2, pGUID->data3, __builtin_bswap64(pGUID->data4)); } #endif rollingCrc = CRC32_calculate_ex(rollingCrc, (uint8_t const *)pGptPartitionEntry, pGptHeader->sizeOfPartitionEntry); } if (result) { result = (rollingCrc == pGptHeader->partitionEntriesArrayCrc32); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "CRC32 of partition entries is %08x, vs expected %08x\n", rollingCrc, pGptHeader->partitionEntriesArrayCrc32); } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Validated GPT Partition Entries ...\n"); pGpt->partitionEntriesValid = true; } } return result; } // // // bool GPT_FindBootSectorIndex(HSS_GPT_t *pGpt, size_t *srcIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut) { bool result = false; assert(srcIndex != NULL); assert(readBlockFnPtr != NULL); assert(pGpt != NULL); result = pGpt->headerValid; if (!result) { result = GPT_ValidateHeader(pGpt); } result = pGpt->partitionEntriesValid; if (!result) { result = GPT_ValidatePartitionEntries(pGpt); } if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT_ValidatePartitionEntries() failed\n"); } if (result) { const HSS_GPT_GUID_t diskGUID = { .data1 = 0x21686148u, .data2 = 0x6449u, .data3 = 0x6E6Fu, .data4 = 0x4946456465654e74u }; size_t partitionIndex = *srcIndex; result = GPT_FindPartitionByTypeId(pGpt, &diskGUID, &partitionIndex, ppGptPartitionEntryOut); if (result) { *srcIndex = partitionIndex; } } return result; } // // // void GPT_Init(HSS_GPT_t *pGpt, struct HSS_Storage *pStorage) { assert(pGpt); assert(pStorage); readBlockFnPtr = pStorage->readBlock; pGpt->headerValid = false; pGpt->partitionEntriesValid = false; pGpt->bootPartitionIndexValid = false; pGpt->bootPartitionIndex = 0; } hart-software-services-2022.10/services/boot/gpt.h000066400000000000000000000106001432224323300220130ustar00rootroot00000000000000#ifndef GPT_H #define GPT_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Hart Software Services - GUID Partition Table (GPT) Types and Routines. * */ #ifdef __cplusplus extern "C" { #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI) # define GPT_MAX_LBA_SIZE 2048u #else # define GPT_MAX_LBA_SIZE 512u #endif typedef struct HSS_GPT_GUID_s { uint32_t data1; uint16_t data2; uint16_t data3; uint64_t data4; } HSS_GPT_GUID_t; typedef struct HSS_GPT_Header_s { union { uint64_t signature; char c[8]; uint8_t u[8]; } s; uint32_t revision; uint32_t headerSize; uint32_t headerCrc32; uint32_t reserved; uint64_t currentLBA; uint64_t backupLBA; uint64_t firstUsableLBA; uint64_t lastUsableLBA; HSS_GPT_GUID_t diskGUID; uint64_t partitionEntriesStartingLBA; uint32_t numPartitions; uint32_t sizeOfPartitionEntry; uint32_t partitionEntriesArrayCrc32; } HSS_GPT_Header_t; typedef struct HSS_GPT_s { union { HSS_GPT_Header_t header; uint8_t buffer[GPT_MAX_LBA_SIZE] __attribute__((aligned(8))); } h; // For now, GPT needs a 2-sector buffer (~1KB) - for partition entity uint8_t lbaBuffer[2 * GPT_MAX_LBA_SIZE] __attribute__((aligned(8))); size_t bootPartitionIndex; size_t lbaSize; int headerValid:1; int partitionEntriesValid:1; int bootPartitionIndexValid:1; } HSS_GPT_t; #define GPT_EXPECTED_SIGNATURE "EFI PART" #define GPT_EXPECTED_REVISION 0x00010000u void GPT_RegisterReadFunction(bool (*fnPtr)(void *pDest, size_t srcOffset, size_t byteCount)); void GPT_Init(HSS_GPT_t *pGpt, struct HSS_Storage *pStorage); bool GPT_ReadHeader(HSS_GPT_t *pGpt); void GPT_DumpHeaderInfo(HSS_GPT_t *pGpt); bool GPT_ValidateHeader(HSS_GPT_t *pGpt); typedef struct HSS_GPT_PartitionEntry_s { HSS_GPT_GUID_t partitionTypeGUID; HSS_GPT_GUID_t uniquePartitionGUID; uint64_t firstLBA; uint64_t lastLBA; uint64_t attributes; union { uint16_t utf16le[36]; char c[72]; uint8_t u[72]; }; } HSS_GPT_PartitionEntry_t; bool GPT_ValidatePartitionEntries(HSS_GPT_t *pGpt); void GPT_DumpPartitionInfo(HSS_GPT_t const * const pGpt, HSS_GPT_PartitionEntry_t const * const pGptPartitionEntry); bool GPT_PartitionIdToLBAOffset(HSS_GPT_t const * const pGpt, size_t partitionIndex, size_t * const pFirstLBA); bool GPT_FindPartitionByTypeId(HSS_GPT_t const * const pGpt, HSS_GPT_GUID_t const * const pGUID, size_t * const pPartitionIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut); bool GPT_FindPartitionByUniqueId(HSS_GPT_t const * const pGpt, HSS_GPT_GUID_t const * const pGUID, size_t * const pPartitionIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut); bool GPT_FindBootSectorIndex(HSS_GPT_t *pGpt, size_t *srcIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut); void GPT_SetBootPartitionIndex(HSS_GPT_t *pGpt, size_t index); bool GPT_GetBootPartitionIndex(HSS_GPT_t *pGpt, size_t *pIndex); bool GPT_ReadPartitionEntryByIndex(HSS_GPT_t const * const pGpt, size_t const partitionIndex, HSS_GPT_PartitionEntry_t const ** ppGptPartitionEntryOut); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/boot/hss_boot_pmp.c000066400000000000000000000204251432224323300237160ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Boot Service State Machine * \brief Boot Service */ #include "config.h" #include "hss_types.h" #include #include "csr_helper.h" #include "hss_state_machine.h" #include "hss_boot_service.h" #include "hss_boot_pmp.h" #include "hss_debug.h" #include "hss_boot_pmp.h" #define XLEN 64u /////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////// static struct PmpEntry pmpEntry[HSS_HART_NUM_PEERS][MAX_NUM_PMPS]; static uint64_t pmp_decode_napot_size_encoding(uint64_t addrVal, uint64_t *pMask); static void pmp_decode(struct PmpEntry *pPmpEntry, struct PmpEntry *pPreviousPmpEntry, uint8_t configVal, uint64_t addrVal); static inline uint8_t pmp_getConfigVal(size_t index); static inline uint64_t pmp_getAddrVal(size_t index); bool HSS_PMP_Init(void) { bool result = true; enum HSSHartId target; unsigned int pmpIndex; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initializing PMPs\n"); for (target = HSS_HART_U54_1; target A) { continue; } // inactive PMP const ptrdiff_t pmpStartAddr = pPmpEntry->baseAddr; const ptrdiff_t pmpEndAddr = pmpStartAddr + pPmpEntry->size; if ((pmpStartAddr <= regionStartAddr) && (pmpEndAddr > regionEndAddr)) { if (pPmpEntry->W == 0) { result = false; // found match disallowing region break; } else if (pPmpEntry->W != 0) { result = true; // found match allowing region break; } } } return result; } bool HSS_PMP_CheckRead(enum HSSHartId target, const ptrdiff_t regionStartAddr, size_t length) { bool result = false; unsigned int pmpIndex; const ptrdiff_t regionEndAddr = regionStartAddr + length; for (pmpIndex = 0u; pmpIndex < MAX_NUM_PMPS; pmpIndex++) { struct PmpEntry *pPmpEntry = &(pmpEntry[target][pmpIndex]); if (!pPmpEntry->A) { continue; } // inactive PMP const ptrdiff_t pmpStartAddr = pPmpEntry->baseAddr; const ptrdiff_t pmpEndAddr = pmpStartAddr + pPmpEntry->size; if ((pmpStartAddr <= regionStartAddr) && (pmpEndAddr > regionEndAddr)) { if (pPmpEntry->R == 0) { result = false; // found match disallowing region break; } else if (pPmpEntry->R != 0) { result = true; // found match allowing region break; } } } return result; } /////////////////////////////////////////////////////////////////////////////////////////// // // Decode Functions // static uint64_t pmp_decode_napot_size_encoding(uint64_t addrVal, uint64_t *pMask) { uint64_t mask = 0u; uint64_t result = XLEN + 2u; mask = (mask - 1u) >> 1; while (mask) { if ((addrVal & mask) == mask) { *pMask = mask; break; } result = result - 1u; mask = mask >> 1; } return (result); } static void pmp_decode(struct PmpEntry *pPmpEntry, struct PmpEntry *pPreviousPmpEntry, uint8_t configVal, uint64_t addrVal) { uint64_t mask = 0u; uint64_t range = 0u; assert(pPmpEntry != NULL); pPmpEntry->A = ((configVal & 0x18) >> 3); if (pPmpEntry->A) { pPmpEntry->R = (configVal & PMP_READ) ? 1u : 0u; pPmpEntry->W = (configVal & PMP_WRITE) ? 1u : 0u; pPmpEntry->X = (configVal & PMP_EXEC) ? 1u : 0u; pPmpEntry->L = (configVal & PMP_LOCK) ? 1u : 0u; } switch (pPmpEntry->A) { case AddressMatchingMode_NULL_REGION: break; case AddressMatchingMode_TOR: assert(pPreviousPmpEntry != NULL); addrVal <<= 2; // shift up from [53:0] to [55:2] if (pPreviousPmpEntry != NULL) { pPmpEntry->baseAddr = pPreviousPmpEntry->baseAddr + pPreviousPmpEntry->size; } else { pPmpEntry->baseAddr = 0u; } pPmpEntry->size = addrVal - pPmpEntry->baseAddr; break; case AddressMatchingMode_NA4: addrVal <<= 2; // shift up from [53:0] to [55:2] pPmpEntry->baseAddr = addrVal; pPmpEntry->size = 4u; break; case AddressMatchingMode_NAPOT: range = pmp_decode_napot_size_encoding(addrVal, &mask); addrVal = addrVal & (~mask); // remove the size encoding addrVal <<= 2; // shift up from [53:0] to [55:2] pPmpEntry->baseAddr = addrVal; pPmpEntry->size = (1lu << range); break; default: break; } } static inline uint8_t pmp_getConfigVal(size_t index) { uint64_t result; switch (index) { case 0: result = (uint64_t)csr_read(pmpcfg0); break; case 1: result = (uint64_t)csr_read(pmpcfg0); break; case 2: result = (uint64_t)csr_read(pmpcfg0); break; case 3: result = (uint64_t)csr_read(pmpcfg0); break; case 4: result = (uint64_t)csr_read(pmpcfg0); break; case 5: result = (uint64_t)csr_read(pmpcfg0); break; case 6: result = (uint64_t)csr_read(pmpcfg0); break; case 7: result = (uint64_t)csr_read(pmpcfg0); break; case 8: result = (uint64_t)csr_read(pmpcfg1); break; case 9: result = (uint64_t)csr_read(pmpcfg1); break; case 10: result = (uint64_t)csr_read(pmpcfg1); break; case 11: result = (uint64_t)csr_read(pmpcfg1); break; case 12: result = (uint64_t)csr_read(pmpcfg1); break; case 13: result = (uint64_t)csr_read(pmpcfg1); break; case 14: result = (uint64_t)csr_read(pmpcfg1); break; case 15: result = (uint64_t)csr_read(pmpcfg1); break; default: result = 0u; break; } if (index < 8u) { result = result >> (index * 8u); } else if (index < 15) { result = result >> ((index - 8u) * 8u); } return (uint8_t)(result & 0xFFu); } static inline uint64_t pmp_getAddrVal(size_t index) { uint64_t result; switch (index) { case 0: result = (uint64_t)csr_read(pmpaddr0); break; case 1: result = (uint64_t)csr_read(pmpaddr1); break; case 2: result = (uint64_t)csr_read(pmpaddr2); break; case 3: result = (uint64_t)csr_read(pmpaddr3); break; case 4: result = (uint64_t)csr_read(pmpaddr4); break; case 5: result = (uint64_t)csr_read(pmpaddr5); break; case 6: result = (uint64_t)csr_read(pmpaddr6); break; case 7: result = (uint64_t)csr_read(pmpaddr7); break; case 8: result = (uint64_t)csr_read(pmpaddr8); break; case 9: result = (uint64_t)csr_read(pmpaddr9); break; case 10: result = (uint64_t)csr_read(pmpaddr10); break; case 11: result = (uint64_t)csr_read(pmpaddr11); break; case 12: result = (uint64_t)csr_read(pmpaddr12); break; case 13: result = (uint64_t)csr_read(pmpaddr13); break; case 14: result = (uint64_t)csr_read(pmpaddr14); break; case 15: result = (uint64_t)csr_read(pmpaddr15); break; default: result = 0u; break; } return result; } hart-software-services-2022.10/services/boot/hss_boot_pmp.h000066400000000000000000000047561432224323300237340ustar00rootroot00000000000000#ifndef HSS_BOOT_PMP_H #define HSS_BOOT_PMP_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Physical Memory Protections * */ #ifdef __cplusplus extern "C" { #endif enum PMP_Priv_S { PMP_READ = 1 << 0, PMP_WRITE = 1 << 1, PMP_EXEC = 1 << 2, PMP_LOCK = 1 << 7 }; #define MAX_NUM_PMPS 16u bool HSS_PMP_Init(void); bool HSS_PMP_CheckWrite(enum HSSHartId target, const ptrdiff_t regionStartAddr, size_t length); bool HSS_PMP_CheckRead(enum HSSHartId target, const ptrdiff_t regionStartAddr, size_t length); /* TODO: the following enum could be removed from this header and kept local in scope */ enum AddressMatchingMode { AddressMatchingMode_NULL_REGION = 0, AddressMatchingMode_TOR = 1, AddressMatchingMode_NA4 = 2, AddressMatchingMode_NAPOT = 3 }; /* TODO: the following struct could be removed from this header and kept local in scope */ struct PmpEntry { uint64_t baseAddr; uint64_t size; enum AddressMatchingMode A; unsigned int R:1; unsigned int W:1; unsigned int X:1; unsigned int L:1; }; // uint64_t pmp_decode_napot_size_encoding(uint64_t addrVal, uint64_t *pMask); // void pmp_decode(struct PmpEntry *pPmpEntry, struct PmpEntry *pPreviousPmpEntry, uint64_t configVal, uint64_t addrVal); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/boot/hss_boot_secure.c000066400000000000000000000031101432224323300244000ustar00rootroot00000000000000/******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Boot Service Image Signing * \brief Boot Service */ #include "config.h" #include "hss_types.h" #include "hss_clock.h" #include "hss_debug.h" #include "hss_perfctr.h" #include "hss_crypto.h" #include "hss_boot_secure.h" #include #include static void __attribute__((__noreturn__)) boot_secure_failure_(void) { // TODO: assert tamper flag? mHSS_DEBUG_PRINTF(LOG_ERROR, "failure during signature verification...\n"); while (1) { // spin forever }; // will never be reached __builtin_unreachable(); } static int perf_ctr_index = PERF_CTR_UNINITIALIZED; bool HSS_Boot_Secure_CheckCodeSigning(struct HSS_BootImage *pBootImage) { bool result = false; assert(pBootImage != NULL); struct HSS_Signature originalSig __attribute__((aligned)) = pBootImage->signature; memset((void *)&(pBootImage->signature), 0, sizeof(struct HSS_Signature)); HSS_PerfCtr_Allocate(&perf_ctr_index, "SecureBoot"); HSS_PerfCtr_Start(perf_ctr_index); result = HSS_Crypto_Verify_ECDSA_P384(ARRAY_SIZE(originalSig.ecdsaSig), &(originalSig.ecdsaSig[0]), pBootImage->bootImageLength, (uint8_t *)pBootImage); if (!result) { boot_secure_failure_(); } else { mHSS_DEBUG_PRINTF(LOG_STATUS, "ECDSA verification passed\n"); } HSS_PerfCtr_Lap(perf_ctr_index); return result; } hart-software-services-2022.10/services/boot/hss_boot_secure.h000066400000000000000000000007171432224323300244170ustar00rootroot00000000000000#ifndef HSS_BOOT_SECURE_H #define HSS_BOOT_SECURE_H /******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Boot Service - Code Signing * \brief Boot Service - Code Signing */ bool HSS_Boot_Secure_CheckCodeSigning(struct HSS_BootImage *pBootImage) __attribute__((nonnull)); #endif hart-software-services-2022.10/services/boot/hss_boot_service.c000066400000000000000000001262701432224323300245670ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Boot Service State Machine * \brief Boot Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_boot_service.h" #include "opensbi_service.h" #include "hss_boot_pmp.h" #include "hss_sys_setup.h" #include "hss_clock.h" #include "hss_debug.h" #include "hss_perfctr.h" #include "common/mss_peripherals.h" #include "hss_crc32.h" #include "u54_state.h" #include #include #include "mpfs_reg_map.h" #if IS_ENABLED(CONFIG_OPENSBI) # include "sbi/riscv_asm.h" # define ffs SBI_FFS # define fls SBI_FLS # include "sbi/sbi_bitops.h" # undef ffs # undef fls # include "sbi/sbi_hart.h" # include "sbi_init.h" # include "sbi_scratch.h" # include "sbi_types.h" # include "sbi_platform.h" #else # ifdef __riscv # include # include # endif #endif #include "hss_atomic.h" #if IS_ENABLED(CONFIG_PLATFORM_MPFS) # include "mss_sysreg.h" #endif #include "hss_memcpy_via_pdma.h" #include "system_startup.h" #include "fpga_design_config/fpga_design_config.h" #if IS_ENABLED(CONFIG_CRYPTO_SIGNING) # include "hss_boot_secure.h" #endif #if IS_ENABLED(CONFIG_SERVICE_OPENSBI_RPROC) # include "opensbi_rproc_ecall.h" #endif /* Timeouts */ #define BOOT_SETUP_PMP_COMPLETE_TIMEOUT (ONE_SEC * 1u) #define BOOT_WAIT_TIMEOUT (ONE_SEC * 5u) #define BOOT_SUB_CHUNK_SIZE 256u /* * Module Prototypes (states) */ static void boot_init_handler(struct StateMachine * const pMyMachine); static void boot_setup_pmp_onEntry(struct StateMachine * const pMyMachine); static void boot_setup_pmp_handler(struct StateMachine * const pMyMachine); static void boot_setup_pmp_complete_onEntry(struct StateMachine * const pMyMachine); static void boot_setup_pmp_complete_handler(struct StateMachine * const pMyMachine); static void boot_zero_init_chunks_onEntry(struct StateMachine * const pMyMachine); static void boot_zero_init_chunks_handler(struct StateMachine * const pMyMachine); static void boot_download_chunks_onEntry(struct StateMachine * const pMyMachine); static void boot_download_chunks_handler(struct StateMachine * const pMyMachine); static void boot_download_chunks_onExit(struct StateMachine * const pMyMachine); static void boot_opensbi_init_onEntry(struct StateMachine * const pMyMachine); static void boot_opensbi_init_handler(struct StateMachine * const pMyMachine); static void boot_opensbi_init_onExit(struct StateMachine * const pMyMachine); static void boot_wait_onEntry(struct StateMachine * const pMyMachine); static void boot_wait_handler(struct StateMachine * const pMyMachine); static void boot_error_handler(struct StateMachine * const pMyMachine); static void boot_idle_onEntry(struct StateMachine * const pMyMachine); static void boot_idle_handler(struct StateMachine * const pMyMachine); static void boot_do_download_chunk(struct HSS_BootChunkDesc const *pChunk, ptrdiff_t subChunkOffset, size_t subChunkSize); static void boot_do_zero_init_chunk(struct HSS_BootZIChunkDesc const *pZiChunk); static bool validateCrc_(struct HSS_BootImage *pImage); /*! * \brief Boot Driver States * */ enum BootStatesEnum { BOOT_INITIALIZATION, BOOT_SETUP_PMP, BOOT_SETUP_PMP_COMPLETE, BOOT_ZERO_INIT_CHUNKS, BOOT_DOWNLOAD_CHUNKS, BOOT_OPENSBI_INIT, BOOT_WAIT, BOOT_IDLE, BOOT_ERROR, BOOT_NUM_STATES = BOOT_ERROR+1 }; /*! * \brief Boot Driver State Descriptors * */ static const struct StateDesc boot_state_descs[] = { { (const stateType_t)BOOT_INITIALIZATION, (const char *)"Init", NULL, NULL, &boot_init_handler }, { (const stateType_t)BOOT_SETUP_PMP, (const char *)"SetupPMP", &boot_setup_pmp_onEntry, NULL, &boot_setup_pmp_handler }, { (const stateType_t)BOOT_SETUP_PMP_COMPLETE, (const char *)"SetupPMPComplete", &boot_setup_pmp_complete_onEntry, NULL, &boot_setup_pmp_complete_handler }, { (const stateType_t)BOOT_ZERO_INIT_CHUNKS, (const char *)"ZeroInit", &boot_zero_init_chunks_onEntry, NULL, &boot_zero_init_chunks_handler }, { (const stateType_t)BOOT_DOWNLOAD_CHUNKS, (const char *)"Download", &boot_download_chunks_onEntry, &boot_download_chunks_onExit, &boot_download_chunks_handler }, { (const stateType_t)BOOT_OPENSBI_INIT, (const char *)"OpenSBIInit", &boot_opensbi_init_onEntry, &boot_opensbi_init_onExit, &boot_opensbi_init_handler }, { (const stateType_t)BOOT_WAIT, (const char *)"Wait", &boot_wait_onEntry, NULL, &boot_wait_handler }, { (const stateType_t)BOOT_IDLE, (const char *)"Idle", &boot_idle_onEntry, NULL, &boot_idle_handler }, { (const stateType_t)BOOT_ERROR, (const char *)"Error", NULL, NULL, &boot_error_handler } }; /*! * \brief Boot Driver State Machine * */ struct HSS_Boot_LocalData { const enum HSSHartId target; struct HSS_BootChunkDesc const *pChunk; struct HSS_BootZIChunkDesc const *pZiChunk; size_t chunkCount; size_t ziChunkCount; size_t subChunkOffset; uint32_t msgIndex; uint32_t hartMask; int perfCtr; unsigned int iterator; uintptr_t ancilliaryData; uint32_t msgIndexAux[MAX_NUM_HARTS-1]; }; static struct HSS_Boot_LocalData localData[MAX_NUM_HARTS-1] = { { HSS_HART_U54_1, NULL, NULL, 0u, 0u, 0u, IPI_MAX_NUM_OUTSTANDING_COMPLETES, 0u, PERF_CTR_UNINITIALIZED, 0u, 0u, { 0u, 0u, 0u, 0u } }, { HSS_HART_U54_2, NULL, NULL, 0u, 0u, 0u, IPI_MAX_NUM_OUTSTANDING_COMPLETES, 0u, PERF_CTR_UNINITIALIZED, 0u, 0u, { 0u, 0u, 0u, 0u } }, { HSS_HART_U54_3, NULL, NULL, 0u, 0u, 0u, IPI_MAX_NUM_OUTSTANDING_COMPLETES, 0u, PERF_CTR_UNINITIALIZED, 0u, 0u, { 0u, 0u, 0u, 0u } }, { HSS_HART_U54_4, NULL, NULL, 0u, 0u, 0u, IPI_MAX_NUM_OUTSTANDING_COMPLETES, 0u, PERF_CTR_UNINITIALIZED, 0u, 0u, { 0u, 0u, 0u, 0u } }, }; struct HSS_BootImage *pBootImage = NULL; static bool pmpSetupFlag[HSS_HART_NUM_PEERS] = { false, false, false, false, false }; /* * individual boot machines, one per U54 hart */ struct StateMachine boot_service1 = { .state = (stateType_t)BOOT_IDLE, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)BOOT_NUM_STATES, .pMachineName = (const char *)"boot_service(u54_1)", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = boot_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = (void *)&localData[0] }; struct StateMachine boot_service2 = { .state = (stateType_t)BOOT_IDLE, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)BOOT_NUM_STATES, .pMachineName = (const char *)"boot_service(u54_2)", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = boot_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = (void *)&localData[1] }; struct StateMachine boot_service3 = { .state = (stateType_t)BOOT_IDLE, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)BOOT_NUM_STATES, .pMachineName = (const char *)"boot_service(u54_3)", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = boot_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = (void *)&localData[2] }; struct StateMachine boot_service4 = { .state = (stateType_t)BOOT_IDLE, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)BOOT_NUM_STATES, .pMachineName = (const char *)"boot_service(u54_4)", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = boot_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = (void *)&localData[3] }; /* * table of individual boot machines, for convenience */ const struct { struct StateMachine* const pMachine; const enum HSSHartId hartId; } bootMachine[] = { { &boot_service1, HSS_HART_U54_1 }, { &boot_service2, HSS_HART_U54_2 }, { &boot_service3, HSS_HART_U54_3 }, { &boot_service4, HSS_HART_U54_4 }, }; // ---------------------------------------------------------------------------- /*! * \brief Helper Functions */ /*! * \brief Download Chunks * * The E51 places chunks from the boot image to their correct location in * physical system memory *before* releasing the U54s from WFI. * * \warning It is vitally important that we permissions check the bounds of each of * these reads/writes w.r.t. the U54 that owns it to make sure that is a permitted * write. Otherwise, a boot image could be constructed to circumvent these * protections. * * This checks are done outside this function. * */ static void boot_do_download_chunk(struct HSS_BootChunkDesc const *pChunk, ptrdiff_t subChunkOffset, size_t subChunkSize) { assert(pChunk); assert(pChunk->size); const uintptr_t execAddr = (uintptr_t)pChunk->execAddr + subChunkOffset; const uintptr_t loadAddr = (uintptr_t)pBootImage + (uintptr_t)pChunk->loadAddr + subChunkOffset; memcpy_via_pdma((void *)execAddr, (void*)loadAddr, subChunkSize); } static void boot_do_zero_init_chunk(struct HSS_BootZIChunkDesc const *pZiChunk) { assert(pZiChunk); const uintptr_t execAddr = (uintptr_t)pZiChunk->execAddr; const size_t ziChunkSize = pZiChunk->size; memset((void *)execAddr, 0, ziChunkSize); } static void free_msg_index(struct HSS_Boot_LocalData * const pInstanceData) { if (pInstanceData->msgIndex != IPI_MAX_NUM_OUTSTANDING_COMPLETES) { IPI_MessageFree(pInstanceData->msgIndex); pInstanceData->msgIndex = IPI_MAX_NUM_OUTSTANDING_COMPLETES; } } static void free_msg_index_aux(struct HSS_Boot_LocalData * const pInstanceData, enum HSSHartId peer) { if (pInstanceData->msgIndexAux[peer-1] != IPI_MAX_NUM_OUTSTANDING_COMPLETES) { IPI_MessageFree(pInstanceData->msgIndexAux[peer-1]); pInstanceData->msgIndexAux[peer-1] = IPI_MAX_NUM_OUTSTANDING_COMPLETES; } } static bool check_for_ipi_acks(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; bool result = true; for (unsigned int i = 0u; i < ARRAY_SIZE(bootMachine); i++) { enum HSSHartId const peer = bootMachine[i].hartId; if (pInstanceData->msgIndexAux[peer-1] != IPI_MAX_NUM_OUTSTANDING_COMPLETES) { result = IPI_MessageCheckIfComplete(pInstanceData->msgIndexAux[peer-1]); if (result) { free_msg_index_aux(pInstanceData, peer); } } } if (pInstanceData->msgIndex != IPI_MAX_NUM_OUTSTANDING_COMPLETES) { result = result & IPI_MessageCheckIfComplete(pInstanceData->msgIndex); if (result) { free_msg_index(pInstanceData); } } return result; } // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void boot_init_handler(struct StateMachine * const pMyMachine) { if (pBootImage) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::\tstarting boot\n", pMyMachine->pMachineName); pMyMachine->startTime = HSS_GetTime(); struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; if (pBootImage->hart[target-1].flags & BOOT_FLAG_SKIP_OPENSBI) { mHSS_DEBUG_PRINTF(LOG_STATUS, "%s:: BOOT_FLAG_SKIP_OPENSBI found\n", pMyMachine->pMachineName); } HSS_PerfCtr_Allocate(&pInstanceData->perfCtr, pMyMachine->pMachineName); pMyMachine->state = BOOT_SETUP_PMP; } else { // unexpected error state if (!pBootImage) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s::\tNo Boot Image registered\n", pMyMachine->pMachineName); } pMyMachine->state = BOOT_ERROR; } } ///////////////// static void boot_setup_pmp_onEntry(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; pInstanceData->msgIndex = IPI_MAX_NUM_OUTSTANDING_COMPLETES; bool const primary_boot_hart = (pBootImage->hart[target-1].numChunks) && (pBootImage->hart[target-1].entryPoint); for (unsigned int i = 0u; i < ARRAY_SIZE(bootMachine); i++) { enum HSSHartId peer = bootMachine[i].hartId; pInstanceData->msgIndexAux[peer-1] = IPI_MAX_NUM_OUTSTANDING_COMPLETES; if (primary_boot_hart) { if (pBootImage->hart[peer-1].flags & BOOT_FLAG_SKIP_OPENSBI) { // skipping OpenSBI => don't register as a hart mpfs_domains_deregister_hart(peer); } else if ((peer == target) || (pBootImage->hart[peer-1].entryPoint == pBootImage->hart[target-1].entryPoint)) { pInstanceData->hartMask |= (1u << peer); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Registering u54_%d to domain \"%s\"\n", // pMyMachine->pMachineName, peer, pBootImage->hart[target-1].name); mpfs_domains_register_hart(peer, target); } } } if (primary_boot_hart) { if (pBootImage->hart[target-1].flags & BOOT_FLAG_SKIP_OPENSBI) { // skipping OpenSBI => don't register as a domain } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Registering domain \"%s\" (hart mask 0x%x)\n", pMyMachine->pMachineName, pBootImage->hart[target-1].name, pInstanceData->hartMask); mpfs_domains_register_boot_hart(pBootImage->hart[target-1].name, pInstanceData->hartMask, target, pBootImage->hart[target-1].privMode, (void *)pBootImage->hart[target-1].entryPoint, (void *)pInstanceData->ancilliaryData, pBootImage->hart[target-1].flags & BOOT_FLAG_ALLOW_COLD_REBOOT, pBootImage->hart[target-1].flags & BOOT_FLAG_ALLOW_WARM_REBOOT); } } } static void boot_setup_pmp_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; bool result = false; if (pInstanceData->msgIndex == IPI_MAX_NUM_OUTSTANDING_COMPLETES) { result = HSS_Boot_PMPSetupRequest(target, &(pInstanceData->msgIndex)); } else { result = true; } if (result) { pMyMachine->state = BOOT_SETUP_PMP_COMPLETE; } } static void boot_setup_pmp_complete_onEntry(struct StateMachine * const pMyMachine) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Checking for IPI ACKs: - -\n", pMyMachine->pMachineName); } static void boot_setup_pmp_complete_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; if (HSS_Timer_IsElapsed(pMyMachine->startTime, BOOT_SETUP_PMP_COMPLETE_TIMEOUT)) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s::Timeout after %" PRIu64 " iterations\n", pMyMachine->pMachineName, pMyMachine->executionCount); for (unsigned int i = 0u; i < ARRAY_SIZE(bootMachine); i++) { enum HSSHartId peer = bootMachine[i].hartId; free_msg_index_aux(pInstanceData, peer); } free_msg_index(pInstanceData); pMyMachine->state = BOOT_ERROR; } else { // need to free as received, not all at once... if (check_for_ipi_acks(pMyMachine)) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Checking for IPI ACKs: ACK/IDLE ACK\n", pMyMachine->pMachineName); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::PMP setup completed\n", pMyMachine->pMachineName); if (pBootImage->hart[target-1].flags & BOOT_FLAG_SKIP_AUTOBOOT) pMyMachine->state = BOOT_IDLE; else pMyMachine->state = BOOT_ZERO_INIT_CHUNKS; } } } ///////////////// static void boot_zero_init_chunks_onEntry(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; assert(pBootImage != NULL); pInstanceData->pZiChunk = (struct HSS_BootZIChunkDesc const *)((char *)pBootImage + pBootImage->ziChunkTableOffset); } static void boot_zero_init_chunks_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; assert(pBootImage != NULL); struct HSS_BootZIChunkDesc const *pZiChunk = pInstanceData->pZiChunk; if (pZiChunk->size != 0u) { if (target == pZiChunk->owner) { #if IS_ENABLED(CONFIG_DEBUG_CHUNK_DOWNLOADS) mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::%d:ziChunk->0x%x, %u bytes\n", pMyMachine->pMachineName, pInstanceData->ziChunkCount, (uintptr_t)pZiChunk->execAddr, pZiChunk->size); #endif boot_do_zero_init_chunk(pZiChunk); } pInstanceData->pZiChunk++; } else { pMyMachine->state = BOOT_DOWNLOAD_CHUNKS; } } ///////////////// static void boot_download_chunks_onEntry(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; assert(pBootImage != NULL); if (pBootImage->hart[target-1].numChunks) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Processing boot image: \"%s\"\n", pMyMachine->pMachineName, pBootImage->hart[target-1].name); pInstanceData->pChunk = (struct HSS_BootChunkDesc *)((char *)pBootImage + pBootImage->chunkTableOffset); #if IS_ENABLED(CONFIG_DEBUG_CHUNK_DOWNLOADS) mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::firstChunk is %u\n", pMyMachine->pMachineName, pBootImage->hart[target-1].firstChunk); mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::lastChunk is %u\n", pMyMachine->pMachineName, pBootImage->hart[target-1].lastChunk); mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::numChunks is %u\n", pMyMachine->pMachineName, pBootImage->hart[target-1].numChunks); #endif pInstanceData->chunkCount = 0u; pInstanceData->subChunkOffset = 0u; pInstanceData->pChunk += pBootImage->hart[target-1].firstChunk; } else { // nothing to do for this machine, numChunks is zero... } } static void boot_download_chunks_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; assert(pBootImage != NULL); if (pBootImage->hart[target-1].numChunks) { // // end of image is denoted by sentinel chunk with zero size... // so if we're not on the sentinel chunk struct HSS_BootChunkDesc const *pChunk = pInstanceData->pChunk; if ((pInstanceData->chunkCount <= pBootImage->hart[target-1].lastChunk) && (pChunk->size)) { // // and it is for us, then download it if we have permission if (((pChunk->owner & ~BOOT_FLAG_ANCILLIARY_DATA) == target) && (HSS_PMP_CheckWrite(target, pChunk->execAddr, pChunk->size))) { #if IS_ENABLED(CONFIG_DEBUG_CHUNK_DOWNLOADS) if (!pInstanceData->subChunkOffset) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::%d:chunk@0x%x->0x%x, %u bytes\n", pMyMachine->pMachineName, pInstanceData->chunkCount, (uintptr_t)pChunk->loadAddr, (uintptr_t)pChunk->execAddr, pChunk->size); } #endif // check each hart to see if it wants to transmit boot_do_download_chunk(pChunk, #ifdef BOOT_SUB_CHUNK_SIZE pInstanceData->subChunkOffset, BOOT_SUB_CHUNK_SIZE #else 0u, pChunk->size #endif ); if ((pChunk->owner & BOOT_FLAG_ANCILLIARY_DATA) && (!pInstanceData->ancilliaryData)) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::%d:ancilliary data found at 0x%x\n", pMyMachine->pMachineName, pInstanceData->chunkCount, pChunk->execAddr); pInstanceData->ancilliaryData = pChunk->execAddr; } #ifdef BOOT_SUB_CHUNK_SIZE pInstanceData->subChunkOffset += BOOT_SUB_CHUNK_SIZE; if (pInstanceData->subChunkOffset > pChunk->size) { # if IS_ENABLED(CONFIG_DEBUG_CHUNK_DOWNLOADS) mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::%d:sub-chunk finished at 0x%x\n", pMyMachine->pMachineName, pInstanceData->chunkCount, pInstanceData->subChunkOffset); # endif pInstanceData->subChunkOffset = 0u; pInstanceData->chunkCount++; pInstanceData->pChunk++; } #else pInstanceData->chunkCount++; pInstanceData->pChunk++; #endif } else { if (pChunk->owner == target) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s::Skipping chunk %p due to invalid permissions\n", pMyMachine->pMachineName, pChunk); } else { mHSS_DEBUG_PRINTF(LOG_WARN, "%s::Skipping chunk %p due to ownership %d\n", pMyMachine->pMachineName, pChunk, pChunk->owner); } pInstanceData->pChunk++; } // // either way, with a non-sentinel chunk, // move onto next chunk, which will be handled by next time into state machine... } else { // // otherwise we are on a sentinel chunk and thus we are // finished processing the image pMyMachine->state = BOOT_OPENSBI_INIT; } } else { pMyMachine->state = BOOT_IDLE; } } static void boot_download_chunks_onExit(struct StateMachine * const pMyMachine) { } ///////////////// static void boot_opensbi_init_onEntry(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; assert(pBootImage != NULL); if (pBootImage->hart[target-1].entryPoint) { pInstanceData->iterator = 0u; } } static void boot_opensbi_init_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; assert(pBootImage != NULL); // if target has a valid entry point, allocate a message for it and send a OPENSBI_INIT IPI bool const primary_boot_hart = (pBootImage->hart[target-1].numChunks) && (pBootImage->hart[target-1].entryPoint); if (primary_boot_hart) { bool result; if (pInstanceData->iterator < ARRAY_SIZE(bootMachine)) { enum HSSHartId peer = bootMachine[pInstanceData->iterator].hartId; if (peer == target) { // skip myself for now } else if (pBootImage->hart[peer-1].entryPoint == pBootImage->hart[target-1].entryPoint) { // found another hart in same boot set as me... result = IPI_MessageAlloc(&(pInstanceData->msgIndexAux[peer-1])); assert(result); if (pBootImage->hart[target-1].flags & BOOT_FLAG_SKIP_OPENSBI) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::u54_%u:goto %p\n", pMyMachine->pMachineName, peer, pBootImage->hart[peer-1].entryPoint); result = IPI_MessageDeliver(pInstanceData->msgIndexAux[peer-1], peer, IPI_MSG_GOTO, pBootImage->hart[peer-1].privMode, (void *)pBootImage->hart[peer-1].entryPoint, (void *)pInstanceData->ancilliaryData); assert(result); } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::u54_%u:sbi_init %p\n", pMyMachine->pMachineName, peer, pBootImage->hart[peer-1].entryPoint); result = IPI_MessageDeliver(pInstanceData->msgIndexAux[peer-1], peer, IPI_MSG_OPENSBI_INIT, pBootImage->hart[peer-1].privMode, (void *)pBootImage->hart[peer-1].entryPoint, (void *)pInstanceData->ancilliaryData); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s::u54_%u:sbi_init failed\n", pMyMachine->pMachineName, peer); pMyMachine->state = BOOT_ERROR; } } } pInstanceData->iterator++; } else { pMyMachine->state = BOOT_WAIT; } } } static void boot_opensbi_init_onExit(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; assert(pBootImage != NULL); if (pBootImage->hart[target-1].entryPoint) { bool result; result = IPI_MessageAlloc(&(pInstanceData->msgIndex)); assert(result); mb(); mb_i(); if (pBootImage->hart[target-1].flags & BOOT_FLAG_SKIP_OPENSBI) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::u54_%u:goto %p\n", pMyMachine->pMachineName, target, pBootImage->hart[target-1].entryPoint); result = IPI_MessageDeliver(pInstanceData->msgIndex, target, IPI_MSG_GOTO, pBootImage->hart[target-1].privMode, (void *)pBootImage->hart[target-1].entryPoint, (void *)pInstanceData->ancilliaryData); assert(result); } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::u54_%u:sbi_init %p\n", pMyMachine->pMachineName, target, pBootImage->hart[target-1].entryPoint); result = IPI_MessageDeliver(pInstanceData->msgIndex, target, IPI_MSG_OPENSBI_INIT, pBootImage->hart[target-1].privMode, (void *)pBootImage->hart[target-1].entryPoint, (void *)pInstanceData->ancilliaryData); assert(result); } } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::target is %u, pBootImage is %p, skipping goto/sbi_init %p\n", pMyMachine->pMachineName, target, pBootImage, pBootImage->hart[target-1].entryPoint); } } ///////////////// static void boot_wait_onEntry(struct StateMachine * const pMyMachine) { (void)pMyMachine; mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Checking for IPI ACKs: - -\n", pMyMachine->pMachineName); } static void boot_wait_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData * const pInstanceData = pMyMachine->pInstanceData; enum HSSHartId const target = pInstanceData->target; pMyMachine->startTime = HSS_GetTime(); if (!pBootImage->hart[target-1].entryPoint) { // nothing for me to do, not expecting GOTO ack... HSS_U54_SetState_Ex(target, HSS_State_Idle); pMyMachine->state = BOOT_IDLE; } else if (HSS_Timer_IsElapsed(pMyMachine->startTime, BOOT_WAIT_TIMEOUT)) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s::Timeout after %" PRIu64 " iterations\n", pMyMachine->pMachineName, pMyMachine->executionCount); for (unsigned int i = 0u; i < ARRAY_SIZE(bootMachine); i++) { enum HSSHartId peer = bootMachine[i].hartId; free_msg_index_aux(pInstanceData, peer); } free_msg_index(pInstanceData); pMyMachine->state = BOOT_ERROR; } else { // need to free as received, not all at once... if (check_for_ipi_acks(pMyMachine)) { #if IS_ENABLED(CONFIG_PLATFORM_MPFS) // turn appropriate bit on in SYSREGSCB:MSS_STATUS:BOOT_STATUS to indicate it is up // note: this bit is a status indicator to SW only, and is not functional/does not have side effects mHSS_ReadModWriteRegU32(SYSREGSCB, MSS_STATUS, 0xFFFFu, 1u << (target-1)); #endif mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s::Checking for IPI ACKs: ACK/IDLE ACK\n", pMyMachine->pMachineName); pMyMachine->state = BOOT_IDLE; } } } ///////////////// static void boot_error_handler(struct StateMachine * const pMyMachine) { mHSS_DEBUG_PRINTF(LOG_ERROR, "%s::\n" "*******************************************************************\n" "* WARNING: Boot Error - transitioning to IDLE *\n" "*******************************************************************\n", pMyMachine->pMachineName); pMyMachine->state = BOOT_IDLE; } ///////////////// static void boot_idle_onEntry(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData const * const pInstanceData = pMyMachine->pInstanceData; HSS_PerfCtr_Lap(pInstanceData->perfCtr); //mHSS_DEBUG_PRINTF(LOG_ERROR, "%s:: now at state %d\n", pMyMachine->pMachineName, pMyMachine->state); } static void boot_idle_handler(struct StateMachine * const pMyMachine) { struct HSS_Boot_LocalData const * const pInstanceData = pMyMachine->pInstanceData; IPI_ConsumeIntent(pInstanceData->target, IPI_MSG_BOOT_REQUEST); // check for boot requests } // ---------------------------------------------------------------------------- // PUBLIC API // bool HSS_Boot_Harts(const union HSSHartBitmask restartHartBitmask) { bool result = false; // TODO: should it restart all, or only the non-busy boot state machines?? // for (unsigned int i = 0u; i < ARRAY_SIZE(bootMachine); i++) { if (restartHartBitmask.uint & (1u << bootMachine[i].hartId)) { struct StateMachine * const pMachine = bootMachine[i].pMachine; if (pMachine->state == BOOT_OPENSBI_INIT) { pMachine->state = (stateType_t)BOOT_OPENSBI_INIT; result = true; } else if (pMachine->state == BOOT_SETUP_PMP_COMPLETE) { pMachine->state = (stateType_t)BOOT_INITIALIZATION; result = true; } else if ((pMachine->state == BOOT_INITIALIZATION) || (pMachine->state == BOOT_IDLE)) { pMachine->state = (stateType_t)BOOT_INITIALIZATION; result = true; } else { result = false; mHSS_DEBUG_PRINTF(LOG_ERROR, "invalid hart state %d for u54_%u\n", pMachine->state, i+1u); } } } return result; } enum IPIStatusCode HSS_Boot_RestartCore(enum HSSHartId source) { enum IPIStatusCode result = IPI_FAIL; if (!HSS_Boot_ValidateImage(pBootImage)) { mHSS_DEBUG_PRINTF(LOG_ERROR, "validation failed for u54_%u\n", source); } else if (source != HSS_HART_ALL) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "called for u54_%u\n", source); union HSSHartBitmask restartHartBitmask = { .uint = 0u }; // in interrupts-always-enabled world of the HSS, it would appear less // racey to boot secondary cores first and have them all wait... for (unsigned int i = 0u; i < ARRAY_SIZE(bootMachine); i++) { enum HSSHartId peer = bootMachine[i].hartId; if (peer == source) { continue; } // skip myself if (pBootImage->hart[peer-1].entryPoint == pBootImage->hart[source-1].entryPoint) { // found another hart in same boot set as me... restartHartBitmask.uint |= (1u << peer); } } restartHartBitmask.uint |= (1u << source); if (pBootImage->hart[source-1].numChunks) { if (HSS_Boot_Harts(restartHartBitmask)) { result = IPI_SUCCESS; } } } else { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "called for all harts\n"); const union HSSHartBitmask restartHartBitmask = { .s = { .u54_1 = 1, .u54_2 = 1, .u54_3 = 1, .u54_4 = 1, } }; if (HSS_Boot_Harts(restartHartBitmask)) { result = IPI_SUCCESS; } } return result; } bool HSS_SkipBoot_IsSet(enum HSSHartId target) { bool result = false; assert(pBootImage != NULL); if (pBootImage->hart[target-1].flags & BOOT_FLAG_SKIP_AUTOBOOT) result = true; return result; } enum IPIStatusCode HSS_Boot_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { (void)transaction_id; (void)source; (void)immediate_arg; (void)p_extended_buffer_in_ddr; (void)p_ancilliary_buffer_in_ddr; // boot strap IPI received from one of the U54s... //mHSS_DEBUG_PRINTF(LOG_ERROR, "called for %d\n", source); /* Remoteproc use case 1.1: Elf file loaded by Linux using rproc elf loader, so no need to reload the payload on the HSS */ #if IS_ENABLED(CONFIG_SERVICE_OPENSBI_RPROC) if(immediate_arg == RPROC_BOOT) { struct RemoteProcMsg *rproc_data = (struct RemoteProcMsg *)p_extended_buffer_in_ddr; source = rproc_data->target; struct StateMachine * const pMachine = bootMachine[source - 1].pMachine; pMachine->state = (stateType_t)BOOT_OPENSBI_INIT; } #endif return HSS_Boot_RestartCore(source); return IPI_SUCCESS; } static bool validateCrc_(struct HSS_BootImage *pImageHdr) { bool result = false; uint32_t headerCrc; struct HSS_BootImage shadowHdr = *pImageHdr; shadowHdr.headerCrc = 0u; memset(&(shadowHdr.signature), 0, sizeof(shadowHdr.signature)); size_t crcLen; switch (pImageHdr->version) { case 0u: // pre crypto-signing, the BootImage format was slightly different, so to ensure // no CRC failures on older images, we use a legacy structure size... crcLen = sizeof(struct HSS_BootImage_v0); break; default: crcLen = sizeof(struct HSS_BootImage); break; } headerCrc = CRC32_calculate((const uint8_t *)&shadowHdr, crcLen); if (headerCrc == pImageHdr->headerCrc) { result = true; } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "Checked HSS_BootImage header CRC (%p->%p): calculated %08x vs expected %08x\n", pImageHdr, (char *)pImageHdr + sizeof(struct HSS_BootImage), headerCrc, pImageHdr->headerCrc); } return result; } bool HSS_Boot_ValidateImage(struct HSS_BootImage *pImage) { bool result = false; #if IS_ENABLED(CONFIG_SERVICE_BOOT) // // now have a Full Boot Image, let's check it is a valid one... // { if (!pImage) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Boot Image NULL, ignoring\n"); } else if (pImage->magic != mHSS_BOOT_MAGIC) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Boot Image magic invalid, ignoring\n"); # if IS_ENABLED(CONFIG_CRYPTO_SIGNING) } else if (!HSS_Boot_Secure_CheckCodeSigning(pImage)) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Boot Image failed code signing\n"); # endif } else if (validateCrc_(pImage)) { mHSS_DEBUG_PRINTF(LOG_STATUS, "Boot image passed CRC\n"); // GCC 9.x appears to dislike the pImage cast, and sees dereferencing the // set name as an out-of-bounds... So we'll disable that warning just for // this print... # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Warray-bounds" mHSS_DEBUG_PRINTF(LOG_NORMAL, "Boot image set name: \"%s\"\n", pImage->set_name); # pragma GCC diagnostic pop # if defined(CONFIG_SERVICE_BOOT_CUSTOM_FLOW) result = HSS_Boot_Custom(); # else result = true; # endif } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "Boot image failed CRC\n"); } } #endif return result; } bool HSS_Boot_VerifyMagic(struct HSS_BootImage const * const pImage) { bool result = false; if ((pImage->magic == mHSS_BOOT_MAGIC) || (pImage->magic == mHSS_COMPRESSED_MAGIC)) { result = true; } else { mHSS_DEBUG_PRINTF(LOG_WARN, "magic is %08x vs expected %08x or %08x\n", pImage->magic, mHSS_BOOT_MAGIC, mHSS_COMPRESSED_MAGIC); } return result; } void HSS_Register_Boot_Image(struct HSS_BootImage *pImage) { pBootImage = pImage; } bool HSS_Boot_Custom(void) { int i; size_t numChunks = 0u; size_t firstChunk = 0u; size_t chunkNum = 0u; size_t subChunkOffset = 0u; enum HSSHartId target = 0; struct HSS_BootChunkDesc const *pChunk; struct HSS_BootZIChunkDesc const *pZiChunk; if (!pBootImage) return false; for (i = 0; i < (MAX_NUM_HARTS-1); i++) { if (pBootImage->hart[i].numChunks) { target = i + 1; numChunks = pBootImage->hart[i].numChunks; firstChunk = pBootImage->hart[i].firstChunk; } } if (!numChunks || !target) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Failed to find target HART\n"); return false; } mHSS_DEBUG_PRINTF(LOG_NORMAL, "Zeroing chunks for HART%d\n", target); pZiChunk = (struct HSS_BootZIChunkDesc const *)((char *)pBootImage + pBootImage->ziChunkTableOffset); while (pZiChunk->size != 0u) { if (target == pZiChunk->owner) { #if IS_ENABLED(CONFIG_DEBUG_CHUNK_DOWNLOADS) mHSS_DEBUG_PRINTF(LOG_NORMAL, "%d:ziChunk->0x%x, %u bytes\n", chunkNum, (uintptr_t)pZiChunk->execAddr, pZiChunk->size); #endif boot_do_zero_init_chunk(pZiChunk); chunkNum++; } pZiChunk++; } pChunk = (struct HSS_BootChunkDesc *)((char *)pBootImage + pBootImage->chunkTableOffset); chunkNum = 0u; pChunk += firstChunk; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Downloading chunks for HART%d at 0x%x\n", target, (uintptr_t)pChunk->execAddr); while (pChunk->size != 0u) { if ((pChunk->owner == target) && (HSS_PMP_CheckWrite(target, pChunk->execAddr, pChunk->size))) { #if IS_ENABLED(CONFIG_DEBUG_CHUNK_DOWNLOADS) if (!subChunkOffset) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%d:chunk@0x%x->0x%x, %u bytes\n", chunkNum, (uintptr_t)pChunk->loadAddr, (uintptr_t)pChunk->execAddr, pChunk->size); } #endif // check each hart to see if it wants to transmit #ifdef BOOT_SUB_CHUNK_SIZE boot_do_download_chunk(pChunk, subChunkOffset, BOOT_SUB_CHUNK_SIZE); subChunkOffset += BOOT_SUB_CHUNK_SIZE; if (subChunkOffset > pChunk->size) { subChunkOffset = 0u; chunkNum++; pChunk++; } #else boot_do_download_chunk(pChunk, 0u, pChunk->size); chunkNum++; pChunk++; (void)subChunkOffset; #endif } else { pChunk++; } } #if IS_ENABLED(CONFIG_SERVICE_BOOT_CUSTOM_FLOW) // For custom boot-flow, all U54 HARTs and E51 HART // should jump to common entry point in M-mode uintptr_t custom_entryPoint = pBootImage->hart[target - 1].entryPoint; uint8_t custom_privMode = PRV_M; mHSS_DEBUG_PRINTF(LOG_NORMAL, "All HARTs jumping to entry address 0x%lx in M-mode\n", custom_entryPoint); for (i = 1; i < MAX_NUM_HARTS; i++) { IPI_Send(i, IPI_MSG_OPENSBI_INIT, 0, custom_privMode, (void * const)custom_entryPoint, NULL); } ((void (*)(uintptr_t, uintptr_t))custom_entryPoint)(current_hartid(), 0); #endif return true; } /*! * \brief PMP Setup Handler * * Handle request to U54 from E51 to setup PMPs * */ enum IPIStatusCode HSS_Boot_PMPSetupHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { enum IPIStatusCode result = IPI_FAIL; (void)transaction_id; (void)source; (void)immediate_arg; (void)p_extended_buffer_in_ddr; (void)p_ancilliary_buffer_in_ddr; // request to setup PMP by E51 received enum HSSHartId myHartId = current_hartid(); HSS_U54_SetState(HSS_State_Booting); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Hart%u ", myHartId); if (!pmpSetupFlag[myHartId]) { pmpSetupFlag[myHartId] = true; // PMPs can be setup only once without reboot.... // The E51 ensures that hardware separate is ensured before the U54 code starts running. // To do this, it needs to partition memory and peripheral access, based on configuration // information provided at build time. // // In order to setup RISC-V PMPs, the E51 instructs the U54s to run code routines through // setting their reset vectors and temporarily bringing them out of WFI. This is because // the U54-specific PMP registers are CSRs and thus are only available locally on the // individual U54 and not memory mapped. // // The PMPs will be setup in M-Mode on the U54s and locked so that their configuration // cannot subsequently be changed without reboot to prevent accidental or malicious // modification through software defect. // init_pmp(myHartId); (void)mss_set_apb_bus_cr((uint32_t)LIBERO_SETTING_APBBUS_CR); // //mHSS_DEBUG_PRINTF_EX("setup complete\n"); result = IPI_SUCCESS; } else { //mHSS_DEBUG_PRINTF_EX("PMPs already configured\n"); result = IPI_SUCCESS; } return result; } /*! * \brief PMP Setup Request * * Make request to U54 from E51 to setup PMPs * */ bool HSS_Boot_PMPSetupRequest(enum HSSHartId target, uint32_t *indexOut) { // setup PMP for each hart ... bool result; assert(target != HSS_HART_ALL); // need to setup PMPs on each Hart individually result = IPI_MessageAlloc(indexOut); assert(result); if (result) { result = IPI_MessageDeliver(*indexOut, target, IPI_MSG_PMP_SETUP, 0u, NULL, NULL); // couldn't send message, so free up resources... if (!result) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "u54_%u: failed to send message, so freeing\n", target); IPI_MessageFree(*indexOut); } } return result; } /*! * \brief SBI Setup Request * * Make request to U54 from E51 to setup SBIs * */ bool HSS_Boot_SBISetupRequest(enum HSSHartId target, uint32_t *indexOut) { // setup SBI for each hart ... bool result; assert(target != HSS_HART_ALL); // need to setup SBIs on each Hart individually //mHSS_DEBUG_PRINTF(LOG_NORMAL, "called for u54_%u\n", target); result = IPI_MessageAlloc(indexOut); assert(result); if (result) { result = IPI_MessageDeliver(*indexOut, target, IPI_MSG_OPENSBI_INIT, 0u, NULL, NULL); // couldn't send message, so free up resources... if (!result) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "u54_%u: failed to send message, so freeing\n", target); //TODO IPI_MessageFree(*indexOut); } } return result; } hart-software-services-2022.10/services/boot/hss_boot_service.h000066400000000000000000000052031432224323300245640ustar00rootroot00000000000000#ifndef HSS_BOOT_SERVICE_H #define HSS_BOOT_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Boot Service * */ /*! * \file Boot Boot Service * \brief State Machine and API functions for booting firmware service * */ #ifdef __cplusplus extern "C" { #endif #include "ssmb_ipi.h" #include "hss_types.h" enum IPIStatusCode HSS_Boot_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); enum IPIStatusCode HSS_Boot_PMPSetupHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); bool HSS_Boot_PMPSetupRequest(enum HSSHartId target, uint32_t *indexOut); bool HSS_Boot_SBISetupRequest(enum HSSHartId target, uint32_t *indexOut); enum IPIStatusCode HSS_Boot_RestartCore(enum HSSHartId source); bool HSS_SkipBoot_IsSet(enum HSSHartId target); void HSS_Register_Boot_Image(struct HSS_BootImage *pImage); bool HSS_Boot_Harts(const union HSSHartBitmask restartHartBitmask); bool HSS_Boot_ValidateImage(struct HSS_BootImage *pBootImage); bool HSS_Boot_VerifyMagic(struct HSS_BootImage const * const pBootImage); bool HSS_Boot_Custom(void); extern struct StateMachine boot_service1; extern struct StateMachine boot_service2; extern struct StateMachine boot_service3; extern struct StateMachine boot_service4; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/crypto/000077500000000000000000000000001432224323300214305ustar00rootroot00000000000000hart-software-services-2022.10/services/crypto/Kconfig000066400000000000000000000003561432224323300227370ustar00rootroot00000000000000config SERVICE_CRYPTO bool "Cryptography support" depends on CRYPTO_USER_CRYPTO default n help This feature enables support for crytographic signing of boot images. If you do not know what to do here, say Y. hart-software-services-2022.10/services/crypto/Makefile000066400000000000000000000025771432224323300231030ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Crypto Service SRCS-$(CONFIG_SERVICE_CRYPTO) += \ services/crypto/crypto_service.c \ services/crypto/crypto_api.c \ SRCS-$(CONFIG_CRYPTO_USER_CRYPTO) += \ services/crypto/athena_cal_stub.c \ INCLUDES +=\ -I./services/crypto \ hart-software-services-2022.10/services/crypto/athena_cal.h000066400000000000000000000477661432224323300237040ustar00rootroot00000000000000#ifndef ATHENA_CAL #define ATHENA_CAL /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Athena CAL * */ #ifdef __cplusplus extern "C" { #endif typedef enum { SATASYMKEYTYPE_NULL, SATASYMKEYTYPE_RSA_PUBLIC, SATASYMKEYTYPE_RSA_PRIVATE, SATASYMKEYTYPE_EC_PUBLIC, SATASYMKEYTYPE_EC_PRIVATE } SATASYMKEYTYPE; typedef bool SATBOOL; typedef enum { SATRSAENCTYPE_NULL, SATRSAENCTYPE_PKCS, SATRSAENCTYPE_ANSI, SATRSAENCTYPE_PSS } SATRSAENCTYPE; typedef enum { SATHASHTYPE_SHA1, SATHASHTYPE_SHA224, SATHASHTYPE_SHA256, SATHASHTYPE_SHA384, SATHASHTYPE_SHA512, SATHASHTYPE_SHA512_224, SATHASHTYPE_SHA512_256, } SATHASHTYPE; typedef enum { SATMACTYPE_NULL, SATMACTYPE_SHA1, SATMACTYPE_SHA224, SATMACTYPE_SHA256, SATMACTYPE_SHA384, SATMACTYPE_SHA512, SATMACTYPE_SHA512_224, SATMACTYPE_SHA512_256, SATMACTYPE_AESCMAC128, SATMACTYPE_AESCMAC192, SATMACTYPE_AESCMAC256, SATMACTYPE_AESGMAC } SATMACTYPE; typedef enum { SATR_BADCONTEXT, SATR_BADHANDLE, SATR_BADHASHLEN, SATR_BADHASHTYPE, SATR_BADLEN, SATR_BADMACLEN, SATR_BADMACTYPE, SATR_BADMODE, SATR_BADPARAM, SATR_BADTYPE, SATR_BUSY, SATR_DCMPARMB, SATR_DCMPARMP, SATR_DCMPARMX, SATR_FAIL, SATR_FNP, SATR_KEYSFULL, SATR_LSB0PAD, SATR_MSBICV1, SATR_MSBICV2, SATR_PADLEN, SATR_PAF, SATR_PARITYFLUSH, SATR_ROFATAL, SATR_SIGNFAIL, SATR_SATRESCONTEXT, SATR_SATRESHANDLE, SATR_SATSYMMODE, SATR_SIGNPARMD, SATR_SIGNPARMK, SATR_SUCCESS, SATR_VALIDATEFAIL, SATR_VALPARMB, SATR_VALPARMX, SATR_VALPARMY, SATR_VERIFYFAIL, SATR_VERPARMR, SATR_VERPARMS, } SATR; typedef void* SATRESCONTEXTPTR; typedef enum { SATRES_DEFAULT, SATRES_CALSW } SATRESHANDLE; typedef enum { SATSYMMODE_ECB, SATSYMMODE_CBC, SATSYMMODE_CFB, SATSYMMODE_OFB, SATSYMMODE_CTR, SATSYMMODE_GCM, SATSYMMODE_GHASH, } SATSYMMODE; typedef enum { SATSYMTYPE_AES128, SATSYMTYPE_AES192, SATSYMTYPE_AES256, SATSYMTYPE_AESKS128, SATSYMTYPE_AESKS192, SATSYMTYPE_AESKS256, } SATSYMTYPE; typedef enum { SATSYMKEYSIZE_AES128, SATSYMKEYSIZE_AES256, } SATSYMKEYSIZE; typedef uint8_t SATUINT8_t; typedef uint16_t SATUINT16_t; typedef uint32_t SATUINT32_t; typedef uint64_t SATUINT64_t; typedef void * DRBGCTXPTR; #define SAT_TRUE true #define SAT_FALSE false #define SAT_NULL 0 // General Functions SATR CALIni(void); SATR CALPurge52(SATBOOL bVerify); SATR CALPKTrfRes(SATBOOL bBlock); SATR CALPreCompute(const uint32_t *puiMod, uint32_t *puiMu, uint32_t uiModLen); // Conventional Public Key Crypto Functions SATR CALExpo(const uint32_t *puiBase, const uint32_t *puiExpo, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiExpLen, uint32_t uiModLen, uint32_t *puiResult); SATR CALModRed(const uint32_t *puiA, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiALen, uint32_t uiModLen, uint32_t *puiResult); SATR CALMMult(const uint32_t *puiA, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiModLen, uint32_t *puiResult); SATR CALMMultAdd(const uint32_t *puiA, const uint32_t *puiB, const uint32_t *puiC, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiModLen, uint32_t *puiResult); SATR CALRSACRT(const uint32_t *puiCipher, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiLen, uint32_t *puiPlain); SATR CALRSACRTSign(SATRSAENCTYPE eRSAEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiLen, uint32_t *puiPlain); SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiMsg, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiModLen, uint32_t uiMsgLen, uint32_t *puiSig, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiD, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiModLen, uint32_t *puiSig); SATR CALRSASignVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiE, const uint32_t uiExpLen, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiModLen, uint32_t *puiSig); SATR CALDSASignHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiG, const uint32_t *puiK, const uint32_t *puiX, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALDSAVerifyHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiG, const uint32_t *puiY, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, SATBOOL bDMA, uint32_t uiDMAChConfig); // Elliptic Curve Crypto Functions SATR CALECMult(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiLen, uint32_t uiPtCompress, uint32_t *puiRx, uint32_t *puiRy); SATR CALECMultTwist(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiN, uint32_t uiLen, uint32_t *puiRx, uint32_t *puiRy); SATR CALECMultAdd(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiLen, uint32_t uiPtPCompress, uint32_t uiPtQCompress, uint32_t *puiRx, uint32_t *puiRy); SATR CALECPtValidate(const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiLen); SATR CALECKeyPairGen(const uint32_t *puiC, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiNM1, const uint32_t *puiNM1Mu, const uint32_t *puiB, uint32_t *puiD, uint32_t *puiQx, uint32_t *puiQy, uint32_t uiLen); SATR CALECDHC(const uint32_t *puiS, const uint32_t *puiWx, const uint32_t *puiWy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiK, const uint32_t *puiR, const uint32_t *puiRMu, uint32_t uiLen, uint32_t uiPtCompress, uint32_t* puiZ); SATR CALECDSASign(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS); SATR CALECDSAVerify(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress); SATR CALECDSASignHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, const uint32_t *puiSigR, const uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALECDSAVerifyHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALECDSASignTwist(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS); SATR CALECDSAVerifyTwist(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress); SATR CALECDSASignTwistHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALECDSAVerifyTwistHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress, SATBOOL bDMA, uint32_t uiDMAChConfig); // Functions with SCA counter measures SATR CALExpoCM(const uint32_t *puiBase, const uint32_t *puiExpo, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiExpLen, uint32_t uiModLen, uint32_t *puiResult); SATR CALRSACRTCM(const uint32_t *puiCipher, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiE, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiELen, uint32_t *puiPlain); SATR CALRSACRTSignCM(SATRSAENCTYPE eRSAEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiE, uint32_t uiELen, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSig); SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiMsg, const uint32_t *puiE, uint32_t uiELen, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiMsgLen, uint32_t uiModLen, const uint32_t *puiSig, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALDSASignCM(const uint32_t *puiHash, const uint32_t *puiG, const uint32_t *puiK, const uint32_t *puiX, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, const uint32_t *puiSigR, const uint32_t *puiSigS); SATR CALDSASignHashCM(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiG, const uint32_t *puiK, const uint32_t *puiX, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALECMultCM(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiN, uint32_t uiLen, uint32_t uiPtCompress, uint32_t *puiRx, uint32_t *puiRy); SATR CALECMultTwistCM(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiN, uint32_t uiLen, uint32_t *puiRx, uint32_t *puiRy); SATR CALECDSASignCM(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS); SATR CALECDSASignHashCM(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig); SATR CALECDSASignTwistCM(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS); // CAL Synmmetric Crypto Functions SATR CALSymTrfRes(SATBOOL bBlock); SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen); SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen); SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig); // Combined Encryption-Authentication Functions SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen); SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen); SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiDMAChConfig); SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiDMAChConfig); SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF) ; SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF); SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig); // Hashes SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash); SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig); // Multiple Call Hash Functions SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen); SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen); SATR CALHashRead(void *pHash); // Hash Functions with Context Switching SATR CALHashCtx(const SATRESHANDLE hResource, SATRESCONTEXTPTR const pContext, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash, const SATBOOL bFinal); SATR CALHashCtxIni(SATRESCONTEXTPTR const pContext, const SATHASHTYPE eHashType); SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC); SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC, SATUINT32_t uiDMAChConfig); // Multiple Call MAC Functions SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen); SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen); SATR CALMACRead(const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, void *pMAC); // MAC Functions with Context Switching SATR CALMACCtx(const SATRESHANDLE hResource, SATRESCONTEXTPTR const pContext, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash, const SATBOOL bFinal); SATR CALMACCtxIni(SATRESCONTEXTPTR const pContext, SATHASHTYPE eHashType, const SATUINT32_t *puiKey, SATUINT32_t uiKey); // Random Number Generation SATR CALNRBGSetTestEntropy(SATUINT32_t *puiEntropy, SATUINT32_t uiEntLen32); SATR CALNRBGAddTestEntropy(SATUINT32_t *puiEntropy, SATUINT32_t uiEntLen32); SATR CALNRBGGetEntropy(SATUINT32_t *puiEntropy, SATUINT32_t uiEntLen32, SATBOOL bTesting); SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, SATUINT32_t *puiStatus); SATUINT32_t CALNRBGHealthStatus(void); // Deterministic Random Bit Generation (SP800-90A) SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting); SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen); SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks); SATR CALDRBGUninstantiate(void); SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt); SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt); // Key Wrap and Unwrap SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, SATBOOL bWrap); SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, SATBOOL bWrap); // Context Management SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource); SATR CALContextLoad(const SATRESHANDLE hResource, SATRESCONTEXTPTR const pContext); SATR CALContextRemove(const SATRESHANDLE hResource); SATR CALContextUnload(const SATRESHANDLE hResource); // Key Derivation Functions SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t *puiKey, const uint8_t uiOpType, const SATUINT32_t *puiPath, const SATUINT32_t *puiKeyOut); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/crypto/athena_cal_stub.c000066400000000000000000000465471432224323300247300ustar00rootroot00000000000000#include #include #include #include "athena_cal.h" // General Functions SATR CALIni(void) { return SATR_SUCCESS; } SATR CALPurge52(SATBOOL bVerify) { (void)bVerify; return SATR_SUCCESS; } SATR CALPKTrfRes(SATBOOL bBlock) { (void)bBlock; return SATR_SUCCESS; } SATR CALPreCompute(const uint32_t *puiMod, uint32_t *puiMu, uint32_t uiModLen) { (void)puiMod; (void)puiMu; (void)uiModLen; return SATR_SUCCESS; } // Conventional Public Key Crypto Functions SATR CALExpo(const uint32_t *puiBase, const uint32_t *puiExpo, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiExpLen, uint32_t uiModLen, uint32_t *puiResult) { (void)puiBase; (void)puiExpo; (void)puiMod; (void)puiMu; (void)uiExpLen; (void)uiModLen; (void)puiResult; return SATR_SUCCESS; } SATR CALModRed(const uint32_t *puiA, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiALen, uint32_t uiModLen, uint32_t *puiResult) { (void)puiA; (void)puiMod; (void)puiMu; (void)puiMod; (void)uiALen; (void)uiModLen; (void)puiResult; return SATR_SUCCESS; } SATR CALMMult(const uint32_t *puiA, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiModLen, uint32_t *puiResult) { (void)puiA; (void)puiB; (void)puiMod; (void)puiMu; (void)uiModLen; (void)puiResult; return SATR_SUCCESS; } SATR CALMMultAdd(const uint32_t *puiA, const uint32_t *puiB, const uint32_t *puiC, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiModLen, uint32_t *puiResult) { (void)puiA; (void)puiB; (void)puiC; (void)puiMod; (void)puiMu; (void)uiModLen; (void)puiResult; return SATR_SUCCESS; } SATR CALRSACRT(const uint32_t *puiCipher, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiLen, uint32_t *puiPlain) { return SATR_SUCCESS; } SATR CALRSACRTSign(SATRSAENCTYPE eRSAEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiLen, uint32_t *puiPlain) { return SATR_SUCCESS; } SATR CALRSACRTSignHash(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiMsg, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiModLen, uint32_t uiMsgLen, uint32_t *puiSig, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALRSASign(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiD, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiModLen, uint32_t *puiSig) { return SATR_SUCCESS; } SATR CALRSASignVerify(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiE, const uint32_t uiExpLen, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiModLen, uint32_t *puiSig) { return SATR_SUCCESS; } SATR CALDSASignHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiG, const uint32_t *puiK, const uint32_t *puiX, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALDSAVerifyHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiG, const uint32_t *puiY, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } // Elliptic Curve Crypto Functions SATR CALECMult(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiLen, uint32_t uiPtCompress, uint32_t *puiRx, uint32_t *puiRy) { return SATR_SUCCESS; } SATR CALECMultTwist(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiN, uint32_t uiLen, uint32_t *puiRx, uint32_t *puiRy) { return SATR_SUCCESS; } SATR CALECMultAdd(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiLen, uint32_t uiPtPCompress, uint32_t uiPtQCompress, uint32_t *puiRx, uint32_t *puiRy) { return SATR_SUCCESS; } SATR CALECPtValidate(const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiLen) { return SATR_SUCCESS; } SATR CALECKeyPairGen(const uint32_t *puiC, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiNM1, const uint32_t *puiNM1Mu, const uint32_t *puiB, uint32_t *puiD, uint32_t *puiQx, uint32_t *puiQy, uint32_t uiLen) { return SATR_SUCCESS; } SATR CALECDHC(const uint32_t *puiS, const uint32_t *puiWx, const uint32_t *puiWy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiK, const uint32_t *puiR, const uint32_t *puiRMu, uint32_t uiLen, uint32_t uiPtCompress, uint32_t* puiZ) { return SATR_SUCCESS; } SATR CALECDSASign(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS) { return SATR_SUCCESS; } SATR CALECDSAVerify(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress) { return SATR_SUCCESS; } SATR CALECDSASignHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, const uint32_t *puiSigR, const uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALECDSAVerifyHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALECDSASignTwist(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS) { return SATR_SUCCESS; } SATR CALECDSAVerifyTwist(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress) { return SATR_SUCCESS; } SATR CALECDSASignTwistHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALECDSAVerifyTwistHash(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiQx, const uint32_t *puiQy, const uint32_t *puiSigR, const uint32_t *puiSigS, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiPtCompress, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } // Functions with SCA counter measures SATR CALExpoCM(const uint32_t *puiBase, const uint32_t *puiExpo, const uint32_t *puiMod, const uint32_t *puiMu, uint32_t uiExpLen, uint32_t uiModLen, uint32_t *puiResult) { return SATR_SUCCESS; } SATR CALRSACRTCM(const uint32_t *puiCipher, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiE, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t uiELen, uint32_t *puiPlain) { return SATR_SUCCESS; } SATR CALRSACRTSignCM(SATRSAENCTYPE eRSAEncod, SATHASHTYPE eHashType, const uint32_t *puiHash, const uint32_t *puiE, uint32_t uiELen, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSig) { return SATR_SUCCESS; } SATR CALRSACRTSignHashCM(SATRSAENCTYPE eRsaEncod, SATHASHTYPE eHashType, const uint32_t *puiMsg, const uint32_t *puiE, uint32_t uiELen, const uint32_t *puiQInv, const uint32_t *puiDP, const uint32_t *puiDQ, const uint32_t *puiP, const uint32_t *puiQ, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiMsgLen, uint32_t uiModLen, const uint32_t *puiSig, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALDSASignCM(const uint32_t *puiHash, const uint32_t *puiG, const uint32_t *puiK, const uint32_t *puiX, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, const uint32_t *puiSigR, const uint32_t *puiSigS) { return SATR_SUCCESS; } SATR CALDSASignHashCM(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiG, const uint32_t *puiK, const uint32_t *puiX, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiQ, const uint32_t *puiQMu, uint32_t uiN, uint32_t uiL, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALECMultCM(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiN, uint32_t uiLen, uint32_t uiPtCompress, uint32_t *puiRx, uint32_t *puiRy) { return SATR_SUCCESS; } SATR CALECMultTwistCM(const uint32_t *puiMul, const uint32_t *puiPx, const uint32_t *puiPy, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiMod, const uint32_t *puiMu, const uint32_t *puiN, uint32_t uiLen, uint32_t *puiRx, uint32_t *puiRy) { return SATR_SUCCESS; } SATR CALECDSASignCM(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS) { return SATR_SUCCESS; } SATR CALECDSASignHashCM(const uint32_t *puiMsg, SATHASHTYPE eHashType, uint32_t uiMsgLen, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS, SATBOOL bDMA, uint32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALECDSASignTwistCM(const uint32_t *puiHash, const uint32_t *puiGx, const uint32_t *puiGy, const uint32_t *puiK, const uint32_t *puiD, const uint32_t *puiB, const uint32_t *puiZ, const uint32_t *puiP, const uint32_t *puiPMu, const uint32_t *puiN, const uint32_t *puiNMu, uint32_t uiLen, uint32_t *puiSigR, uint32_t *puiSigS) { return SATR_SUCCESS; } // CAL Synmmetric Crypto Functions SATR CALSymTrfRes(SATBOOL bBlock) { return SATR_SUCCESS; } SATR CALSymEncrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen) { return SATR_SUCCESS; } SATR CALSymDecrypt(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen) { return SATR_SUCCESS; } SATR CALSymEncryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALSymDecryptDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } // Combined Encryption-Authentication Functions SATR CALSymEncAuth(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen) { return SATR_SUCCESS; } SATR CALSymDecVerify(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiMACLen) { return SATR_SUCCESS; } SATR CALSymEncAuthDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALSymDecVerifyDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, const void *pSrc, void *pDest, SATUINT32_t uiEncLen, void *pAuth, SATUINT32_t uiAuthLen, void *pMAC, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALSymEncryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF) { return SATR_SUCCESS; } SATR CALSymDecryptKR(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF) { return SATR_SUCCESS; } SATR CALSymEncryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } SATR CALSymDecryptKRDMA(SATSYMTYPE eSymType, const SATUINT32_t *puiKey, SATSYMMODE eMode, void *pIV, SATBOOL bLoadIV, const void *pSrc, void *pDest, SATUINT32_t uiLen, SATUINT32_t uiKRF, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } // Hashes SATR CALHash(SATHASHTYPE eHashType, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash) { return SATR_SUCCESS; } SATR CALHashDMA(SATHASHTYPE eHashType, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } // Multiple Call Hash Functions SATR CALHashIni(SATHASHTYPE eHashType, SATUINT32_t uiMsgLen) { return SATR_SUCCESS; } SATR CALHashWrite(const void *pBuffer, SATUINT32_t uiBufLen) { return SATR_SUCCESS; } SATR CALHashRead(void *pHash) { return SATR_SUCCESS; } // Hash Functions with Context Switching SATR CALHashCtx(const SATRESHANDLE hResource, SATRESCONTEXTPTR const pContext, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash, const SATBOOL bFinal) { return SATR_SUCCESS; } SATR CALHashCtxIni(SATRESCONTEXTPTR const pContext, const SATHASHTYPE eHashType) { return SATR_SUCCESS; } SATR CALMAC(SATMACTYPE eMACType, const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC) { return SATR_SUCCESS; } SATR CALMACDMA(SATMACTYPE eMACType, const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, const void *pMsg, SATUINT32_t uiMsgLen, void *pMAC, SATUINT32_t uiDMAChConfig) { return SATR_SUCCESS; } // Multiple Call MAC Functions SATR CALMACIni(SATMACTYPE eMACType, const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, SATUINT32_t uiMsgLen) { return SATR_SUCCESS; } SATR CALMACWrite(const void *pBuffer, SATUINT32_t uiBufLen) { return SATR_SUCCESS; } SATR CALMACRead(const SATUINT32_t *puiKey, SATUINT32_t uiKeyLen, void *pMAC) { return SATR_SUCCESS; } // MAC Functions with Context Switching SATR CALMACCtx(const SATRESHANDLE hResource, SATRESCONTEXTPTR const pContext, const void *pMsg, SATUINT32_t uiMsgLen, void *pHash, const SATBOOL bFinal) { return SATR_SUCCESS; } SATR CALMACCtxIni(SATRESCONTEXTPTR const pContext, SATHASHTYPE eHashType, const SATUINT32_t *puiKey, SATUINT32_t uiKey) { return SATR_SUCCESS; } // Random Number Generation SATR CALNRBGSetTestEntropy(SATUINT32_t *puiEntropy, SATUINT32_t uiEntLen32) { return SATR_SUCCESS; } SATR CALNRBGAddTestEntropy(SATUINT32_t *puiEntropy, SATUINT32_t uiEntLen32) { return SATR_SUCCESS; } SATR CALNRBGGetEntropy(SATUINT32_t *puiEntropy, SATUINT32_t uiEntLen32, SATBOOL bTesting) { return SATR_SUCCESS; } SATR CALNRBGConfig(SATUINT32_t uiWriteEn, SATUINT32_t uiCSR, SATUINT32_t uiCntLim, SATUINT32_t uiVoTimer, SATUINT32_t uiFMsk, SATUINT32_t *puiStatus) { return SATR_SUCCESS; } SATUINT32_t CALNRBGHealthStatus(void) { return SATR_SUCCESS; } // Deterministic Random Bit Generation (SP800-90A) SATR CALDRBGInstantiate(const SATUINT32_t *puiNonce, SATUINT32_t uiNonceLen, const SATUINT32_t *puiPzStr, SATUINT32_t uiPzStrLen, SATSYMKEYSIZE eStrength, SATUINT32_t uiEntropyFactor, SATUINT32_t uiReseedLim, SATBOOL bTesting) { return SATR_SUCCESS; } SATR CALDRBGReseed(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen) { return SATR_SUCCESS; } SATR CALDRBGGenerate(const SATUINT32_t *puiAddIn, SATUINT32_t uiAddInLen, SATBOOL bPredResist, SATUINT32_t *puiOut, SATUINT32_t uiOutBlocks) { return SATR_SUCCESS; } SATR CALDRBGUninstantiate(void) { return SATR_SUCCESS; } SATR CALDRBGGetCtx(DRBGCTXPTR drbgCtxExt) { return SATR_SUCCESS; } SATR CALDRBGLoadCtx(DRBGCTXPTR drbgCtxExt) { return SATR_SUCCESS; } // Key Wrap and Unwrap SATR CALSymKw(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, SATBOOL bWrap) { return SATR_SUCCESS; } SATR CALSymKwp(SATSYMTYPE eSymType, const SATUINT32_t *puiKEK, const SATUINT32_t *puiInKey, SATUINT32_t *puiOutKey, SATUINT32_t uiLen, SATBOOL bWrap) { return SATR_SUCCESS; } // Context Management SATRESCONTEXTPTR CALContextCurrent(const SATRESHANDLE hResource) { return NULL; } SATR CALContextLoad(const SATRESHANDLE hResource, SATRESCONTEXTPTR const pContext) { return SATR_SUCCESS; } SATR CALContextRemove(const SATRESHANDLE hResource) { return SATR_SUCCESS; } SATR CALContextUnload(const SATRESHANDLE hResource) { return SATR_SUCCESS; } // Key Derivation Functions SATR CALKeyTree(SATBOOL bPathSizeSel, const SATUINT32_t *puiKey, const uint8_t uiOpType, const SATUINT32_t *puiPath, const SATUINT32_t *puiKeyOut) { return SATR_SUCCESS; } hart-software-services-2022.10/services/crypto/calenum.h000066400000000000000000000000541432224323300232240ustar00rootroot00000000000000#ifndef CALENUM_H #define CALENUM_H #endif hart-software-services-2022.10/services/crypto/calini.h000066400000000000000000000001041432224323300230330ustar00rootroot00000000000000#ifndef CAL_INI_H #define CAL_INI_H #include "athena_cal.h" #endif hart-software-services-2022.10/services/crypto/crypto_api.c000066400000000000000000000017721432224323300237540ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Crypto Driver API * \brief MSS Crypto Driver API */ #include #include #include "ssmb_ipi.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "crypto_types.h" #include "crypto_service.h" void HSS_Crypto_Init(void) { // placeholder function incase any Athena or G5C specific initialisation is required... mHSS_DEBUG_PRINTF(LOG_NORMAL, "called\n"); } //static uint32_t dummy = 0u; //static uint32_t* pSSI_SystemServiceDescriptor = &dummy; void HSS_SecureNVMWrite(void const *pPayload, const size_t count) { (void)pPayload; (void)count; // setup state machine to do transfer } void HSS_SecureNVMRead(void *pPayload, const size_t count) { (void)pPayload; (void)count; // setup state machine to do transfer } hart-software-services-2022.10/services/crypto/crypto_service.c000066400000000000000000000044571432224323300246460ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Crypto Driver State Machine * \brief MSS Crypto Driver */ #include #include #include "ssmb_ipi.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "crypto_types.h" #include "athena_cal.h" static void crypto_init_handler(struct StateMachine * const pMyMachine); static void crypto_state1_handler(struct StateMachine * const pMyMachine); static void crypto_lastState_handler(struct StateMachine * const pMyMachine); /*! * \brief Crypto Driver States */ enum CryptoStatesEnum { CRYPTO_INITIALIZATION, CRYPTO_STATE1, CRYPTO_LAST_STATE, CRYPTO_NUM_STATES = CRYPTO_LAST_STATE+1 }; /*! * \brief Crypto Driver State Descriptors */ static const struct StateDesc crypto_state_descs[] = { { (const stateType_t)CRYPTO_INITIALIZATION, (const char *)"init", NULL, NULL, &crypto_init_handler }, { (const stateType_t)CRYPTO_STATE1, (const char *)"state1", NULL, NULL, &crypto_state1_handler }, { (const stateType_t)CRYPTO_LAST_STATE, (const char *)"lastState", NULL, NULL, &crypto_lastState_handler } }; /*! * \brief Crypto Driver State Machine */ struct StateMachine crypto_service = { (stateType_t)CRYPTO_INITIALIZATION, (stateType_t)SM_INVALID_STATE, (const uint32_t)CRYPTO_NUM_STATES, (const char *)"crypto_service", 0u, 0u, 0u, crypto_state_descs, false, 0u, NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void crypto_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state++; } ///////////////// static uint32_t i = HSS_HART_U54_1; static void crypto_state1_handler(struct StateMachine * const pMyMachine) { // check each core to see if it wants to transmit if (IPI_GetQueuePendingCount(i)) { IPI_ConsumeIntent(i, IPI_MSG_POWERMODE); } i = (i + 1u) % HSS_HART_NUM_PEERS; } ///////////////// static void crypto_lastState_handler(struct StateMachine * const pMyMachine) { pMyMachine->state = CRYPTO_INITIALIZATION; } hart-software-services-2022.10/services/crypto/crypto_service.h000066400000000000000000000033741432224323300246500ustar00rootroot00000000000000#ifndef MPFS_HSS_CRYPTO_SERVICE_H #define MPFS_HSS_CRYPTO_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Crypto Service * */ /*! * \file Crypto Driver State Machine * \brief MSS Crypto Driver */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" void HSS_Crypto_Init(void); void HSS_SecureNVMWrite(void const *pPayload, const size_t count); void HSS_SecureNVMRead(void *pPayload, const size_t count); extern struct StateMachine crypto_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/crypto/crypto_types.h000066400000000000000000000050461432224323300243520ustar00rootroot00000000000000#ifndef HSS_CRYPTO_TYPES_H #define HSS_CRYPTO_TYPES_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Crypto types * */ /*! * \file Crypto Driver State Machine * \brief MSS Crypto Driver */ #ifdef __cplusplus extern "C" { #endif #include struct SNVMWriteNonAuthPlaintext { uint8_t SVNMADDR; uint8_t RESERVED[3]; uint8_t PT[252]; } __attribute__ ((packed)); struct SNVMWriteAuthPlaintext { uint8_t SVNMADDR; uint8_t RESERVED[3]; uint8_t PT[236]; uint8_t USK[12]; } __attribute__ ((packed)); struct SNVMWriteAuthCiphertext { uint8_t SVNMADDR; uint8_t RESERVED[3]; uint8_t CT[236]; uint8_t USK[12]; } __attribute__ ((packed)); #if 0 #ifdef __GNUC__ #define GCC_VERSION ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__)) #if GCC_VERSION > 40300 // gcc (>4.3) supports C11 static asserts, so use them to ensure that our packing is okay... // _Static_assert(sizeof(struct SNVMWriteNonAuthPlaintext)==256, "size of struct SNVMWriteNonAuthPlaintext must be 256 bytes"); _Static_assert(sizeof(struct SNVMWriteAuthPlaintext)==252, "size of struct SNVMWriteNonAuthPlaintext must be 252 bytes"); _Static_assert(sizeof(struct SNVMWriteAuthCiphertext)==252, "size of struct SNVMWriteNonAuthPlaintext must be 252 bytes"); #endif #endif #endif #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/crypto/hash.h000066400000000000000000000000461432224323300225240ustar00rootroot00000000000000#ifndef HASH_H #define HASH_H #endif hart-software-services-2022.10/services/ddr/000077500000000000000000000000001432224323300206615ustar00rootroot00000000000000hart-software-services-2022.10/services/ddr/Kconfig000066400000000000000000000001541432224323300221640ustar00rootroot00000000000000config SERVICE_DDR def_bool y help This feature enables support for the E51 to setup DDR. hart-software-services-2022.10/services/ddr/Makefile000066400000000000000000000025031432224323300223210ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # DDR Refresh Service SRCS-y += \ services/ddr/ddr_service.c \ services/ddr/ddr_api.c \ INCLUDES +=\ -I./services/ddr \ services/ddr/ddr_api.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/ddr/ddr_api.c000066400000000000000000000042501432224323300224300ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file DDR related utilities * \brief DDR utilities */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include "ddr_service.h" extern const uint64_t __ddr_start; extern const uint64_t __ddr_end; extern const uint64_t __ddrhi_startAddr; extern const uint64_t __ddrhi_end; ///////////////// // // We only want to specify the DDR location and size in one place - the linker script // // ddr_end is too high for the RV64 toolchain, sadly. We get an error message concerning // "relocation truncated to fit: R_RISCV_PCREL_HI20 against symbol `__ddr_end' defined in // .text.init section" as it is above 4GiB away from eNVM. // // See https://github.com/riscv/riscv-gnu-toolchain/issues/103 for background. // // So we can't easily do ... // // extern uint64_t __ddr_end; // const uintptr_t ddr_size = (size_t)((char *)&__ddr_end - (char *)&__ddr_start); // // However, we can workaround by using the GNU assembler to store the DDR size into a 64-bit memory // location and use this size in our C code // asm(" .globl __ddr_size\n" " .type __ddr_size, @object\n" " .globl __ddrhi_size\n" " .type __ddrhi_size, @object\n" " .globl __ddrhi_size\n" " .type __ddrhi_size, @object\n" " .globl __ddrhi_startAddr\n" " .type __ddrhi_startAddr, @object\n" " .align 3\n" "__ddr_size: .quad (__ddr_end-__ddr_start)\n" "__ddrhi_startAddr: .quad(__ddrhi_start)\n" "__ddrhi_size: .quad (__ddrhi_end-__ddrhi_start)\n" ); extern const size_t __ddr_size; extern const size_t __ddrhi_size; size_t HSS_DDR_GetSize(void) { return __ddr_size; } size_t HSS_DDRHi_GetSize(void) { return __ddrhi_size; } uintptr_t HSS_DDR_GetStart(void) { return (uintptr_t)&__ddr_start; } uintptr_t HSS_DDRHi_GetStart(void) { return (uintptr_t)__ddrhi_startAddr; } void HSS_DDR_Train(void) { //mHSS_DEBUG_PRINTF("running DDR training on hart %u...\n", current_hartid()); } hart-software-services-2022.10/services/ddr/ddr_service.c000066400000000000000000000050331432224323300233170ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file DDR Retraining Driver State Machine * \brief DDR Retraining */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ddr_service.h" #include "ssmb_ipi.h" /* Timeouts */ #define DDR_IDLE_PERIODIC_TIMEOUT (ONE_SEC * 60llu * 60llu * 10llu) /* Module Prototypes (states) */ static void ddr_init_handler(struct StateMachine * const pMyMachine); static void ddr_idle_handler(struct StateMachine * const pMyMachine); static void ddr_retrain_handler(struct StateMachine * const pMyMachine); /*! * \brief DDR Driver States */ enum DDRStatesEnum { DDR_INITIALIZATION, DDR_IDLE, DDR_RETRAIN, DDR_NUM_STATES = DDR_IDLE+1 }; /*! * \brief DDR Driver State Descriptors */ static const struct StateDesc ddr_state_descs[] = { { (const stateType_t)DDR_INITIALIZATION, (const char *)"Init", NULL, NULL, &ddr_init_handler }, { (const stateType_t)DDR_IDLE, (const char *)"Idle", NULL, NULL, &ddr_idle_handler }, { (const stateType_t)DDR_RETRAIN, (const char *)"Retrain", NULL, NULL, &ddr_retrain_handler } }; /*! * \brief DDR Driver State Machine */ struct StateMachine ddr_service = { .state = (stateType_t)DDR_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)DDR_NUM_STATES, .pMachineName = (const char *)"ddr_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = ddr_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void ddr_init_handler(struct StateMachine * const pMyMachine) { (void) pMyMachine; pMyMachine->state = DDR_IDLE; } ///////////////// static void ddr_idle_handler(struct StateMachine * const pMyMachine) { (void) pMyMachine; if (HSS_Timer_IsElapsed(pMyMachine->startTime, (HSSTicks_t)DDR_IDLE_PERIODIC_TIMEOUT)) { pMyMachine->state = DDR_RETRAIN; } } ///////////////// static void ddr_retrain_handler(struct StateMachine * const pMyMachine) { (void) pMyMachine; HSS_DDR_Train(); pMyMachine->state = DDR_IDLE; } hart-software-services-2022.10/services/ddr/ddr_service.h000066400000000000000000000033731432224323300233310ustar00rootroot00000000000000#ifndef HSS_DDR_SERVICE_H #define HSS_DDR_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - DDR Retraining Service * */ /*! * \file DDR Retraining Service State Machine * \brief DDR Retraining */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" size_t HSS_DDR_GetSize(void); uintptr_t HSS_DDR_GetStart(void); size_t HSS_DDRHi_GetSize(void); uintptr_t HSS_DDRHi_GetStart(void); void HSS_DDR_Train(void); extern struct StateMachine ddr_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/goto/000077500000000000000000000000001432224323300210605ustar00rootroot00000000000000hart-software-services-2022.10/services/goto/Kconfig000066400000000000000000000003341432224323300223630ustar00rootroot00000000000000config SERVICE_GOTO bool "GOTO support" default y help This feature enables support for the E51 to instruct a U54 application hart to execute code in an aribtrary location of memory. hart-software-services-2022.10/services/goto/Makefile000066400000000000000000000025031432224323300225200ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # U54-GOTO Service SRCS-$(CONFIG_SERVICE_GOTO) += \ services/goto/goto_service.c \ INCLUDES +=\ -I./services/goto \ services/goto/goto_service.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/goto/goto_service.c000066400000000000000000000147571432224323300237320ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Goto State Machine * \brief U54 goto */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include #include "csr_helper.h" #include "ssmb_ipi.h" #include "goto_service.h" #if IS_ENABLED(CONFIG_SERVICE_BOOT) # include "hss_boot_pmp.h" #endif #include "mpfs_reg_map.h" #include "csr_helper.h" #include "hss_atomic.h" #include "u54_state.h" static void goto_init_handler(struct StateMachine * const pMyMachine); static void goto_idle_handler(struct StateMachine * const pMyMachine); /*! * \brief GOTO Driver States */ enum GotoStatesEnum { GOTO_INITIALIZATION, GOTO_IDLE, GOTO_NUM_STATES = GOTO_IDLE+1 }; /*! * \brief GOTO Driver State Descriptors */ static const struct StateDesc goto_state_descs[] = { { (const stateType_t)GOTO_INITIALIZATION, (const char *)"init", NULL, NULL, &goto_init_handler }, { (const stateType_t)GOTO_IDLE, (const char *)"idle", NULL, NULL, &goto_idle_handler }, }; /*! * \brief GOTO Driver State Machine */ struct StateMachine goto_service = { .state = (stateType_t)GOTO_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)GOTO_NUM_STATES, .pMachineName = (const char *)"goto_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = goto_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL, }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void goto_init_handler(struct StateMachine * const pMyMachine) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "called\n"); pMyMachine->state++; } ///////////////// static void goto_idle_handler(struct StateMachine * const pMyMachine) { (void)pMyMachine; // unused mHSS_DEBUG_PRINTF(LOG_NORMAL, "called\n"); } ///////////////// enum IPIStatusCode HSS_GOTO_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer, void *p_ancilliary_buffer_in_ddr) { enum IPIStatusCode result = IPI_FAIL; (void)p_ancilliary_buffer_in_ddr; int hartid = current_hartid(); if (source != HSS_HART_E51) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "security policy prevented GOTO request from u54_%d\n", source); } else if (hartid == HSS_HART_E51) { mHSS_DEBUG_PRINTF(LOG_ERROR, "u54_%d: request prohibited by policy\n", HSS_HART_E51); } else { // the following should always be true if we have consumed intents for GOTO... assert(p_extended_buffer != NULL); // we ain't coming back from the GOTO, so need to ACK here... IPI_Send(source, IPI_MSG_ACK_COMPLETE, transaction_id, IPI_SUCCESS, NULL, NULL); IPI_MessageUpdateStatus(transaction_id, IPI_IDLE); // free the IPI struct IPI_Outbox_Msg *pMsg = IPI_DirectionToFirstMsgInQueue(source, current_hartid()); size_t i; for (i = 0u; i < IPI_MAX_NUM_QUEUE_MESSAGES; i++) { if (pMsg->transaction_id == transaction_id) { break; } pMsg++; } // if message found process it... if (pMsg->transaction_id == transaction_id) { pMsg->msg_type = IPI_MSG_NO_MESSAGE; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Address to execute is %p\n", (void *)p_extended_buffer); CSR_ClearMSIP(); uint32_t mstatus_val = csr_read(CSR_MSTATUS); mstatus_val = EXTRACT_FIELD(mstatus_val, MSTATUS_MPIE); csr_write(CSR_MSTATUS, mstatus_val); csr_write(CSR_MIE, 0u); result = IPI_SUCCESS; } if (result != IPI_FAIL) { // From the v1.10 RISC-V Priileged Spec: // The MRET, SRET, or URET instructions are used to return from traps in M-mode, S-mode, // or U-mode respectively. When executing an xRET instruction, supposing x PP holds the // value y, x IE is set to x PIE; the privilege mode is changed to y; x PIE is set to 1; // and x PP is set to U (or M if user-mode is not supported). const uint32_t next_mode = immediate_arg; HSS_U54_SetState(HSS_State_Running); #if IS_ENABLED(CONFIG_OPENSBI) sbi_hart_switch_mode(hartid, 0u, (unsigned long)p_extended_buffer, next_mode, false /*next_virt -> required hypervisor */); #else // set MSTATUS.MPP to Supervisor mode, and set MSTATUS.MPIE to 1 uint32_t mstatus_val = csr_read(mstatus); // next_mode stores the desired privilege mode to return to.. // typically PRV_S //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Setting priv mode to %d\n", next_mode); mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_MPP, next_mode); if (next_mode == PRV_M) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Booting into M-Mode so clearing MSTATUS:MIE\n"); mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_MPIE, 0); mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_MIE, 0); } else { mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_MPIE, 1); mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_MIE, 1); } mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_SIE, 0); mstatus_val = INSERT_FIELD(mstatus_val, MSTATUS_SPIE, 0); csr_write(mstatus, mstatus_val); // set MEPC to function address (smuggled in p_extended_buffer argument) csr_write(mepc, *((void **)p_extended_buffer)); // execute MRET, causing MIE <= MPIE, new priv mode <= PRV_S, MPIE <= 1, MPP <= U register unsigned long a0 asm("a0") = hartid; register unsigned long a1 asm("a1") = 0u; asm("mret" : : "r"(a0), "r"(a1)); __builtin_unreachable(); #endif // state machine doesn't want outside framework to send a separate complete // message, as we have jumped somewhere else // // for tidyness/test code, we'll return IPI_IDLE in this scenario if all is okay, or // IPI_FAIL otherwise result = IPI_IDLE; } } return result; } hart-software-services-2022.10/services/goto/goto_service.h000066400000000000000000000034431432224323300237250ustar00rootroot00000000000000#ifndef HSS_GOTO_SERVICE_H #define HSS_GOTO_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - U54 GOTO Service * Allows E51 to instruct U54 to run specific code * */ /*! * \file Virtual GOTO API * \brief GOTO Driver State Machine API function declarations */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" enum IPIStatusCode HSS_GOTO_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/ipi_poll/000077500000000000000000000000001432224323300217175ustar00rootroot00000000000000hart-software-services-2022.10/services/ipi_poll/Kconfig000066400000000000000000000003011432224323300232140ustar00rootroot00000000000000config SERVICE_IPI_POLL bool "IPI Polling support" default n help This feature enables support for IPI Polling. If you do not know what to do here, say Y. hart-software-services-2022.10/services/ipi_poll/Makefile000066400000000000000000000024441432224323300233630ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # IPI Polling as a Service SRCS-$(CONFIG_SERVICE_IPI_POLL) += \ services/ipi_poll/ipi_poll_service.c \ INCLUDES +=\ -I./services/ipi_poll \ hart-software-services-2022.10/services/ipi_poll/ipi_poll_service.c000066400000000000000000000073261432224323300254220ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file IPI Poll Driver State Machine * \brief IPI Poll Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include //memset #include #include "mpfs_reg_map.h" #include "csr_helper.h" #include "ipi_poll_service.h" static void ipiPoll_init_handler(struct StateMachine * const pMyMachine); static void ipiPoll_monitoring_handler(struct StateMachine * const pMyMachine); /*! * \brief UART Driver States * */ enum UartStatesEnum { IPI_POLL_INITIALIZATION, IPI_POLL_MONITORING, IPI_POLL_NUM_STATES = IPI_POLL_MONITORING+1 }; /*! * \brief UART Driver State Descriptors * */ static const struct StateDesc ipiPoll_state_descs[] = { { (const stateType_t)IPI_POLL_INITIALIZATION, (const char *)"Init", NULL, NULL, &ipiPoll_init_handler }, { (const stateType_t)IPI_POLL_MONITORING, (const char *)"Monitoring", NULL, NULL, &ipiPoll_monitoring_handler } }; /*! * \brief UART Driver State Machine * */ struct StateMachine ipi_poll_service = { .state = (stateType_t)IPI_POLL_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)IPI_POLL_NUM_STATES, .pMachineName = (const char *)"ipi_poll_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = ipiPoll_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = NULL, }; // ---------------------------------------------------------------------------------------------------------------------- static union HSSHartBitmask hartBitmask = { .uint = 0 }; static void ipiPoll_init_handler(struct StateMachine * const pMyMachine) { memset(&hartBitmask, 0, sizeof(hartBitmask)); hartBitmask.uint = mHSS_BITMASK_ALL_U54; pMyMachine->state = IPI_POLL_MONITORING; } // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void ipiPoll_monitoring_handler(struct StateMachine * const pMyMachine) { (void) pMyMachine; // poll IPIs each iteration for new messages bool const status = IPI_PollReceive(hartBitmask); enum HSSHartId const myHartId = current_hartid(); if (status) { unsigned int i; for (i = 0u; i < MAX_NUM_HARTS; i++) { if (i == myHartId) { continue; } // don't handle messages if to my own hartid uint32_t const index = IPI_CalculateQueueIndex(i, myHartId); if (IPI_GetQueuePendingCount(index)) { IPI_ConsumeIntent(i, IPI_MSG_ACK_COMPLETE); // gobble up any ACK completes IPI_ConsumeIntent(i, IPI_MSG_ACK_PENDING); // gobble up any ACK pendings } } } } ///////////////// void HSS_IpiPoll_Enable(enum HSSHartId target) { switch (target) { case HSS_HART_U54_1: hartBitmask.s.u54_1 = 1; break; case HSS_HART_U54_2: hartBitmask.s.u54_2 = 1; break; case HSS_HART_U54_3: hartBitmask.s.u54_3 = 1; break; case HSS_HART_U54_4: hartBitmask.s.u54_4 = 1; break; case HSS_HART_ALL: hartBitmask.s.u54_1 = 1; hartBitmask.s.u54_2 = 1; hartBitmask.s.u54_3 = 1; hartBitmask.s.u54_4 = 1; break; default: assert(1 == 0); // should never reach here!! LCOV_EXCL_LINE break; } ipi_poll_service.state = IPI_POLL_MONITORING; } hart-software-services-2022.10/services/ipi_poll/ipi_poll_service.h000066400000000000000000000032731432224323300254240ustar00rootroot00000000000000#ifndef HSS_IPI_POLL_SERVICE_H #define HSS_IPI_POLL_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - IPI Polling * */ /*! * \file IPI Poll Driver State Machine * \brief IPI Poll Service */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include "mpfs_reg_map.h" void HSS_IpiPoll_Enable(enum HSSHartId target); extern struct StateMachine ipi_poll_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/mmc/000077500000000000000000000000001432224323300206645ustar00rootroot00000000000000hart-software-services-2022.10/services/mmc/Kconfig000066400000000000000000000062451432224323300221760ustar00rootroot00000000000000config SERVICE_MMC bool "MMC support" default y help This feature enables support for booting via MMC. If you do not know what to do here, say Y. menu "MMC" visible if SERVICE_MMC menu "MMC Mode" config SERVICE_MMC_MODE_EMMC bool "Use eMMC" default y depends on SERVICE_MMC help This feature sets the MMC system to use eMMC. This option is mutually exclusive with SERVICE_MMC_MODE_SDCARD. If you do not know what to do here, say Y. config SERVICE_MMC_MODE_SDCARD bool "Use SDCard" default y depends on SERVICE_MMC help This feature sets the MMC system to use SDCard. This option is mutually exclusive with SERVICE_MMC_MODE_EMMC. If you do not know what to do here, say N. endmenu menu "MMC Voltage" config SERVICE_MMC_BUS_VOLTAGE_1V8 bool "Use 1.8V Bus Voltage with MMC" default n depends on SERVICE_MMC help This feature sets the bus voltage for MMC to 1.8V. This option is mutually exclusive with SERVICE_MMC_BUS_VOLTAGE_3V3. If you do not know what to do here, say N. config SERVICE_MMC_BUS_VOLTAGE_3V3 bool "Use 3.3V Bus Voltage with MMC" default y depends on SERVICE_MMC && !SERVICE_MMC_BUS_VOLTAGE_1V8 help This feature sets the bus voltage for MMC to 3.3V. This option is mutually exclusive with SERVICE_MMC_BUS_VOLTAGE_1V8.. If you do not know what to do here, say Y. endmenu menu "SDIO Control" config SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT bool "SDIO register present" default n depends on SERVICE_MMC_MODE_SDCARD || SERVICE_MMC_MODE_EMMC help This feature will enable the use of a register in the FPGA fabric for SDIO control. If this register is not present and this option is enabled the HSS will fail to boot. config SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS hex "Memory mapped address of SDIO register" default 0x4f000000 depends on SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_PRESENT help This value represents the memory mapped address of a register in the FPGA fabric. This register is used to select between eMMC and SD card when a de-mux is present on a board. endmenu config SERVICE_MMC_SPIN_TIMEOUT bool "Apply timeout to spins in MMC driver" default y depends on SERVICE_MMC_MODE_SDCARD || SERVICE_MMC_MODE_EMMC help This feature will enable maximum loop checks on spins in the MMC driver. If you do not know what to do here, say Y. config SERVICE_MMC_SPIN_TIMEOUT_ASSERT bool "Assert if spin in MMC driver times out" default n depends on SERVICE_MMC_SPIN_TIMEOUT help This feature will enable an assert if maximum loop checks on spins in the MMC driver trigger. If you do not know what to do here, say N. config SERVICE_MMC_SPIN_TIMEOUT_MAX_SPINS int "Configure maximum permissible number of spins in MMC driver" default 1000000 depends on SERVICE_MMC_SPIN_TIMEOUT range 0 10000000 help This value controls the max number of loop spins before trigger a timeout in the MMC driver. endmenu hart-software-services-2022.10/services/mmc/Makefile000066400000000000000000000025411432224323300223260ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # MMC Service (NOTE: not a traditional super-loop service) EXTRA_SRCS-$(CONFIG_SERVICE_MMC) += \ services/mmc/mmc_api.c \ INCLUDES +=\ -Iservices/mmc \ services/mmc/mmc_api.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/mmc/mmc_api.c000066400000000000000000000255761432224323300224540ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file MMC (null) Service * \brief Setup MMC */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_progress.h" #include "hss_clock.h" #include "hss_perfctr.h" #include #include #include "mmc_service.h" #include "encoding.h" #ifdef CONFIG_MODULE_M100PFS #include "mss_gpio.h" #endif #include "mss_mmc.h" #include "hal/hw_macros.h" #ifndef __IO # define __IO volatile #endif #include "mss_io_config.h" #include "hss_memcpy_via_pdma.h" /* * MMC doesn't need a "service" to run every super-loop, but it does need to be * initialized early... */ #if !defined(CONFIG_SERVICE_MMC_MODE_EMMC) && !defined(CONFIG_SERVICE_MMC_MODE_SDCARD) # error Unknown MMC mode (eMMC or SDcard) #endif #if defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8) && defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_3V3) # error Both MMC Bus Voltages defined! These are mutually exclusive. #endif // --------------------------------------------------------------------------------------------- #include "mss_sysreg.h" extern uint8_t PLIC_mmc_main_IRQHandler(void); static void mmc_reset_block(void) { SYSREG->SUBBLK_CLOCK_CR |= (uint32_t)(SUBBLK_CLOCK_CR_MMC_MASK); SYSREG->SOFT_RESET_CR |= (uint32_t)(SOFT_RESET_CR_MMC_MASK); SYSREG->SOFT_RESET_CR &= ~(uint32_t)(SOFT_RESET_CR_MMC_MASK); } static bool mmc_init_common(mss_mmc_cfg_t *p_mmcConfig) { bool result = false; mss_mmc_status_t retval = MSS_MMC_init(p_mmcConfig); if (retval != MSS_MMC_INIT_SUCCESS) { mmc_reset_block(); HSS_SpinDelay_MilliSecs(50u); // delay for 50 milliseconds retval = MSS_MMC_init(p_mmcConfig); } if (retval != MSS_MMC_INIT_SUCCESS) { //mHSS_DEBUG_PRINTF(LOG_ERROR, "MSS_MMC_init() returned unexpected %d\n", retval); } else { result = true; } return result; } #if defined(CONFIG_SERVICE_MMC_MODE_EMMC) static bool mmc_init_emmc(void) { static mss_mmc_cfg_t emmcConfig = { .card_type = MSS_MMC_CARD_TYPE_MMC, .data_bus_width = MSS_MMC_DATA_WIDTH_8BIT, #if defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_1V8) .bus_voltage = MSS_MMC_1_8V_BUS_VOLTAGE, #ifdef CONFIG_MODULE_M100PFS .clk_rate = MSS_MMC_CLOCK_50MHZ, .bus_speed_mode = MSS_MMC_MODE_SDR, #else .clk_rate = MSS_MMC_CLOCK_200MHZ, .bus_speed_mode = MSS_MMC_MODE_HS200, #endif #elif defined(CONFIG_SERVICE_MMC_BUS_VOLTAGE_3V3) .bus_voltage = MSS_MMC_3_3V_BUS_VOLTAGE, .clk_rate = MSS_MMC_CLOCK_50MHZ, .bus_speed_mode = MSS_MMC_MODE_SDR, #endif }; bool result = mss_does_xml_ver_support_switch(); if (result) { result = switch_mssio_config(EMMC_MSSIO_CONFIGURATION); } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "switch_mssio_config returned false %d\n", result); } #if IS_ENABLED(CONFIG_MODULE_M100PFS) MSS_GPIO_set_output(GPIO0_LO, MSS_GPIO_12, 0); #else /* we will attempt to switch anyway as default may be eMMC */ switch_external_mux(EMMC_MSSIO_CONFIGURATION); #endif /* Initialize eMMC/SD */ result = mmc_init_common(&emmcConfig); return result; } #endif #if defined(CONFIG_SERVICE_MMC_MODE_SDCARD) static bool mmc_init_sdcard(void) { static mss_mmc_cfg_t sdcardConfig = { .card_type = MSS_MMC_CARD_TYPE_SD, .data_bus_width = MSS_MMC_DATA_WIDTH_4BIT, .bus_speed_mode = MSS_SDCARD_MODE_HIGH_SPEED, .clk_rate = MSS_MMC_CLOCK_50MHZ, }; bool result = mss_does_xml_ver_support_switch(); if (result) { result = switch_mssio_config(SD_MSSIO_CONFIGURATION); } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "switch_mssio_config returned false %d\n", result); } /* we will attempt to switch anyway as default may be SD */ #if IS_ENABLED(CONFIG_MODULE_M100PFS) MSS_GPIO_set_output(GPIO0_LO, MSS_GPIO_12, 1); #else switch_external_mux(SD_MSSIO_CONFIGURATION); #endif /* Initialize eMMC/SD */ result = mmc_init_common(&sdcardConfig); return result; } #endif static bool mmc_initialized = false; bool HSS_MMCInit(void) { bool result = false; if (!mmc_initialized) { int perf_ctr_index = PERF_CTR_UNINITIALIZED; HSS_PerfCtr_Allocate(&perf_ctr_index, "MMC Init"); #ifdef CONFIG_MODULE_M100PFS MSS_GPIO_init(GPIO0_LO); MSS_GPIO_config(GPIO0_LO, MSS_GPIO_12, MSS_GPIO_OUTPUT_MODE); MSS_GPIO_set_output(GPIO0_LO, MSS_GPIO_12, 0); #endif mmc_reset_block(); #if defined(CONFIG_SERVICE_MMC_MODE_SDCARD) mHSS_DEBUG_PRINTF(LOG_STATUS, "Attempting to select SDCARD ... "); mmc_initialized = mmc_init_sdcard(); mHSS_DEBUG_PRINTF_EX("%s\n", mmc_initialized ? "Passed" : "Failed"); #endif #if defined(CONFIG_SERVICE_MMC_MODE_EMMC) if (!mmc_initialized) { mHSS_DEBUG_PRINTF(LOG_STATUS, "Attempting to select eMMC ... "); mmc_initialized = mmc_init_emmc(); mHSS_DEBUG_PRINTF_EX("%s\n", mmc_initialized ? "Passed" : "Failed"); } #endif HSS_PerfCtr_Lap(perf_ctr_index); } result = mmc_initialized; return result; } #define HSS_MMC_SECTOR_SIZE (512u) // // HSS_MMC_ReadBlock will handle reads less than a multiple of the sector // size by doing the last transfer into a sector buffer // static char runtBuffer[HSS_MMC_SECTOR_SIZE] __attribute__((aligned(sizeof(uint32_t)))); bool HSS_MMC_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount) { char *pCDest = (char *)pDest; assert(((size_t)srcOffset & (HSS_MMC_SECTOR_SIZE-1)) == 0u); assert(((size_t)pCDest & (sizeof(uint32_t)-1)) == 0u); uint32_t src_sector_num = (uint32_t)(srcOffset / HSS_MMC_SECTOR_SIZE); mss_mmc_status_t result = MSS_MMC_TRANSFER_SUCCESS; uint32_t sectorByteCount = byteCount - (byteCount % HSS_MMC_SECTOR_SIZE); do { result = PLIC_mmc_main_IRQHandler(); } while (MSS_MMC_TRANSFER_IN_PROGRESS == result); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Calling MSS_MMC_sdma_read(%lu, %p) " // "(%lu bytes remaining)\n", src_sector_num, pCDest, sectorByteCount); result = MSS_MMC_sdma_read(src_sector_num, (uint8_t *)pCDest, sectorByteCount); while (result == MSS_MMC_TRANSFER_IN_PROGRESS) { result = PLIC_mmc_main_IRQHandler(); } byteCount = byteCount - sectorByteCount; // handle remainder if ((result == MSS_MMC_TRANSFER_SUCCESS) && byteCount) { assert(byteCount < HSS_MMC_SECTOR_SIZE); src_sector_num += (uint32_t)(sectorByteCount / HSS_MMC_SECTOR_SIZE); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Dealing with remainder (less that full sector)\n"); //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Calling MSS_MMC_single_block_read(%lu, %p) " // "(%lu bytes remaining)\n", src_sector_num, runtBuffer, byteCount); result = MSS_MMC_sdma_read(src_sector_num, (uint8_t *)runtBuffer, HSS_MMC_SECTOR_SIZE); while (result == MSS_MMC_TRANSFER_IN_PROGRESS) { result = PLIC_mmc_main_IRQHandler(); } if (result != MSS_MMC_TRANSFER_SUCCESS) { mHSS_DEBUG_PRINTF(LOG_ERROR, "MSS_MMC_single_block_read() unexpectedly returned %d\n", result); } if (result == MSS_MMC_TRANSFER_SUCCESS) { memcpy_via_pdma(pCDest + sectorByteCount, runtBuffer, byteCount); } } return (result == MSS_MMC_TRANSFER_SUCCESS); } // // HSS_MMC_WriteBlock will handle requested writes of less than a multiple of the sector // size by rounding up to the next full sector worth // bool HSS_MMC_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount) { // temporary code to bring up Icicle board char *pCSrc = (char *)pSrc; // if byte count is not a multiple of the sector size, round it up... if (byteCount & (HSS_MMC_SECTOR_SIZE-1)) { byteCount = byteCount + HSS_MMC_SECTOR_SIZE; byteCount &= ~(HSS_MMC_SECTOR_SIZE-1); } // source and byteCount must be multiples of the sector size // // The MSS MMC driver uses uint32_t* as its pointer type // To ensure alignment, would rather tramp through void* and // assert check here assert(((size_t)dstOffset & (HSS_MMC_SECTOR_SIZE-1)) == 0u); assert(((size_t)pCSrc & (sizeof(uint32_t)-1)) == 0u); assert((byteCount & (HSS_MMC_SECTOR_SIZE-1)) == 0u); uint32_t dst_sector_num = (uint32_t)(dstOffset / HSS_MMC_SECTOR_SIZE); mss_mmc_status_t result = MSS_MMC_TRANSFER_SUCCESS; while ((result == MSS_MMC_TRANSFER_SUCCESS) && (byteCount)) { result = MSS_MMC_single_block_write((uint32_t *)pCSrc, dst_sector_num); if (result != MSS_MMC_TRANSFER_SUCCESS) { mHSS_DEBUG_PRINTF(LOG_ERROR, "MSS_MMC_single_block_write() unexpectedly returned %d\n", result); } dst_sector_num++; byteCount = byteCount - HSS_MMC_SECTOR_SIZE; pCSrc = pCSrc + HSS_MMC_SECTOR_SIZE; } return (result == MSS_MMC_TRANSFER_SUCCESS); } // // HSS_MMC_WriteBlock will handle requested writes of less than a multiple of the sector // size by rounding up to the next full sector worth // bool HSS_MMC_WriteBlockSDMA(size_t dstOffset, void *pSrc, size_t byteCount) { // temporary code to bring up Icicle board char *pCSrc = (char *)pSrc; // if byte count is not a multiple of the sector size, round it up... if (byteCount & (HSS_MMC_SECTOR_SIZE-1)) { byteCount = byteCount + HSS_MMC_SECTOR_SIZE; byteCount &= ~(HSS_MMC_SECTOR_SIZE-1); } // source and byteCount must be multiples of the sector size // // The MSS MMC driver uses uint32_t* as its pointer type // To ensure alignment, would rather tramp through void* and // assert check here assert(((size_t)dstOffset & (HSS_MMC_SECTOR_SIZE-1)) == 0u); assert(((size_t)pCSrc & (sizeof(uint32_t)-1)) == 0u); assert((byteCount & (HSS_MMC_SECTOR_SIZE-1)) == 0u); mss_mmc_status_t result = MSS_MMC_NO_ERROR; uint32_t dst_sector_num = (uint32_t)(dstOffset / HSS_MMC_SECTOR_SIZE); // wait for any in-flight transactions to complete while (MSS_MMC_get_transfer_status() == MSS_MMC_TRANSFER_IN_PROGRESS) { do { result = PLIC_mmc_main_IRQHandler(); } while (result == MSS_MMC_TRANSFER_IN_PROGRESS); } // setup new transaction... result = MSS_MMC_sdma_write((uint8_t *)pCSrc, dst_sector_num, byteCount); if (result == MSS_MMC_TRANSFER_IN_PROGRESS) { do { result = PLIC_mmc_main_IRQHandler(); } while (result == MSS_MMC_TRANSFER_IN_PROGRESS); } return (result == MSS_MMC_TRANSFER_SUCCESS); } void HSS_MMC_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount) { uint16_t sectorSize; MSS_MMC_get_info(§orSize, pBlockCount); *pEraseSize = *pBlockSize = sectorSize; } hart-software-services-2022.10/services/mmc/mmc_service.h000066400000000000000000000035151432224323300233350ustar00rootroot00000000000000#ifndef HSS_MMC_SERVICE_H #define HSS_MMC_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - EMMC Initialization * */ /*! * \file MMC API * \brief MMC (null) Service API */ #ifdef __cplusplus extern "C" { #endif #include "hss_types.h" bool HSS_MMCInit(void); bool HSS_MMC_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount); bool HSS_MMC_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount); bool HSS_MMC_WriteBlockSDMA(size_t dstOffset, void *pSrc, size_t byteCount); void HSS_MMC_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/opensbi/000077500000000000000000000000001432224323300215475ustar00rootroot00000000000000hart-software-services-2022.10/services/opensbi/Kconfig000066400000000000000000000011351432224323300230520ustar00rootroot00000000000000config SERVICE_OPENSBI def_bool y depends on OPENSBI help This feature enables support for OPENSBI. If you do not know what to do here, say Y. config SERVICE_OPENSBI_IHC def_bool y depends on OPENSBI && USE_IHC help This feature enables support for IHC ecall service. If you do not know what to do here, say Y. config SERVICE_OPENSBI_RPROC def_bool y depends on SERVICE_OPENSBI_IHC help This feature enables support for Remote Proc ecall service. If you do not know what to do here, say Y.hart-software-services-2022.10/services/opensbi/Makefile000066400000000000000000000162341432224323300232150ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # OpenSPI Service SRCS-$(CONFIG_SERVICE_OPENSBI) += \ services/opensbi/opensbi_service.c \ thirdparty/opensbi/lib/utils/irqchip/plic.c \ thirdparty/opensbi/lib/utils/libfdt/fdt.c \ thirdparty/opensbi/lib/utils/libfdt/fdt_ro.c \ thirdparty/opensbi/lib/utils/libfdt/fdt_rw.c \ thirdparty/opensbi/lib/utils/libfdt/fdt_wip.c \ thirdparty/opensbi/lib/utils/libfdt/fdt_addresses.c \ thirdparty/opensbi/lib/utils/fdt/fdt_fixup.c \ thirdparty/opensbi/lib/utils/fdt/fdt_helper.c \ thirdparty/opensbi/lib/utils/fdt/fdt_pmu.c \ thirdparty/opensbi/lib/sbi/riscv_asm.c \ thirdparty/opensbi/lib/sbi/riscv_atomic.c \ thirdparty/opensbi/lib/sbi/riscv_locks.c \ thirdparty/opensbi/lib/sbi/sbi_bitmap.c \ thirdparty/opensbi/lib/sbi/sbi_bitops.c \ thirdparty/opensbi/lib/sbi/sbi_console.c \ thirdparty/opensbi/lib/sbi/sbi_domain.c \ thirdparty/opensbi/lib/sbi/sbi_ecall_base.c \ thirdparty/opensbi/lib/sbi/sbi_ecall.c \ thirdparty/opensbi/lib/sbi/sbi_ecall_pmu.c \ thirdparty/opensbi/lib/sbi/sbi_ecall_hsm.c \ thirdparty/opensbi/lib/sbi/sbi_ecall_legacy.c \ thirdparty/opensbi/lib/sbi/sbi_ecall_replace.c \ thirdparty/opensbi/lib/sbi/sbi_ecall_vendor.c \ thirdparty/opensbi/lib/sbi/sbi_emulate_csr.c \ thirdparty/opensbi/lib/sbi/sbi_fifo.c \ thirdparty/opensbi/lib/sbi/sbi_hart.c \ thirdparty/opensbi/lib/sbi/sbi_hsm.c \ thirdparty/opensbi/lib/sbi/sbi_illegal_insn.c \ thirdparty/opensbi/lib/sbi/sbi_init.c \ thirdparty/opensbi/lib/sbi/sbi_ipi.c \ thirdparty/opensbi/lib/sbi/sbi_math.c \ thirdparty/opensbi/lib/sbi/sbi_misaligned_ldst.c \ thirdparty/opensbi/lib/sbi/sbi_platform.c \ thirdparty/opensbi/lib/sbi/sbi_pmu.c \ thirdparty/opensbi/lib/sbi/sbi_scratch.c \ thirdparty/opensbi/lib/sbi/sbi_string.c \ thirdparty/opensbi/lib/sbi/sbi_system.c \ thirdparty/opensbi/lib/sbi/sbi_timer.c \ thirdparty/opensbi/lib/sbi/sbi_tlb.c \ thirdparty/opensbi/lib/sbi/sbi_trap.c \ thirdparty/opensbi/lib/sbi/sbi_unpriv.c \ thirdparty/opensbi/lib/utils/timer/aclint_mtimer.c \ thirdparty/opensbi/lib/utils/ipi/aclint_mswi.c \ ifdef CONFIG_USE_IHC SRCS-$(CONFIG_SERVICE_OPENSBI_IHC) += \ services/opensbi/opensbi_ihc_ecall.c \ SRCS-$(CONFIG_SERVICE_OPENSBI_RPROC) += \ services/opensbi/opensbi_rproc_ecall.c \ endif ASM_SRCS-$(CONFIG_SERVICE_OPENSBI) += \ thirdparty/opensbi/lib/sbi/riscv_hardfp.S \ thirdparty/opensbi/lib/sbi/sbi_expected_trap.S \ thirdparty/opensbi/lib/sbi/sbi_hfence.S \ SRCS-$(CONFIG_SERVICE_OPENSBI) += \ services/opensbi/platform.c \ services/opensbi/opensbi_ecall.c ifdef CONFIG_OPENSBI INCLUDES += \ -I./services/opensbi \ -I./thirdparty/opensbi/include/sbi \ -I./thirdparty/opensbi/include \ -I./thirdparty/opensbi/lib/utils/libfdt endif ifdef CONFIG_PROVIDE_DTB ifdef CONFIG_DEFAULT_DEVICE_TREE EXTRA_OBJS += services/opensbi/mpfs_dtb.o services/opensbi/mpfs_dtb.o: $(CONFIG_DEFAULT_DEVICE_TREE:"%"=%).dtb $(CROSS_COMPILE)ld -r -b binary -o $@ $< endif endif services/opensbi/opensbi_service.o: CFLAGS=$(CFLAGS_GCCEXT) services/opensbi/opensbi_ihc_ecall.o: CFLAGS=$(CFLAGS_GCCEXT) services/opensbi/platform.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/irqchip/plic.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_rw.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_ro.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_overlay.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_strerror.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_sw.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_addresses.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/libfdt/fdt_wip.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/serial/sifive-uart.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/platform/sifive/fu540/platform.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/riscv_asm.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/riscv_atomic.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/riscv_locks.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_bitmap.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_bitops.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_console.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_domain.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall_base.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall_hsm.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall_legacy.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall_replace.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall_vendor.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_emulate_csr.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_fifo.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_hart.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_hsm.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_illegal_insn.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_init.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ipi.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_math.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_misaligned_ldst.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_platform.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_pmu.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_scratch.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_string.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_system.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_timer.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_tlb.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_trap.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_unpriv.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/timer/aclint_mtimer.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/utils/ipi/aclint_mswi.o: CFLAGS=$(CFLAGS_GCCEXT) thirdparty/opensbi/lib/sbi/sbi_ecall_pmu.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/opensbi/opensbi_ecall.c000066400000000000000000000047151432224323300245210ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS Embedded Software * */ #include "config.h" #include "hss_types.h" #include #include #include //#include //#include //#include //#include #include "opensbi_service.h" #include "opensbi_ecall.h" #if !IS_ENABLED(CONFIG_OPENSBI) # error OPENSBI needed for this module #endif #if IS_ENABLED(CONFIG_USE_IHC) && IS_ENABLED(CONFIG_SERVICE_OPENSBI_IHC) # include "miv_ihc.h" # include "opensbi_ihc_ecall.h" #endif #if IS_ENABLED(CONFIG_USE_IHC) && IS_ENABLED(CONFIG_SERVICE_OPENSBI_RPROC) # include "opensbi_rproc_ecall.h" #endif #include "hss_boot_service.h" int HSS_SBI_ECALL_Handler(long extid, long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap) { int result = 0; uint32_t index; switch (funcid) { // // MiV IHC functions case SBI_EXT_IHC_CTX_INIT: __attribute__((fallthrough)); // deliberate fallthrough case SBI_EXT_IHC_SEND: __attribute__((fallthrough)); // deliberate fallthrough case SBI_EXT_IHC_RECEIVE: #if IS_ENABLED(CONFIG_USE_IHC) && IS_ENABLED(CONFIG_SERVICE_OPENSBI_IHC) result = sbi_ecall_ihc_handler(extid, funcid, regs, out_val, out_trap); #endif break; case SBI_EXT_RPROC_STATE: __attribute__((fallthrough)); // deliberate fallthrough case SBI_EXT_RPROC_START: __attribute__((fallthrough)); // deliberate fallthrough case SBI_EXT_RPROC_STOP: #if IS_ENABLED(CONFIG_USE_IHC) && IS_ENABLED(CONFIG_SERVICE_OPENSBI_RPROC) result = sbi_ecall_rproc_handler(extid, funcid, regs, out_val, out_trap); #endif break; // // HSS functions case SBI_EXT_HSS_REBOOT: IPI_MessageAlloc(&index); IPI_MessageDeliver(index, HSS_HART_E51, IPI_MSG_BOOT_REQUEST, 0u, NULL, NULL); result = 0; break; default: result = SBI_ENOTSUPP; }; //exit: //if (result >= 0) { // *out_val = result; // result = 0; //} return result; } int HSS_SBI_Vendor_Ext_Check(long extid) { return (SBI_EXT_MICROCHIP_TECHNOLOGY == extid); } hart-software-services-2022.10/services/opensbi/opensbi_ecall.h000066400000000000000000000051611432224323300245220ustar00rootroot00000000000000#ifndef OPENSBI_ECALL_H #define OPENSBI_ECALL_H /******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - OpenSBI ECALL Interface */ #ifdef __cplusplus extern "C" { #endif #include // Previously the vendor ID was to be a number allocated by RISC-V International, // but this duplicates the work of JEDEC in maintaining a manufacturer ID standard. // SBI ECALLs in the VENDOR region are by MVENDORID as per section 3.1.2 of // RISC-V Priviliged Architectures spec (2.2-draft or later) // // mvendorid[6:0] = JEDEC[6:0] // mvendorid[XLEN-1:7] = number of 0x7f continuation codes // Microchip Technology JEDEC Id: Bank 1, 0x29 => MVENDORID = 0x029 #define MICROCHIP_TECHNOLOGY_MVENDOR_ID 0x029 #define SBI_EXT_MICROCHIP_TECHNOLOGY (SBI_EXT_VENDOR_START | MICROCHIP_TECHNOLOGY_MVENDOR_ID) #define SBI_EXT_IHC_CTX_INIT 0x00 #define SBI_EXT_IHC_SEND 0x01 #define SBI_EXT_IHC_RECEIVE 0x02 #define SBI_EXT_RPROC_STATE 0x03 #define SBI_EXT_RPROC_START 0x04 #define SBI_EXT_RPROC_STOP 0x05 #define SBI_EXT_HSS_REBOOT 0x10 #include #include #include #include #include int HSS_SBI_ECALL_Handler(long extid, long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap); int HSS_SBI_Vendor_Ext_Check(long extid); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/opensbi/opensbi_ihc_ecall.c000066400000000000000000000050601432224323300253360ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS Embedded Software * */ #include "config.h" #include "hss_types.h" #include "opensbi_service.h" #if !IS_ENABLED(CONFIG_OPENSBI) # error OPENSBI needed for this module #endif #if !IS_ENABLED(CONFIG_USE_IHC) # error IHC needed for this module #endif #include #include #include #include #include #include #include #include "miv_ihc.h" #include "opensbi_ecall.h" #include "opensbi_ihc_ecall.h" static uint32_t message_present_handler(uint32_t remote_hart_id, uint32_t * message, uint32_t message_size , bool is_ack, uint32_t *message_storage_ptr) { struct ihc_sbi_rx_msg msg; (void)remote_hart_id; if (is_ack == true) { msg.irq_type = ACK_IRQ; } else { msg.irq_type = MP_IRQ; memcpy((uint32_t *) &msg.ihc_msg, message, message_size * (sizeof(uint32_t))); } memcpy((uint32_t *) message_storage_ptr, (uint32_t *) &msg, sizeof(struct ihc_sbi_rx_msg)); return 0u; } int sbi_ecall_ihc_handler(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap) { uint32_t my_hart_id; uint32_t remote_hart_id; int result = 0; uint32_t remote_channel = (uint32_t) regs->a0; uint32_t * message_ptr = (uint32_t *) regs->a1; if ((remote_channel < IHC_CHANNEL_TO_CONTEXTA) || (remote_channel > IHC_CHANNEL_TO_CONTEXTB)) { result = SBI_EINVAL; goto exit; } switch (funcid) { case SBI_EXT_IHC_CTX_INIT: my_hart_id = IHC_context_to_context_hart_id(current_hartid()); remote_hart_id = IHC_context_to_context_hart_id(remote_channel); IHC_local_remote_config(my_hart_id, remote_hart_id, message_present_handler, true, true); result = SBI_OK; break; case SBI_EXT_IHC_SEND: if (IHC_tx_message_from_context(remote_channel, (uint32_t *) message_ptr)) result = SBI_ERR_DENIED; break; case SBI_EXT_IHC_RECEIVE: IHC_context_indirect_isr((uint32_t *) message_ptr); result = SBI_OK; break; default: result = SBI_ENOTSUPP; }; exit: if (result >= 0) { *out_val = result; result = 0; } return result; } hart-software-services-2022.10/services/opensbi/opensbi_ihc_ecall.h000066400000000000000000000034071432224323300253460ustar00rootroot00000000000000#ifndef OPENSBI_IHC_SERVICE_H #define OPENSBI_IHC_SERVICE_H /******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * */ #ifdef __cplusplus extern "C" { #endif #include "opensbi_ecall.h" enum { MP_IRQ = 0x0, ACK_IRQ = 0x1, }; struct mpfs_ihc_msg { uint32_t msg[IHC_MAX_MESSAGE_SIZE]; }; struct ihc_sbi_rx_msg { struct mpfs_ihc_msg ihc_msg; uint8_t irq_type; }; int sbi_ecall_ihc_handler(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/opensbi/opensbi_rproc_ecall.c000066400000000000000000000046411432224323300257240ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS Embedded Software * */ #include "config.h" #include "hss_types.h" #include "csr_helper.h" #include "opensbi_service.h" #include #include #include #include #include #include #if !IS_ENABLED(CONFIG_OPENSBI) # error OPENSBI needed for this module #endif #if !IS_ENABLED(CONFIG_USE_IHC) # error IHC needed for this module #endif #include "miv_ihc.h" #include "opensbi_ecall.h" #include "opensbi_rproc_ecall.h" #include "hss_boot_service.h" static struct RemoteProcMsg rproc_data; int sbi_ecall_rproc_handler(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap) { int result = SBI_ERR_FAILED; uint32_t index, remote_hart_id; uint32_t remote_channel = (uint8_t) regs->a0; uint32_t ihc_tx_message[IHC_MAX_MESSAGE_SIZE]; if ((remote_channel < IHC_CHANNEL_TO_CONTEXTA) || (remote_channel > IHC_CHANNEL_TO_CONTEXTB)) { result = SBI_EINVAL; goto exit; } remote_hart_id = IHC_context_to_context_hart_id(remote_channel); switch (funcid) { #if IS_ENABLED(CONFIG_SERVICE_BOOT) case SBI_EXT_RPROC_STATE: if (!HSS_SkipBoot_IsSet(remote_hart_id)) result = CONTEXT_RUNNING; else result = CONTEXT_OFFLINE; break; #endif case SBI_EXT_RPROC_START: rproc_data.target = remote_hart_id; if (IPI_MessageAlloc(&index)) { if(IPI_MessageDeliver(index, HSS_HART_E51, IPI_MSG_BOOT_REQUEST, RPROC_BOOT, &rproc_data, NULL)) result = SBI_OK; else IPI_MessageFree(index); } break; case SBI_EXT_RPROC_STOP: ihc_tx_message[0] = RPROC_SHUTDOWN_MSG; if (IHC_tx_message_from_context(remote_channel, (uint32_t *) ihc_tx_message)) result = SBI_ERR_FAILED; else result = SBI_OK; break; default: result = SBI_ENOTSUPP; }; exit: if (result >= 0) { *out_val = result; result = 0; } return result; } hart-software-services-2022.10/services/opensbi/opensbi_rproc_ecall.h000066400000000000000000000033631432224323300257310ustar00rootroot00000000000000#ifndef OPENSBI_RPROC_SERVICE_H #define OPENSBI_RPROC_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * */ #ifdef __cplusplus extern "C" { #endif #include "opensbi_ecall.h" # define RPROC_BOOT 0x80 # define RPROC_SHUTDOWN_MSG 0xFFFFFF02 #define CONTEXT_OFFLINE 0 #define CONTEXT_RUNNING 1 struct RemoteProcMsg { enum HSSHartId target; }; int sbi_ecall_rproc_handler(unsigned long extid, unsigned long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap); #ifdef __cplusplus } #endif #endifhart-software-services-2022.10/services/opensbi/opensbi_service.c000066400000000000000000000201251432224323300250720ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Goto State Machine * \brief U54 opensbi */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_atomic.h" #include "hss_clock.h" #include "ssmb_ipi.h" #include #include #include "csr_helper.h" #include "ssmb_ipi.h" #include "opensbi_service.h" #include "opensbi_ecall.h" #include "riscv_encoding.h" #if IS_ENABLED(CONFIG_SERVICE_BOOT) # include "hss_boot_pmp.h" #endif #include "mpfs_reg_map.h" #include "sbi_version.h" #if !IS_ENABLED(CONFIG_OPENSBI) # error OPENSBI needed for this module #endif #if IS_ENABLED(CONFIG_HSS_USE_IHC) # include "miv_ihc.h" #endif extern const struct sbi_platform platform; extern const struct sbi_hsm_device mpfs_hsm; static unsigned long l_hartid_to_scratch(int hartid); // // OpenSBI needs a scratch structure per hart, plus some ancilliary data space // after this... // // "External firmware must create per-HART non-overlapping: // 1. Program Stack // 2.OpenSBI scratch space (i.e. struct sbi_scratch instance with extra space above)" // place this in DDR... union t_HSS_scratchBuffer { struct sbi_scratch scratch; unsigned long buffer[SBI_SCRATCH_SIZE / __SIZEOF_POINTER__]; } scratches[MAX_NUM_HARTS] __attribute__((section(".l2_scratchpad"),used)); //} scratches[MAX_NUM_HARTS] __attribute__((section(".opensbi_scratch"))); asm(" .globl scratch_addr\n" " .type scratch_addr, @object\n" " .align 3\n" "scratch_addr: .quad scratches\n"); extern const size_t scratch_addr; union t_HSS_scratchBuffer *pScratches = 0; static void opensbi_scratch_setup(enum HSSHartId hartid) { assert(hartid < MAX_NUM_HARTS); pScratches = (union t_HSS_scratchBuffer * const)scratch_addr; pScratches[hartid].scratch.options = SBI_SCRATCH_DEBUG_PRINTS; pScratches[hartid].scratch.hartid_to_scratch = (unsigned long)l_hartid_to_scratch; pScratches[hartid].scratch.platform_addr = (unsigned long)&platform; extern unsigned long _hss_start, _hss_end; pScratches[hartid].scratch.fw_start = (unsigned long)&_hss_start; pScratches[hartid].scratch.fw_size = (unsigned long)&_hss_end - (unsigned long)&_hss_start; sbi_hsm_set_device(&mpfs_hsm); } static unsigned long l_hartid_to_scratch(int hartid) { unsigned long result = 0u; assert(hartid < MAX_NUM_HARTS); if (hartid != 0) { result = (unsigned long)(&(pScratches[hartid].scratch)); } return result; } static void opensbi_init_handler(struct StateMachine * const pMyMachine); static void opensbi_idle_handler(struct StateMachine * const pMyMachine); /*! * \brief OPENSBI Driver States */ enum GotoStatesEnum { OPENSBI_INITIALIZATION, OPENSBI_IDLE, OPENSBI_NUM_STATES = OPENSBI_IDLE+1 }; /*! * \brief OPENSBI Driver State Descriptors */ static const struct StateDesc opensbi_state_descs[] = { { (const stateType_t)OPENSBI_INITIALIZATION, (const char *)"Init", NULL, NULL, &opensbi_init_handler }, { (const stateType_t)OPENSBI_IDLE, (const char *)"Idle", NULL, NULL, &opensbi_idle_handler }, }; /*! * \brief OPENSBI Driver State Machine */ struct StateMachine opensbi_service = { .state = (stateType_t)OPENSBI_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)OPENSBI_NUM_STATES, .pMachineName = (const char *)"opensbi_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = opensbi_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL, }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void opensbi_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state++; } ///////////////// static void opensbi_idle_handler(struct StateMachine * const pMyMachine) { (void)pMyMachine; // unused } ///////////////// extern unsigned long _trap_handler; #include "sbi/sbi_domain.h" #include "sbi/sbi_ecall_interface.h" void HSS_OpenSBI_Setup(void) { enum HSSHartId hartid = current_hartid(); if (hartid == HSS_HART_E51) { uint32_t mstatus_val = csr_read(CSR_MSTATUS); mstatus_val = EXTRACT_FIELD(mstatus_val, MSTATUS_MPIE); csr_write(CSR_MSTATUS, mstatus_val); csr_write(CSR_MIE, 0u); opensbi_scratch_setup(hartid); int sbi_console_init(struct sbi_scratch *scratch); int rc = sbi_console_init(&(pScratches[hartid].scratch)); if (rc) sbi_hart_hang(); } else { ; } } void __noreturn HSS_OpenSBI_DoBoot(enum HSSHartId hartid); void __noreturn HSS_OpenSBI_DoBoot(enum HSSHartId hartid) { uint32_t mstatus_val = csr_read(CSR_MSTATUS); mstatus_val = EXTRACT_FIELD(mstatus_val, MSTATUS_MPIE); csr_write(CSR_MSTATUS, mstatus_val); csr_write(CSR_MIE, 0u); opensbi_scratch_setup(hartid); mpfs_mark_hart_as_booted(hartid); sbi_init(&(pScratches[hartid].scratch)); // should never be reached... while (1) { asm("wfi"); }; } enum IPIStatusCode HSS_OpenSBI_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer, void *p_ancilliary_buffer_in_ddr) { enum IPIStatusCode result = IPI_FAIL; int hartid = current_hartid(); if (source != HSS_HART_E51) { // prohibited by policy mHSS_DEBUG_PRINTF(LOG_ERROR, "u54_%d: request from source %d prohibited by policy\n", hartid, source); } else if (hartid == HSS_HART_E51) { // prohibited by policy mHSS_DEBUG_PRINTF(LOG_ERROR, "u54_%d: request prohibited by policy\n", HSS_HART_E51); } else { IPI_Send(source, IPI_MSG_ACK_COMPLETE, transaction_id, IPI_SUCCESS, NULL, NULL); IPI_MessageUpdateStatus(transaction_id, IPI_IDLE); // free the IPI #if IS_ENABLED(CONFIG_HSS_USE_IHC) __sync_synchronize(); // small delay to ensure that IHC message has been sent before jumping into OpenSBI // without this, HSS never receives ACK from U54 that OPENSBI_INIT was successful HSS_SpinDelay_MilliSecs(250u); #endif struct IPI_Outbox_Msg *pMsg = IPI_DirectionToFirstMsgInQueue(source, hartid); size_t i; for (i = 0u; i < IPI_MAX_NUM_QUEUE_MESSAGES; i++) { if (pMsg->transaction_id == transaction_id) { break; } pMsg++; } // if message found process it... if (pMsg->transaction_id == transaction_id) { pMsg->msg_type = IPI_MSG_NO_MESSAGE; result = IPI_SUCCESS; } else { result = IPI_FAIL; } if (result != IPI_FAIL) { csr_write(mscratch, &(pScratches[hartid].scratch)); pScratches[hartid].scratch.next_addr = (uintptr_t)p_extended_buffer; pScratches[hartid].scratch.next_mode = (unsigned long)immediate_arg; // set arg1 (A1) to point to override device tree blob, if provided #if IS_ENABLED(CONFIG_PROVIDE_DTB) # if IS_ENABLED(CONFIG_PLATFORM_MPFS) extern unsigned long _binary_services_opensbi_mpfs_dtb_start; scratches[hartid].scratch.next_arg1 = (unsigned long)&_binary_services_opensbi_mpfs_dtb_start; # elif IS_ENABLED(CONFIG_PLATFORM_FU540) extern unsigned long _binary_hifive_unleashed_a00_dtb_start; pScratches[hartid].scratch.next_arg1 = (unsigned long)&_binary_hifive_unleashed_a00_dtb_start; # else # error Unknown PLATFORM settings # endif #else // else use ancilliary data if provided in boot image, assuming it is a DTB scratches[hartid].scratch.next_arg1 = (uintptr_t)p_ancilliary_buffer_in_ddr; #endif HSS_OpenSBI_DoBoot(hartid); } } return result; } void HSS_OpenSBI_Reboot(void) { uint32_t index; IPI_MessageAlloc(&index); IPI_MessageDeliver(index, HSS_HART_E51, IPI_MSG_BOOT_REQUEST, 0u, NULL, NULL); } hart-software-services-2022.10/services/opensbi/opensbi_service.h000066400000000000000000000044461432224323300251070ustar00rootroot00000000000000#ifndef HSS_OPENSBI_SERVICE_H #define HSS_OPENSBI_SERVICE_H /******************************************************************************* * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - OpenSBI API Handler * */ /*! * \file Virtual OPENSBI API * \brief OPENSBI Driver State Machine API function declarations */ #ifdef __cplusplus extern "C" { #endif #include "ssmb_ipi.h" #include "hss_state_machine.h" #include "hss_debug.h" enum IPIStatusCode HSS_OpenSBI_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); void HSS_OpenSBI_Setup(void); void HSS_OpenSBI_Reboot(void); void mpfs_domains_register_hart(int hartid, int boot_hartid); void mpfs_domains_deregister_hart(int hartid); void mpfs_domains_register_boot_hart(char *pName, u32 hartMask, int boot_hartid, u32 privMode, void * entryPoint, void * pArg1, bool allow_cold_reboot, bool allow_warm_reboot); void mpfs_mark_hart_as_booted(int hartid); bool mpfs_is_last_hart_ready(void); bool mpfs_is_hart_using_opensbi(int hartid); extern struct StateMachine opensbi_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/opensbi/platform.c000066400000000000000000000406101432224323300235400ustar00rootroot00000000000000 /****************************************************************************************** * * MPFS HSS Embedded Software * * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Originally based on code from OpenSBI, which is: * * Copyright (c) 2019 Western Digital Corporation or its affiliates. * */ #include "config.h" #include "hss_types.h" #include #include #define false FALSE #define true TRUE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opensbi_service.h" #include "opensbi_ecall.h" #include "mpfs_reg_map.h" #include "wdog_service.h" #define MPFS_HART_COUNT 5 #define MPFS_HART_STACK_SIZE 8192 #define MPFS_SYS_CLK 1000000000 #define MPFS_CLINT_ADDR 0x2000000 #define MPFS_PLIC_ADDR 0xc000000 #define MPFS_PLIC_NUM_SOURCES 186 #define MPFS_PLIC_NUM_PRIORITIES 7 #define MPFS_ACLINT_MTIMER_FREQ 1000000 #define MPFS_ACLINT_MTIMER_ADDR (0x02004000) /** * PolarFire SoC has 5 HARTs but HART ID 0 doesn't have S mode. enable only * HARTs 1 to 4. */ #ifndef MPFS_ENABLED_HART_MASK # define MPFS_ENABLED_HART_MASK (1 << 1 | 1 << 2 | 1 << 3 | 1 << 4) #endif #define MPFS_HARITD_DISABLED ~(MPFS_ENABLED_HART_MASK) static struct plic_data plicInfo = { .addr = MPFS_PLIC_ADDR, .num_src = MPFS_PLIC_NUM_SOURCES }; static struct aclint_mswi_data mswi = { .addr = MPFS_CLINT_ADDR, .size = ACLINT_MSWI_SIZE, .first_hartid = 0, .hart_count = MPFS_HART_COUNT, }; static struct aclint_mtimer_data mtimer = { .mtime_freq = MPFS_ACLINT_MTIMER_FREQ, .mtime_addr = MPFS_ACLINT_MTIMER_ADDR + ACLINT_DEFAULT_MTIME_OFFSET, .mtime_size = ACLINT_DEFAULT_MTIME_SIZE, .mtimecmp_addr = MPFS_ACLINT_MTIMER_ADDR + ACLINT_DEFAULT_MTIMECMP_OFFSET, .mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE, .first_hartid = 0, .hart_count = MPFS_HART_COUNT, .has_64bit_mmio = TRUE }; static struct { char name[64]; u64 next_addr; u64 next_arg1; struct sbi_hartmask hartMask; u32 next_mode; int owner_hartid; int boot_pending; int reset_type; int reset_reason; bool allow_cold_reboot; bool allow_warm_reboot; } hart_ledger[MAX_NUM_HARTS] = { { { 0, }, } }; extern unsigned long STACK_SIZE_PER_HART; static void mpfs_modify_dt(void *fdt) { fdt_cpu_fixup(fdt); fdt_fixups(fdt); fdt_reserved_memory_nomap_fixup(fdt); } static void __attribute__((__noreturn__)) mpfs_system_reset(u32 reset_type, u32 reset_reason) { (void)reset_type; (void)reset_reason; const u32 hartid = current_hartid(); struct sbi_scratch * const scratch = sbi_hartid_to_scratch(hartid); hart_ledger[hartid].boot_pending = 1; hart_ledger[hartid].reset_reason = reset_reason; hart_ledger[hartid].reset_type = reset_type; /* re-enable IPIs */ csr_write(CSR_MSTATUS, MIP_MSIP); csr_write(CSR_MIE, MIP_MSIP); sbi_exit(scratch); // never reached __builtin_unreachable(); } static int mpfs_system_reset_check(u32 reset_type, u32 reset_reason) { int result; switch (reset_type) { default: result = 0; break; case SBI_SRST_RESET_TYPE_SHUTDOWN: __attribute__((fallthrough)); // deliberate fallthrough case SBI_SRST_RESET_TYPE_COLD_REBOOT: __attribute__((fallthrough)); // deliberate fallthrough case SBI_SRST_RESET_TYPE_WARM_REBOOT: result = 1; break; } return result; } static struct sbi_system_reset_device mpfs_reset = { .name = "mpfs_reset", .system_reset_check = mpfs_system_reset_check, .system_reset = mpfs_system_reset, }; static int mpfs_early_init(bool cold_boot) { if (cold_boot) { sbi_system_reset_add_device(&mpfs_reset); } return 0; } static int mpfs_final_init(bool cold_boot) { if (!cold_boot) { return 0; } void *fdt = sbi_scratch_thishart_arg1_ptr(); if (fdt) { mpfs_modify_dt(fdt); } return 0; } static bool console_initialized = false; #if IS_ENABLED(CONFIG_UART_SURRENDER) static bool uart_surrendered_flag = false; void uart_surrender(void); void uart_surrender(void) { uart_surrendered_flag = true; } #endif static void mpfs_console_putc(char ch) { if (console_initialized) { u32 hartid = current_hartid(); #if IS_ENABLED(CONFIG_UART_SURRENDER) if (hartid || !uart_surrendered_flag) { #else { #endif int uart_putc(int hartid, const char ch); //TBD uart_putc(hartid, ch); } } } #define NO_BLOCK 0 #define GETC_EOF -1 static int mpfs_console_getc(void) { int result = GETC_EOF; bool uart_getchar(uint8_t *pbuf, int32_t timeout_sec, bool do_sec_tick); uint8_t rcvBuf; if (uart_getchar(&rcvBuf, NO_BLOCK, FALSE)) { result = rcvBuf; } return result; } static struct sbi_console_device mpfs_console = { .name = "mmuart", .console_putc = mpfs_console_putc, .console_getc = mpfs_console_getc, }; static int mpfs_console_init(void) { console_initialized = true; sbi_console_set_device(&mpfs_console); return 0; } static int mpfs_irqchip_init(bool cold_boot) { int rc = 0; u32 hartid = current_hartid(); if (cold_boot) { rc = plic_cold_irqchip_init(&plicInfo); } if (!rc) { // instead of calling plic_warm_irqchip_init ... // // rc = plic_warm_irqchip_init(&plicInfo, // (hartid) ? (2 * hartid - 1) : 0, (hartid) ? (2 * hartid) : -1); // // we'll do it ourselves to customize behavior.. //const int m_cntx_id = (hartid) ? (2 * hartid - 1) : 0; const int s_cntx_id = (hartid) ? (2 * hartid) : -1; struct plic_data * const plic = &plicInfo; size_t i, ie_words; if (!plic) { return SBI_EINVAL; } else { ie_words = plic->num_src / 32 + 1; // By default, disable all IRQs for M-mode of target HART // need to reconsider this with IHC... // //if (m_cntx_id > -1) { // for (i = 0; i < ie_words; i++) { // plic_set_ie(plic, m_cntx_id, i, 0); // } //} /* By default, disable all IRQs for S-mode of target HART */ if (s_cntx_id > -1) { for (i = 0; i < ie_words; i++) { plic_set_ie(plic, s_cntx_id, i, 0); } } // By default, disable M-mode threshold // need to reconsider these with IHC... // //if (m_cntx_id > -1) { // plic_set_thresh(plic, m_cntx_id, 0x7); //} /* By default, disable S-mode threshold */ if (s_cntx_id > -1) { plic_set_thresh(plic, s_cntx_id, 0x7); } } } return rc; } static int mpfs_ipi_init(bool cold_boot) { int result = 0; if (cold_boot) { result = aclint_mswi_cold_init(&mswi); } if (!result) { result = aclint_mswi_warm_init(); } return result; } static int mpfs_timer_init(bool cold_boot) { int result = 0; if (cold_boot) { result = aclint_mtimer_cold_init(&mtimer, NULL); } if (!result) { aclint_mtimer_warm_init(); } return result; } static void mpfs_final_exit(void) { /* re-enable IPIs */ csr_write(CSR_MSTATUS, MIP_MSIP); csr_write(CSR_MIE, MIP_MSIP); } #define MPFS_TLB_RANGE_FLUSH_LIMIT 0u static u64 mpfs_get_tlbr_flush_limit(void) { return MPFS_TLB_RANGE_FLUSH_LIMIT; } // don't allow OpenSBI to play with PMPs int sbi_hart_pmp_configure(struct sbi_scratch *pScratch) { (void)pScratch; return 0; } static struct sbi_domain_memregion mpfs_memregion[3] = { { .order = 0, .base = 0u, .flags = 0u }, { .order = __riscv_xlen, .base = 0u, .flags = (SBI_DOMAIN_MEMREGION_READABLE | SBI_DOMAIN_MEMREGION_WRITEABLE | SBI_DOMAIN_MEMREGION_EXECUTABLE) }, { .order = 0u, .base = 0u, .flags = 0u } }; static struct sbi_domain_memregion * mpfs_domains_root_regions(void) { return mpfs_memregion; } u32 mpfs_hart_index2id[MPFS_HART_COUNT] = { [0] = -1, [1] = 1, [2] = 2, [3] = 3, [4] = 4, }; void mpfs_domains_register_hart(int hartid, int boot_hartid) { hart_ledger[hartid].owner_hartid = boot_hartid; hart_ledger[hartid].boot_pending = 1; hart_ledger[hartid].reset_reason = 0; hart_ledger[hartid].reset_type = 0; } void mpfs_domains_deregister_hart(int hartid) { hart_ledger[hartid].owner_hartid = 0; hart_ledger[hartid].boot_pending = 0; assert((hartid > 0) & (hartid < ARRAY_SIZE(mpfs_hart_index2id))); mpfs_hart_index2id[hartid] = -1; } bool mpfs_is_hart_using_opensbi(int hartid) { bool result = true; assert((hartid > 0) & (hartid < ARRAY_SIZE(mpfs_hart_index2id))); if (mpfs_hart_index2id[hartid] == -1) { result = false; } return result; } void mpfs_mark_hart_as_booted(int hartid) { assert(hartid < ARRAY_SIZE(hart_ledger)); assert((hartid >= 0) & (hartid < ARRAY_SIZE(hart_ledger))); if (hartid < ARRAY_SIZE(hart_ledger)) { hart_ledger[hartid].boot_pending = 0; } } bool mpfs_is_last_hart_ready(void) { bool result; int outstanding = 0; for (int hartid = 0; hartid < ARRAY_SIZE(hart_ledger); hartid++) { outstanding += hart_ledger[hartid].boot_pending; } result = (outstanding == 0); return result; } void mpfs_domains_register_boot_hart(char *pName, u32 hartMask, int boot_hartid, u32 privMode, void * entryPoint, void * pArg1, bool allow_cold_reboot, bool allow_warm_reboot) { assert(hart_ledger[boot_hartid].owner_hartid == boot_hartid); memcpy(hart_ledger[boot_hartid].name, pName, ARRAY_SIZE(hart_ledger[boot_hartid].name) - 1); hart_ledger[boot_hartid].next_addr = (u64)entryPoint; hart_ledger[boot_hartid].next_arg1 = (u64)pArg1; hart_ledger[boot_hartid].hartMask.bits[0] = hartMask; hart_ledger[boot_hartid].next_mode = privMode; hart_ledger[boot_hartid].allow_cold_reboot = allow_cold_reboot; hart_ledger[boot_hartid].allow_warm_reboot = allow_warm_reboot; } static struct sbi_domain dom_table[MAX_NUM_HARTS] = { 0 }; static int mpfs_domains_init(void) { // register all AMP domains int result = SBI_EINVAL; for (int hartid = 1; hartid < ARRAY_SIZE(hart_ledger); hartid++) { const int boot_hartid = hart_ledger[hartid].owner_hartid; if (boot_hartid) { struct sbi_domain * const pDom = &dom_table[boot_hartid]; if (!pDom->index) { // { pDom->boot_hartid != boot_hartid) { pDom->boot_hartid = boot_hartid; memcpy(pDom->name, hart_ledger[boot_hartid].name, ARRAY_SIZE(dom_table[0].name)-1); struct sbi_hartmask * const pMask = &(hart_ledger[boot_hartid].hartMask); struct sbi_scratch * const pScratch = sbi_scratch_thishart_ptr(); pDom->regions = mpfs_domains_root_regions(); pDom->regions[0].order = log2roundup(pScratch->fw_size); pDom->regions[0].base = pScratch->fw_start & ~((1UL << pDom->regions[0].order) - 1UL); pDom->regions[0].flags = 0u; pDom->next_arg1 = hart_ledger[boot_hartid].next_arg1; pDom->next_addr = hart_ledger[boot_hartid].next_addr; pDom->next_mode = hart_ledger[boot_hartid].next_mode; pDom->system_reset_allowed = TRUE; pDom->possible_harts = pMask; result = sbi_domain_register(pDom, pMask); if (result) { sbi_printf("%s(): sbi_domain_register() failed for %s\n", __func__, pDom->name); break; } } } else { //sbi_printf("%s(): boot_hart_id not set for u54_%d\n", __func__, hartid); } } return result; } static int mpfs_hart_start(u32 hartid, ulong saddr) { (void)hartid; (void)saddr; return 0; } static int mpfs_hart_stop(void) { const u32 hartid = current_hartid(); /* re-enable IPIs */ csr_write(CSR_MSTATUS, MIP_MSIP); csr_write(CSR_MIE, MIP_MSIP); if (hart_ledger[hartid].owner_hartid == hartid) { switch (hart_ledger[hartid].reset_reason) { case SBI_SRST_RESET_REASON_SYSFAIL: mHSS_DEBUG_PRINTF(LOG_ERROR, "u54_%d reported SYSTEM FAILURE\n", hartid); break; case SBI_SRST_RESET_REASON_NONE: __attribute__((fallthrough)); // deliberate fallthrough default: break; } switch(hart_ledger[hartid].reset_type) { case SBI_SRST_RESET_TYPE_SHUTDOWN: break; #if IS_ENABLED(CONFIG_ALLOW_COLDREBOOT) case SBI_SRST_RESET_TYPE_COLD_REBOOT: if (IS_ENABLED(CONFIG_ALLOW_COLDREBOOT_ALWAYS) || hart_ledger[hartid].allow_cold_reboot) { # if IS_ENABLED(CONFIG_SERVICE_WDOG) HSS_Wdog_Reboot(HSS_HART_ALL); #endif } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "u54_%d not permitted to cold reboot\n", hartid); } __attribute__((fallthrough)); // deliberate fallthrough #endif case SBI_SRST_RESET_TYPE_WARM_REBOOT: __attribute__((fallthrough)); // deliberate fallthrough default: HSS_OpenSBI_Reboot(); break; } } asm("j _start"); // never reached __builtin_unreachable(); } static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0); bool mpfs_is_first_boot(void); bool mpfs_is_first_boot(void) { return (atomic_xchg(&coldboot_lottery, 1) == 0); } const struct sbi_hsm_device mpfs_hsm = { .name = "mpfs_hsm", .hart_start = mpfs_hart_start, .hart_stop = mpfs_hart_stop, .hart_suspend = NULL }; const struct sbi_platform_operations platform_ops = { .early_init = mpfs_early_init, .final_init = mpfs_final_init, .early_exit = NULL, .final_exit = mpfs_final_exit, .misa_check_extension = NULL, .misa_get_xlen = NULL, .console_init = mpfs_console_init, .ipi_init = mpfs_ipi_init, .irqchip_init = mpfs_irqchip_init, .irqchip_exit = NULL, .get_tlbr_flush_limit = mpfs_get_tlbr_flush_limit, .timer_init = mpfs_timer_init, .timer_exit = NULL, .domains_init = mpfs_domains_init, .vendor_ext_check = HSS_SBI_Vendor_Ext_Check, .vendor_ext_provider = HSS_SBI_ECALL_Handler }; const struct sbi_platform platform = { .opensbi_version = OPENSBI_VERSION, .platform_version = SBI_PLATFORM_VERSION(0x0, 0x2), .name = "Microchip PolarFire(R) SoC", .features = SBI_PLATFORM_DEFAULT_FEATURES, // already have PMPs setup .hart_count = MPFS_HART_COUNT, .hart_index2id = mpfs_hart_index2id, .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, .platform_ops_addr = (unsigned long)&platform_ops, .firmware_context = 0 }; hart-software-services-2022.10/services/powermode/000077500000000000000000000000001432224323300221115ustar00rootroot00000000000000hart-software-services-2022.10/services/powermode/Kconfig000066400000000000000000000003021432224323300234070ustar00rootroot00000000000000config SERVICE_POWERMODE bool "Low Power Mode support" default n help This feature enables support for Low Power Mode operation. If you do not know what to do here, say Y. hart-software-services-2022.10/services/powermode/Makefile000066400000000000000000000024411432224323300235520ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Powermode Service SRCS-$(CONFIG_SERVICE_POWERMODE) += \ services/powermode/powermode_service.c \ INCLUDES +=\ -I./services/powermode \ hart-software-services-2022.10/services/powermode/powermode_service.c000066400000000000000000000052441432224323300260030ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file PowerMode Driver State Machine * \brief Clock Switching / MSS Power Mode Selection */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" static void powermode_init_handler(struct StateMachine * const pMyMachine); static void powermode_state1_handler(struct StateMachine * const pMyMachine); static void powermode_lastState_handler(struct StateMachine * const pMyMachine); /*! * \brief PowerMode Driver States */ enum PowerModeStatesEnum { POWER_MODE_INITIALIZATION, POWER_MODE_STATE1_DO_SOMETHING, POWER_MODE_LAST_STATE, POWER_MODE_NUM_STATES = POWER_MODE_LAST_STATE+1 }; /*! * \brief PowerMode Driver State Descriptors */ static const struct StateDesc powermode_state_descs[] = { { (const stateType_t)POWER_MODE_INITIALIZATION, (const char *)"init", NULL, NULL, &powermode_init_handler }, { (const stateType_t)POWER_MODE_STATE1_DO_SOMETHING, (const char *)"state1", NULL, NULL, &powermode_state1_handler }, { (const stateType_t)POWER_MODE_LAST_STATE, (const char *)"lastState", NULL, NULL, &powermode_lastState_handler } }; /*! * \brief PowerMode Driver State Machine */ struct StateMachine powermode_service = { .state = (stateType_t)POWER_MODE_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)POWER_MODE_NUM_STATES, .pMachineName = (const char *)"powermode_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = powermode_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void powermode_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state++; } ///////////////// static uint32_t i = HSS_HART_U54_1; static void powermode_state1_handler(struct StateMachine * const pMyMachine) { // check each core to see if it wants to transmit if (IPI_GetQueuePendingCount(i)) { IPI_ConsumeIntent(i, IPI_MSG_POWERMODE); } i = (i + 1u) % HSS_HART_NUM_PEERS; } ///////////////// static void powermode_lastState_handler(struct StateMachine * const pMyMachine) { pMyMachine->state = POWER_MODE_INITIALIZATION; } hart-software-services-2022.10/services/powermode/powermode_service.h000066400000000000000000000031771432224323300260130ustar00rootroot00000000000000#ifndef HSS_POWERMODE_SERVICE_H #define HSS_POWERMODE_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - PowerMode Service * */ /*! * \file PowerMode Service State Machine * \brief Clock Switching / MSS Power Mode Selection */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" extern struct StateMachine powermode_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/qspi/000077500000000000000000000000001432224323300210645ustar00rootroot00000000000000hart-software-services-2022.10/services/qspi/Kconfig000066400000000000000000000014301432224323300223650ustar00rootroot00000000000000config SERVICE_QSPI bool "Boot from QSPI NAND flash support" default y help This feature enables support for booting via QSPI NAND Flash. Currently the Winbond W25N01GV is supported. If you do not know what to do here, say Y. menu "QSPI" visible if SERVICE_QSPI choice prompt "QSPI Driver" default SERVICE_QSPI_WINBOND_W25N01GV config SERVICE_QSPI_WINBOND_W25N01GV bool "Winbond W25N01GV" depends on SERVICE_QSPI help This feature enables support for Winbond W25N01GV SPI NAND flash. If you don't know what to do here, say Y. config SERVICE_QSPI_MICRON_MQ25T bool "Micron MQ25T" depends on SERVICE_QSPI help This feature enables support for Micron MQ25T SPI NOR flash. If you don't know what to do here, say N. endchoice endmenu hart-software-services-2022.10/services/qspi/Makefile000066400000000000000000000025521432224323300225300ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # QSPI Service (NOTE: not a traditional super-loop service) EXTRA_SRCS-$(CONFIG_SERVICE_QSPI) += \ services/qspi/qspi_api.c \ INCLUDES +=\ -I./services/qspi \ services/qspi/qspi_api.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/qspi/qspi_api.c000066400000000000000000000411431432224323300230400ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file QSPI (null) Service * \brief Setup QSPI */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_progress.h" #include "hss_debug.h" #include #include #include "qspi_service.h" #include "encoding.h" #include "mss_qspi.h" #include "mss_sys_services.h" #include "mss_peripherals.h" #if IS_ENABLED(CONFIG_SERVICE_QSPI_WINBOND_W25N01GV) # include "winbond_w25n01gv.h" #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI_MICRON_MQ25T) # include "micron_mt25q.h" #endif /* * QSPI doesn't need a "service" to run every super-loop, but it does need to be * initialized early... */ #define QSPI_MIN_BYTE_SECTOR_SIZE 512 enum spi_type { SPI_NAND, SPI_NOR }; struct FlashDescriptor { uint32_t jedecId; uint32_t pageSize; // minimum writable size uint32_t pagesPerBlock; // writable pages per erasable sector/block uint32_t blocksPerDie; // erasable sectors/block per die enum spi_type type; const char * const name; } qspiFlashes[] = { { 0xEFAA21u, 2048u, 64u, 1024u, SPI_NAND, "Winbond W25N01GV" }, // EFh => Winbond, AA21h => W25N01GV { 0x20BA19u, 256u, 256u, 512u, SPI_NOR, "Micron N25Q256A" }, // 20h => Micron, BA91h => N25Q256A, and using sector as block }; static uint32_t pageSize, blockSize, dieSize, eraseSize, pageCount, blockCount; static enum spi_type spi_type; static uint32_t numBadBlocks; static uint16_t *pLogicalToPhysicalMap = NULL; static uint16_t *pBadBlocksMap = NULL; static struct HSS_QSPI_Cache_Descriptor { bool dirtyCache; bool inCache; } *pLogicalBlockDesc = NULL; static uint8_t *pCacheDataBuffer = NULL; static bool qspiInitialized = false; static size_t qspiIndex = 0u; bool cacheDirtyFlag = false; //////////////////////////////////////////////////////////////////////////////////////// // // Generic Local module functions // __attribute__((nonnull)) static bool flash_id_to_descriptor_(const uint32_t jedec_id, size_t *indexOut) { bool result = false; assert(indexOut); for (size_t i = 0u; i < ARRAY_SIZE(qspiFlashes); i++) { if (qspiFlashes[i].jedecId == jedec_id) { *indexOut = i; result = true; break; } } return result; } static void build_bad_block_map_(void) { #if IS_ENABLED(CONFIG_SERVICE_QSPI_WINBOND_W25N01GV) numBadBlocks = Flash_scan_for_bad_blocks(pBadBlocksMap); size_t badBlockIndex = 0u; size_t logicalBlockIndex = 0u; uint32_t badBlocksRemaining = numBadBlocks; for (size_t physicalBlockIndex = 0u; physicalBlockIndex < blockCount; physicalBlockIndex++) { if (badBlocksRemaining && (pBadBlocksMap[badBlockIndex] == physicalBlockIndex)) { // skip bad physical block badBlockIndex++; badBlocksRemaining--; } else { // good physical block, so use pLogicalToPhysicalMap[logicalBlockIndex] = physicalBlockIndex; logicalBlockIndex++; } } #else size_t logicalBlockIndex = 0u; for (size_t physicalBlockIndex = 0u; physicalBlockIndex < blockCount; physicalBlockIndex++) { pLogicalToPhysicalMap[logicalBlockIndex] = physicalBlockIndex; logicalBlockIndex++; } #endif } __attribute__((pure)) static inline uint32_t column_to_block_(const uint32_t column_addr) { assert(blockSize); // avoid divide by zero const uint32_t result = (column_addr / blockSize); return result; } __attribute__((pure)) static inline uint32_t logical_to_physical_address_(const uint32_t logical_addr) { assert(blockSize); // avoid divide by zero const uint16_t logical_block_num = logical_addr / blockSize; const uint32_t remainder = logical_addr % blockSize; const uint16_t physical_block_number = pLogicalToPhysicalMap[logical_block_num]; const uint32_t result = (physical_block_number * blockSize) + remainder; return result; } __attribute__((pure)) static inline uint32_t logical_to_physical_block_(const uint32_t logical_block) { const uint32_t result = pLogicalToPhysicalMap[logical_block]; return result; } static void demandCopyFlashBlocksToCache_(size_t byteOffset, size_t byteCount, bool markDirty) { for (size_t offset = byteOffset; offset < (byteOffset + byteCount); offset += blockSize) { const size_t physicalBlockOffset = logical_to_physical_block_(column_to_block_(offset)); if (!pLogicalBlockDesc[physicalBlockOffset].inCache) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "Reading block %u into cache\n", physicalBlockOffset); const size_t physicalBlockByteOffset = physicalBlockOffset * blockSize; Flash_read(pCacheDataBuffer + physicalBlockByteOffset, physicalBlockByteOffset, blockSize); pLogicalBlockDesc[physicalBlockOffset].inCache = true; } if (markDirty) { pLogicalBlockDesc[physicalBlockOffset].dirtyCache = true; } } } #if IS_ENABLED(CONFIG_SERVICE_QSPI_MICRON_MQ25T) static uint8_t flashEraseSector(uint32_t addr) { uint8_t status = 0xff; /* For the flashes with page size less than 512, as part of * initialization we have already changed the flash parameters, * because of this change the erasable sector size will be 128K * but the actual erasable sector size should be 64K. * so derive the sector address and erase each sector. */ if (qspiFlashes[qspiIndex].pageSize >= QSPI_MIN_BYTE_SECTOR_SIZE) { status = Flash_sector_erase(addr << 16); // 64K sector } else { /* Total erasable sectors in the given address */ uint32_t totalSectors = qspiFlashes[qspiIndex].blocksPerDie / qspiFlashes[qspiIndex].pageSize; for(int count = 0; count < totalSectors; count++) { status = Flash_sector_erase(((addr * totalSectors) + count) << 16); // 64K sector } } return status; } #endif static void copyCacheToFlashBlocks_(size_t byteOffset, size_t byteCount) { const size_t endOffset = byteOffset + byteCount; size_t dirtyBlockCount = 0u; mHSS_DEBUG_PRINTF_EX("\n"); for (size_t blockOffset = 0u; blockOffset < blockCount; blockOffset++) { if (pLogicalBlockDesc[blockOffset].dirtyCache) { dirtyBlockCount++; } } const size_t initialDirtyBlockCount = dirtyBlockCount; uint8_t status = 0xFF; for (size_t offset = byteOffset; dirtyBlockCount && (offset < endOffset); offset += blockSize) { HSS_ShowProgress(initialDirtyBlockCount, dirtyBlockCount); const size_t physicalBlockOffset = logical_to_physical_block_(column_to_block_(offset)); if (pLogicalBlockDesc[physicalBlockOffset].inCache) { if (pLogicalBlockDesc[physicalBlockOffset].dirtyCache) { const size_t physicalBlockByteOffset = physicalBlockOffset * blockSize; #if IS_ENABLED(CONFIG_SERVICE_QSPI_WINBOND_W25N01GV) status = Flash_erase_block(physicalBlockOffset); #else status = flashEraseSector(physicalBlockOffset); #endif if (status) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Error erasing block %u\n", physicalBlockOffset); break; } status = Flash_program(pCacheDataBuffer + physicalBlockByteOffset, physicalBlockByteOffset, blockSize); if (status) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Error programming block %u\n", physicalBlockOffset); } pLogicalBlockDesc[physicalBlockOffset].dirtyCache = false; dirtyBlockCount--; } } } HSS_ShowProgress(initialDirtyBlockCount, 0u); } //////////////////////////////////////////////////////////////////////////////////////// // // QSPI Uncached Functions // // bool HSS_QSPIInit(void) { if (!qspiInitialized) { /* read and output Flash ID as a sanity test */ (void)mss_config_clk_rst(MSS_PERIPH_QSPIXIP, (uint8_t) 0u, PERIPHERAL_ON); uint8_t rd_buf[10] __attribute__ ((aligned(4))); Flash_init(MSS_QSPI_QUAD_FULL); Flash_readid(rd_buf); uint32_t jedec_id = ((rd_buf[0] << 16) | (rd_buf[1] <<8) | (rd_buf[2])); if (flash_id_to_descriptor_(jedec_id, &qspiIndex)) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "%s detected (JEDEC %06X)\n", qspiFlashes[qspiIndex].name, jedec_id); if (qspiFlashes[qspiIndex].pageSize >= QSPI_MIN_BYTE_SECTOR_SIZE) { pageSize = qspiFlashes[qspiIndex].pageSize; blockSize = qspiFlashes[qspiIndex].pageSize * qspiFlashes[qspiIndex].pagesPerBlock; blockCount = qspiFlashes[qspiIndex].blocksPerDie; } else { /* The minimum sector size (page size) allowed for a block device is * 512. so for the flashes with page size less than 512 will get an * error on host PC like "Unsupported sector size 256" and from here * onwards the writes and reads will fail on the block device. * to overcome this, tweak the pageSize and other parameters of the * flash so that the block device is recognized on the host PC. */ pageSize = QSPI_MIN_BYTE_SECTOR_SIZE; blockSize = pageSize * qspiFlashes[qspiIndex].pagesPerBlock; blockCount = pageSize / 2; } eraseSize = blockSize; blockCount = qspiFlashes[qspiIndex].blocksPerDie; pageCount = qspiFlashes[qspiIndex].pagesPerBlock * blockCount; dieSize = blockSize * blockCount; spi_type = qspiFlashes[qspiIndex].type; // mHSS_DEBUG_PRINTF(LOG_NORMAL, "pageSize: %u\n", pageSize); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "blockSize: %u\n", blockSize); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "eraseSize: %u\n", eraseSize); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "pageCount: %u\n", pageCount); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "blockCount: %u\n", blockCount); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "dieSize: %u\n", dieSize); // // we're going to place buffers in DDR for // * a set of logical to physical block qspiIndex mappings; // * a list of bad blocks; // * a set of logical block descriptors; // * a data cache the same size as the QSPI Flash device // extern const uint64_t __ddr_start; #define DDR_START (&__ddr_start) uint8_t *pU8Buffer = (uint8_t *)DDR_START; // start of cached DDR, as good a place as any pLogicalToPhysicalMap = (uint16_t *)pU8Buffer; memset(pLogicalToPhysicalMap, 0, (sizeof(*pLogicalToPhysicalMap) * blockCount)); pU8Buffer += (sizeof(*pLogicalToPhysicalMap) * blockCount); pBadBlocksMap = (uint16_t *)pU8Buffer; memset(pBadBlocksMap, 0, (sizeof(*pBadBlocksMap) * blockCount)); pU8Buffer += (sizeof(*pBadBlocksMap) * blockCount); pLogicalBlockDesc = (struct HSS_QSPI_Cache_Descriptor*)pU8Buffer; memset(pLogicalBlockDesc, 0, (sizeof(*pLogicalBlockDesc) * blockCount)); pU8Buffer += (sizeof(*pLogicalBlockDesc) * blockCount); pCacheDataBuffer = (uint8_t *)pU8Buffer; // mHSS_DEBUG_PRINTF(LOG_NORMAL, "pLogicalToPhysicalMap: %p\n", pLogicalToPhysicalMap); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "pLogicalBlockDesc: %p\n", pLogicalBlockDesc); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "pCacheDataBuffer: %p\n", pCacheDataBuffer); // // check for bad blocks and reduce the number of blocks accordingly... // our caches and logical block descriptors above may now be slightly too large, but this // is of no consequence build_bad_block_map_(); blockCount -= numBadBlocks; // adjust block count to take account of bad blocks pageCount = qspiFlashes[qspiIndex].pagesPerBlock * blockCount; dieSize = blockSize * blockCount; // mHSS_DEBUG_PRINTF(LOG_NORMAL, "blockCount (after bad blocks): %u\n", blockCount); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initialized Flash\n"); qspiInitialized = true; } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Initialized Flash (JEDEC %06X)\n", jedec_id); } } return qspiInitialized; } __attribute__((nonnull)) bool HSS_QSPI_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount) { bool result = true; const uint32_t read_addr = logical_to_physical_address_((uint32_t)srcOffset); Flash_init(MSS_QSPI_QUAD_FULL); Flash_read((uint8_t *)pDest, read_addr, (uint32_t) byteCount); /* Configure the QSPI and Flash back to default values, so that * rest of the applications will access the flash with defaults. */ Flash_init(MSS_QSPI_NORMAL); return result; } __attribute__((nonnull)) bool HSS_QSPI_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount) { bool result = true; const uint32_t write_addr = logical_to_physical_address_((uint32_t)dstOffset); Flash_program((uint8_t *)pSrc, write_addr, (uint32_t)byteCount); return result; } __attribute__((nonnull)) void HSS_QSPI_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount) { *pBlockSize = pageSize; *pEraseSize = eraseSize; *pBlockCount = pageCount; mHSS_DEBUG_PRINTF(LOG_NORMAL, "QSPI: %s - %u byte pages, %u byte blocks, %u pages per block\n", qspiFlashes[qspiIndex].name, qspiFlashes[qspiIndex].pageSize, qspiFlashes[qspiIndex].blocksPerDie, qspiFlashes[qspiIndex].pagesPerBlock); } void HSS_QSPI_FlushWriteBuffer(void) { } void HSS_QSPI_FlashChipErase(void) { #if IS_ENABLED(CONFIG_SERVICE_QSPI_WINBOND_W25N01GV) for (uint32_t blockIndex = 0u; blockIndex < blockCount; blockIndex++) { HSS_ShowProgress(blockCount, blockCount - blockIndex); Flash_erase_block(blockIndex); } #else Flash_erase(); #endif HSS_ShowProgress(blockCount, 0u); } void HSS_QSPI_BadBlocksInfo(void) { if ((qspiInitialized) && (spi_type == SPI_NAND)) { blockCount = qspiFlashes[qspiIndex].blocksPerDie; pageCount = qspiFlashes[qspiIndex].pagesPerBlock * blockCount; dieSize = blockSize * blockCount; build_bad_block_map_(); // update bad blocks mapping and numBadBlocks mHSS_DEBUG_PRINTF(LOG_ERROR, "QSPI Flash: %u bad block%s found\n", numBadBlocks, numBadBlocks == 1 ? "":"s"); if (numBadBlocks) { blockCount -= numBadBlocks; // adjust block count to take account of bad blocks pageCount = qspiFlashes[qspiIndex].pagesPerBlock * blockCount; dieSize = blockSize * blockCount; mHSS_DEBUG_PRINTF_EX("Bad Block%s: %u", numBadBlocks == 1 ? "":"s", pBadBlocksMap[0]); for (size_t i = 1u; i < numBadBlocks; i++) { mHSS_DEBUG_PRINTF_EX(", %u", pBadBlocksMap[i]); } } } } //////////////////////////////////////////////////////////////////////////////////////// // // QSPI Cached Functions // // To make QSPI Flash available as a USB drive, we need to cache the contents // in DDR. This allows us to reduce wear on the flash by minimizing the number of // block erases performed, and it also makes operation quicker... // bool HSS_CachedQSPIInit(void) { bool result = HSS_QSPIInit(); return result; } __attribute__((nonnull)) bool HSS_CachedQSPI_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount) { bool result = true; assert(pDest); assert((srcOffset + byteCount) <= dieSize); demandCopyFlashBlocksToCache_(srcOffset, byteCount, false); memcpy(pDest, pCacheDataBuffer + srcOffset, byteCount); return result; } __attribute__((nonnull)) bool HSS_CachedQSPI_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount) { bool result = true; assert(pSrc); assert((dstOffset + byteCount) <= dieSize); cacheDirtyFlag = true; demandCopyFlashBlocksToCache_(dstOffset, byteCount, true); memcpy(pCacheDataBuffer + dstOffset, pSrc, byteCount); return result; } __attribute__((nonnull)) void HSS_CachedQSPI_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount) { HSS_QSPI_GetInfo(pBlockSize, pEraseSize, pBlockCount); } void HSS_CachedQSPI_FlushWriteBuffer(void) { if (cacheDirtyFlag) { copyCacheToFlashBlocks_(0u, dieSize); mHSS_DEBUG_PRINTF_EX("\n"); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Synchronized Cache with Flash ...\n"); cacheDirtyFlag = false; } } hart-software-services-2022.10/services/qspi/qspi_service.h000066400000000000000000000043001432224323300237260ustar00rootroot00000000000000#ifndef HSS_QSPI_DRIVER_H #define HSS_QSPI_DRIVER_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - QSPI Initialization * */ /*! * \file QSPI API * \brief QSPI (null) Service API */ #ifdef __cplusplus extern "C" { #endif #include "hss_types.h" bool HSS_QSPIInit(void); bool HSS_QSPI_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount); bool HSS_QSPI_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount); void HSS_QSPI_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount); void HSS_QSPI_FlushWriteBuffer(void); void HSS_QSPI_FlashChipErase(void); void HSS_QSPI_BadBlocksInfo(void); bool HSS_CachedQSPIInit(void); bool HSS_CachedQSPI_ReadBlock(void *pDest, size_t srcOffset, size_t byteCount); bool HSS_CachedQSPI_WriteBlock(size_t dstOffset, void *pSrc, size_t byteCount); void HSS_CachedQSPI_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount); void HSS_CachedQSPI_FlushWriteBuffer(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/scrub/000077500000000000000000000000001432224323300212265ustar00rootroot00000000000000hart-software-services-2022.10/services/scrub/Kconfig000066400000000000000000000025101432224323300225270ustar00rootroot00000000000000config SERVICE_SCRUB bool "RAM Scrubbing support" default n help This feature enables support for E51-delegated RAM Scrubbing. If you do not know what to do here, say Y. menu "RAM Scrubbing Service" visible if SERVICE_SCRUB config SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER int "Number of bytes per superloop iteration to scrub" default 4096 depends on SERVICE_SCRUB help This parameter determines how many bytes will be scrubbed per superloop. config SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS int "Throttle to run every X superloops" default 256 depends on SERVICE_SCRUB help This parameter throttles the scrubbing service to only run once every specified number of superloop iterations. config SERVICE_SCRUB_CACHED_DDR bool "Cached RAM Scrubbing support" default n help This feature enables support for Cached RAM. This will conflict with any Linux drivers using non-coherent DMA transfers for speed on PolarFire SoC, such as PCIe, but may be of use in bare metal systems where the working set won't guarantee sufficient flushing of the cache to prevent undetected singe-bit errors. If you do not know what to do here, say N. endmenu hart-software-services-2022.10/services/scrub/Makefile000066400000000000000000000024251432224323300226710ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # RAM Scrubbing Service SRCS-$(CONFIG_SERVICE_SCRUB) += \ services/scrub/scrub_service.c \ INCLUDES +=\ -I./services/scrub \ hart-software-services-2022.10/services/scrub/scrub_service.c000066400000000000000000000123561432224323300242370ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file RAM Scrubbing Driver State Machine * \brief E51-Assisted RAM Scrubbing */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_boot_pmp.h" #include "ssmb_ipi.h" #include #include #include "hss_memcpy_via_pdma.h" #include "scrub_service.h" #include "scrub_types.h" #ifndef PRIx64 # define PRIx64 "llu" #endif static void scrub_init_handler(struct StateMachine * const pMyMachine); static void scrub_scrubbing_handler(struct StateMachine * const pMyMachine); /*! * \brief SCRUB Driver States */ enum ScrubStatesEnum { SCRUB_INITIALIZATION, SCRUB_SCRUBBING, SCRUB_NUM_STATES = SCRUB_SCRUBBING+1 }; /*! * \brief SCRUB Driver State Descriptors */ static const struct StateDesc scrub_state_descs[] = { { (const stateType_t)SCRUB_INITIALIZATION, (const char *)"init", NULL, NULL, &scrub_init_handler }, { (const stateType_t)SCRUB_SCRUBBING, (const char *)"scrubbing", NULL, NULL, &scrub_scrubbing_handler }, }; /*! * \brief SCRUB Driver State Machine */ struct StateMachine scrub_service = { .state = (stateType_t)SCRUB_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)SCRUB_NUM_STATES, .pMachineName = (const char *)"scrub_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = scrub_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void scrub_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state++; } ///////////////// extern const uint64_t __l2lim_start, __l2lim_end; extern const uint64_t __l2_start, __l2_end; extern const uint64_t __ddr_start, __ddr_end; extern const uint64_t __ddrhi_start, __ddrhi_end; extern const uint64_t __ncddrhi_start, __ncddrhi_end; extern const uint64_t __dtim_start, __dtim_end; extern const uint64_t __e51itim_start, __e51itim_end; extern const uint64_t __u54_1_itim_start, __u54_1_itim_end; extern const uint64_t __u54_2_itim_start, __u54_2_itim_end; extern const uint64_t __u54_3_itim_start, __u54_3_itim_end; extern const uint64_t __u54_4_itim_start, __u54_4_itim_end; const struct { uintptr_t baseAddr; uintptr_t endAddr; } rams[] = { { (uintptr_t)&__l2lim_start, (uintptr_t)&__l2lim_end }, { (uintptr_t)&__l2_start, (uintptr_t)&__l2_end }, #if !IS_ENABLED(CONFIG_SKIP_DDR) #if IS_ENABLED(CONFIG_SERVICE_SCRUB_CACHED_DDR) { (uintptr_t)&__ddr_start, (uintptr_t)&__ddr_end }, { (uintptr_t)&__ddrhi_start, (uintptr_t)&__ddrhi_end }, #endif { (uintptr_t)&__ncddrhi_start, (uintptr_t)&__ncddrhi_end }, #endif //{ (uintptr_t)&__dtim_start, (uintptr_t)&__dtim_end }, //{ (uintptr_t)&__e51itim_start, (uintptr_t)&__e51itim_end }, //{ (uintptr_t)&__u54_1_itim_start, (uintptr_t)&__u54_1_itim_end }, //{ (uintptr_t)&__u54_2_itim_start, (uintptr_t)&__u54_2_itim_end }, //{ (uintptr_t)&__u54_3_itim_start, (uintptr_t)&__u54_3_itim_end }, //{ (uintptr_t)&__u54_4_itim_start, (uintptr_t)&__u54_4_itim_end }, }; static size_t offset = 0u; static size_t index = 0u; static size_t entryCount = 0u; static void scrub_scrubbing_handler(struct StateMachine * const pMyMachine) { (void)pMyMachine; if (ARRAY_SIZE(rams)) { if (!entryCount) { if ((rams[index].baseAddr + offset) >= rams[index].endAddr) { index = (index + 1u) % ARRAY_SIZE(rams); // mHSS_DEBUG_PRINTF(LOG_NORMAL, "Scrubbing %p to %p\n", rams[index].baseAddr, rams[index].endAddr); offset = 0u; } const uintptr_t length = rams[index].endAddr - rams[index].baseAddr; if (length) { const size_t chunkSize = MIN(CONFIG_SERVICE_SCRUB_MAX_SIZE_PER_LOOP_ITER, length-offset); const uint64_t *pStart = (uint64_t *)(rams[index].baseAddr + offset); const uint64_t *pEnd = (uint64_t *)(pStart + chunkSize); for (uint64_t *pMem = (uint64_t *)pStart; pMem < pEnd; pMem++) { *(volatile uint64_t *)pMem; } offset = offset + chunkSize; } } } #if defined(CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS) && (CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS) entryCount = (entryCount + 1u) % CONFIG_SERVICE_SCRUB_RUN_EVERY_X_SUPERLOOPS; #else entryCount = 0u; #endif } void scrub_dump_stats(void) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "index: 0x%" PRIx64 "\n", index); mHSS_DEBUG_PRINTF(LOG_NORMAL, "mem base: 0x%" PRIx64 "\n", rams[index].baseAddr); mHSS_DEBUG_PRINTF(LOG_NORMAL, "offset: 0x%" PRIx64 "\n", offset); mHSS_DEBUG_PRINTF(LOG_NORMAL, "entryCount: 0x%" PRIx64 "\n", entryCount); } hart-software-services-2022.10/services/scrub/scrub_service.h000066400000000000000000000032561432224323300242430ustar00rootroot00000000000000#ifndef HSS_SCRUB_SERVICE_H #define HSS_SCRUB_SERVICE_H /******************************************************************************* * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - RAM Scrubber Service API * */ /*! * \file RAM Scrubber API * \brief RAM Scrubber State Machine API function declarations */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" #include "scrub_types.h" extern struct StateMachine scrub_service; void scrub_dump_stats(void); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/scrub/scrub_types.h000066400000000000000000000030471432224323300237450ustar00rootroot00000000000000#ifndef HSS_SCRUB_TYPES_H #define HSS_SCRUB_TYPES_H /******************************************************************************* * Copyright 2021 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - RAM Scrubber Types * */ /*! * \file RAM Scrubber Types * \brief RAM Scrubber Type Definitions */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/sgdma/000077500000000000000000000000001432224323300212035ustar00rootroot00000000000000hart-software-services-2022.10/services/sgdma/Kconfig000066400000000000000000000002751432224323300225120ustar00rootroot00000000000000config SERVICE_SGDMA bool "SGDMA support" default n help This feature enables support for E51-delegated Scatter-Gather DMA. If you do not know what to do here, say Y. hart-software-services-2022.10/services/sgdma/Makefile000066400000000000000000000024151432224323300226450ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # SGDMA Service SRCS-$(CONFIG_SERVICE_SGDMA) += \ services/sgdma/sgdma_service.c \ INCLUDES +=\ -I./services/sgdma \ hart-software-services-2022.10/services/sgdma/sgdma_service.c000066400000000000000000000121561432224323300241670ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file SGDMA Driver State Machine * \brief E51-Assisted ScatterGather DMA Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_boot_pmp.h" #include "ssmb_ipi.h" #include #include #include "hss_memcpy_via_pdma.h" #include "sgdma_service.h" #include "sgdma_types.h" static void sgdma_init_handler(struct StateMachine * const pMyMachine); static void sgdma_idle_handler(struct StateMachine * const pMyMachine); static void sgdma_transferring_handler(struct StateMachine * const pMyMachine); /*! * \brief SGDMA Driver States */ enum SgdmaStatesEnum { SGDMA_INITIALIZATION, SGDMA_IDLE, SGDMA_TRANSFERRING, SGDMA_NUM_STATES = SGDMA_TRANSFERRING+1 }; /*! * \brief SGDMA Driver State Descriptors */ static const struct StateDesc sgdma_state_descs[] = { { (const stateType_t)SGDMA_INITIALIZATION, (const char *)"init", NULL, NULL, &sgdma_init_handler }, { (const stateType_t)SGDMA_IDLE, (const char *)"idle", NULL, NULL, &sgdma_idle_handler }, { (const stateType_t)SGDMA_TRANSFERRING, (const char *)"transferring", NULL, NULL, &sgdma_transferring_handler } }; /*! * \brief SGDMA Driver State Machine */ struct StateMachine sgdma_service = { .state = (stateType_t)SGDMA_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)SGDMA_NUM_STATES, .pMachineName = (const char *)"sgdma_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = sgdma_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL }; static struct HSS_SGDMA_BlockDesc *pBlockDesc = NULL; static enum HSSHartId activeHart = HSS_HART_E51; // set to signify no U54 active... // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void sgdma_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state++; } ///////////////// static uint32_t i = HSS_HART_U54_1; static void sgdma_idle_handler(struct StateMachine * const pMyMachine) { (void)pMyMachine; // check each core to see if it wants to transmit if (IPI_GetQueuePendingCount(i)) { IPI_ConsumeIntent(i, IPI_MSG_SCATTERGATHER_DMA); } i = (i + 1u) % HSS_HART_NUM_PEERS; } ///////////////// #define MAX_SGDMA_SIZE_PER_LOOP_ITER (4096u) static size_t remaining_in_current_block = 0u; static void sgdma_transferring_handler(struct StateMachine * const pMyMachine) { //mHSS_DEBUG_PRINTF(LOG_NORMAL, "called\n"); assert(pBlockDesc != NULL); if (pBlockDesc->ext) { // for now, memcpy... // TODO: replace this with PDMA, and x blocks per superloop?? // should a max pBlockDesc->size be permitted per loop iteration? I guess so... // size_t chunk_size = 0u; if (remaining_in_current_block == 0u) { remaining_in_current_block = pBlockDesc->size; chunk_size = pBlockDesc->size; } else { chunk_size = remaining_in_current_block; } if (chunk_size > MAX_SGDMA_SIZE_PER_LOOP_ITER) { chunk_size = MAX_SGDMA_SIZE_PER_LOOP_ITER; } // check PMPs - todo - check MPRs also #if IS_ENABLED(CONFIG_SERVICE_BOOT) if (HSS_PMP_CheckWrite(activeHart, (ptrdiff_t)pBlockDesc->dest_phys_addr, chunk_size) && HSS_PMP_CheckRead(activeHart, (ptrdiff_t)pBlockDesc->src_phys_addr, chunk_size)) { memcpy_via_pdma(pBlockDesc->dest_phys_addr, pBlockDesc->src_phys_addr, chunk_size); } #endif assert(remaining_in_current_block >= chunk_size); remaining_in_current_block -= chunk_size; if (remaining_in_current_block == 0u) { // finished current block, move to next pBlockDesc++; } } else { pMyMachine->state = SGDMA_IDLE; pBlockDesc = NULL; activeHart = HSS_HART_E51; // set to signify no U54 active... } } enum IPIStatusCode HSS_SGDMA_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { (void)transaction_id; (void)immediate_arg; (void)p_ancilliary_buffer_in_ddr; // scatter gather DMA IPI received from one of the U54s... mHSS_DEBUG_PRINTF(LOG_NORMAL, "called (sgdma_service.state is %u)\n", sgdma_service.state); // the following should always be true if we have consumed intents for SGDMA... assert(p_extended_buffer_in_ddr != NULL); assert(sgdma_service.state == SGDMA_IDLE); // setup the transfer -- the state machine will execute it in chunks pBlockDesc = (struct HSS_SGDMA_BlockDesc *)p_extended_buffer_in_ddr; activeHart = source; sgdma_service.state = SGDMA_TRANSFERRING; return IPI_SUCCESS; } hart-software-services-2022.10/services/sgdma/sgdma_service.h000066400000000000000000000035041432224323300241710ustar00rootroot00000000000000#ifndef HSS_SGDMA_SERVICE_H #define HSS_SGDMA_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Virtual SGDMA Service API * */ /*! * \file Virtual SGDMA API * \brief SGDMA Driver State Machine API function declarations */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" #include "sgdma_types.h" enum IPIStatusCode HSS_SGDMA_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); extern struct StateMachine sgdma_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/sgdma/sgdma_types.h000066400000000000000000000033131432224323300236730ustar00rootroot00000000000000#ifndef HSS_SGDMA_TYPES_H #define HSS_SGDMA_TYPES_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Virtual SGDMA Types * */ /*! * \file Virtual SGDMA Types * \brief SGDMA Driver Type Definitions */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" struct HSS_SGDMA_BlockDesc { void * src_phys_addr; void * dest_phys_addr; size_t size; unsigned int reserved:31; unsigned int ext:1; }; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/spi/000077500000000000000000000000001432224323300207035ustar00rootroot00000000000000hart-software-services-2022.10/services/spi/Kconfig000066400000000000000000000004161432224323300222070ustar00rootroot00000000000000config SERVICE_SPI bool "Boot from System Controller SPI flash support" default n help This feature enables booting from a payload stored in the SPI flash connected to the PolarFire SoC System Controller. If you do not know what to do here, say Y. hart-software-services-2022.10/services/spi/Makefile000066400000000000000000000024131432224323300223430ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Virtual SPI Service SRCS-$(CONFIG_SERVICE_SPI) += \ services/spi/spi_service.c \ INCLUDES +=\ -I./services/spi \ hart-software-services-2022.10/services/spi/spi_service.c000066400000000000000000000051551432224323300233700ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file SPI Driver State Machine * \brief SPI Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" static void spi_init_onEntry(struct StateMachine * const pMyMachine); static void spi_init_onExit(struct StateMachine * const pMyMachine); static void spi_init_handler(struct StateMachine * const pMyMachine); static void spi_lastState_onEntry(struct StateMachine * const pMyMachine); static void spi_lastState_onExit(struct StateMachine * const pMyMachine); static void spi_lastState_handler(struct StateMachine * const pMyMachine); /*! * \brief SPI Driver States * */ enum SpiStatesEnum { SPI_INITIALIZATION, SPI_LAST_STATE, SPI_NUM_STATES = SPI_LAST_STATE+1 }; /*! * \brief SPI Driver State Descriptors * */ static const struct StateDesc spi_state_descs[] = { { (const stateType_t)SPI_INITIALIZATION, (const char *)"init", &spi_init_onEntry, &spi_init_onExit, &spi_init_handler }, { (const stateType_t)SPI_LAST_STATE, (const char *)"lastState", &spi_lastState_onEntry, &spi_lastState_onExit, &spi_lastState_handler } }; /*! * \brief SPI Driver State Machine * */ struct StateMachine spi_service = { .state = (stateType_t)SPI_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)SPI_NUM_STATES, .pMachineName = (const char *)"spi_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = spi_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void spi_init_onEntry(struct StateMachine * const pMyMachine) { (void)pMyMachine; } static void spi_init_onExit(struct StateMachine * const pMyMachine) { (void)pMyMachine; } static void spi_init_handler(struct StateMachine * const pMyMachine) { } ///////////////// static void spi_lastState_onEntry(struct StateMachine * const pMyMachine) { (void)pMyMachine; } static void spi_lastState_onExit(struct StateMachine * const pMyMachine) { (void)pMyMachine; } static void spi_lastState_handler(struct StateMachine * const pMyMachine) { pMyMachine->state = SPI_INITIALIZATION; } hart-software-services-2022.10/services/spi/spi_service.h000066400000000000000000000031241432224323300233670ustar00rootroot00000000000000#ifndef SPI_SERVICE_H #define SPI_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - SPI Service * */ /*! * \file SPI Service * \brief State Machine and API functions for SPI firmware service * */ #ifdef __cplusplus extern "C" { #endif #include "ssmb_ipi.h" #include "hss_types.h" extern struct StateMachine spi_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/tinycli/000077500000000000000000000000001432224323300215635ustar00rootroot00000000000000hart-software-services-2022.10/services/tinycli/Kconfig000066400000000000000000000032671432224323300230760ustar00rootroot00000000000000config SERVICE_TINYCLI bool "TinyCLI support" default n help This feature enables a simple command-line interpreter prompt. If you do not know what to do here, say N. menu "Tiny Command Line Interface" visible if SERVICE_TINYCLI config SERVICE_TINYCLI_TIMEOUT depends on SERVICE_TINYCLI int "Timeout for entering TinyCLI (in seconds)" default 5 help The timeout for entering the TinyCLI (in seconds). When CONFIG_TINYCLI is enabled, the HSS will wait for a keypress for this timeout before continuing with its boot process. If a key press (other than ESC) is detected, the HSS will enter the TINYCLI mode, which allows interactive running of a small number of commands. Typing `HELP` at the TINYCLI prompt lists the supported commands. config SERVICE_TINYCLI_REGISTER depends on SERVICE_TINYCLI bool "Register TinyCLI as a state machine" default n help This feature enables the TinyCLI command-line interpreter to be registered as a state machine, which makes it available at all times via the E51. If you select this, you will not be able to configure UART_SURRENDER, which allows the HSS to surrender use of MMUART0 post-boot. If you do not know what to do here, say N. config SERVICE_TINYCLI_MONITOR depends on SERVICE_TINYCLI && SERVICE_TINYCLI_REGISTER bool "Enable periodic monitoring of memory" default n help This feature enables the creation of a number of monitor tasks which can be configured to dump the contents of blocks of memory to the E51 console periodically. If you do not know what to do here, say N. endmenu hart-software-services-2022.10/services/tinycli/Makefile000066400000000000000000000027241432224323300232300ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # TINYCLI service SRCS-$(CONFIG_SERVICE_TINYCLI) += \ services/tinycli/tinycli_api.c \ services/tinycli/tinycli_service.c \ services/tinycli/tinycli_hexdump.c \ INCLUDES +=\ -I./services/tinycli \ services/tinycli/tinycli_api.o: CFLAGS=$(CFLAGS_GCCEXT) services/tinycli/tinycli_service.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/tinycli/tinycli_api.c000066400000000000000000001010601432224323300242310ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Tiny CLI parser * \brief Tiny CLI parser */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" //#include // tolower() #include // strcasecmp(), strtok(), strtok_r() #include #include #include "hss_boot_init.h" #include "gpt.h" #include "hss_init.h" #include "hss_state_machine.h" #include "tinycli_service.h" #include "tinycli_hexdump.h" #include "hss_memtest.h" #include "hss_progress.h" #include "hss_version.h" #include "hss_crc32.h" #include "uart_helper.h" #include "ddr_service.h" #include "csr_helper.h" #include "wdog_service.h" #include "hss_perfctr.h" #include "u54_state.h" #include "hss_registry.h" #include "assert.h" #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) # include "usbdmsc_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI) # include "qspi_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_SCRUB) # include "scrub_service.h" #endif #if IS_ENABLED(CONFIG_SERVICE_BEU) # include "beu_service.h" #endif #if IS_ENABLED(CONFIG_CRYPTO_SIGNING) # include "hss_boot_secure.h" #endif #define mMAX_NUM_TOKENS 40 static size_t argc_tokenCount = 0u; static char *argv_tokenArray[mMAX_NUM_TOKENS]; static bool quitFlag = false; #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) # define mNUM_MONITORS 10 struct tinycli_monitor { bool active; bool allocated; HSSTicks_t time; size_t interval_sec; uintptr_t startAddr; size_t count; } monitors[mNUM_MONITORS]; #endif enum CmdId { CMD_YMODEM, CMD_QUIT, CMD_BOOT, CMD_RESET, CMD_HELP, CMD_VERSION, CMD_UPTIME, CMD_DEBUG, #if IS_ENABLED(CONFIG_MEMTEST) CMD_MEMTEST, #endif CMD_QSPI, CMD_EMMC, CMD_MMC, #if IS_ENABLED(CONFIG_SERVICE_PAYLOAD) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI) || IS_ENABLED(CONFIG_SERVICE_SPI)) CMD_PAYLOAD, #endif CMD_SPI, #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) CMD_USBDMSC, #endif #if IS_ENABLED(CONFIG_SERVICE_SCRUB) CMD_SCRUB, #endif CMD_INVALID }; struct tinycli_key { const int tokenId; const char * const name; const char * const helpString; }; const struct tinycli_key cmdKeys[] = { #if IS_ENABLED(CONFIG_SERVICE_YMODEM) { CMD_YMODEM, "YMODEM", "Run YMODEM utility to download an image to DDR." }, #endif { CMD_QUIT, "QUIT", "Quit TinyCLI and return to regular boot process." }, { CMD_BOOT, "BOOT", "Quit TinyCLI and return to regular boot process." }, { CMD_RESET, "RESET", "Reset the E51." }, { CMD_HELP, "HELP", "Display command summary / command help information." }, { CMD_VERSION, "VERSION", "Display system version information." }, { CMD_UPTIME, "UPTIME", "Display uptime information." }, { CMD_DEBUG, "DEBUG", "Display debug information." }, #if IS_ENABLED(CONFIG_MEMTEST) { CMD_MEMTEST, "MEMTEST", "Full DDR memory test." }, #endif { CMD_QSPI, "QSPI", "Select boot via QSPI." }, { CMD_EMMC, "EMMC", "Select boot via MMC." }, { CMD_MMC, "MMC", "Select boot via MMC." }, #if IS_ENABLED(CONFIG_SERVICE_PAYLOAD) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) { CMD_PAYLOAD, "PAYLOAD", "Select boot via payload." }, #endif #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) { CMD_USBDMSC, "USBDMSC", "Export eMMC as USBD Mass Storage Class." }, #endif { CMD_SPI, "SPI", "Select boot via SPI." }, #if IS_ENABLED(CONFIG_SERVICE_SCRUB) { CMD_SCRUB, "SCRUB", "Dump Scrub service stats." }, #endif }; static void tinyCLI_CmdHandler_(int tokenId); static bool tinyCLI_NameToKeyIndex_(struct tinycli_key const * const keys, size_t numKeys, char const * const pToken, size_t *pIndex); static bool tinyCLI_CmdIdToCommandIndex_(enum CmdId tokenId, size_t * pIndex); static void tinyCLI_PrintVersion_(void); static void tinyCLI_PrintUptime_(void); static void tinyCLI_PrintHelp_(void); static void tinyCLI_Debug_(void); static void tinyCLI_Reset_(void); #if IS_ENABLED(CONFIG_SERVICE_MMC) && IS_ENABLED(CONFIG_SERVICE_BOOT) static void tinyCLI_Boot_List_(void); static void tinyCLI_Boot_Select_(void); #endif static bool tinyCLI_Boot_(void); #if IS_ENABLED(CONFIG_SERVICE_QSPI) static bool tinyCLI_QSPI_Scan_(void); static bool tinyCLI_QSPI_Erase_(void); static bool tinyCLI_QSPI_(void); #endif #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) static void tinyCLI_Monitor_(void); #endif static void tinyCLI_CRC32_(void); static void tinyCLI_HexDump_(void); #if IS_ENABLED(CONFIG_MEMTEST) static void tinyCLI_MemTest_(void); #endif struct tinycli_command { const enum CmdId tokenId; bool warnIfPostInit; void (* const handler)(int); }; static struct tinycli_command commands[] = { #if IS_ENABLED(CONFIG_SERVICE_YMODEM) { CMD_YMODEM, true, tinyCLI_CmdHandler_ }, #endif { CMD_QUIT, true, tinyCLI_CmdHandler_ }, { CMD_BOOT, true, tinyCLI_CmdHandler_ }, { CMD_RESET, true, tinyCLI_CmdHandler_ }, { CMD_HELP, false, tinyCLI_CmdHandler_ }, { CMD_VERSION, false, tinyCLI_CmdHandler_ }, { CMD_UPTIME, false, tinyCLI_CmdHandler_ }, { CMD_DEBUG, false, tinyCLI_CmdHandler_ }, #if IS_ENABLED(CONFIG_MEMTEST) { CMD_MEMTEST, true, tinyCLI_CmdHandler_ }, #endif { CMD_QSPI, true, tinyCLI_CmdHandler_ }, { CMD_EMMC, true, tinyCLI_CmdHandler_ }, { CMD_MMC, true, tinyCLI_CmdHandler_ }, #if IS_ENABLED(CONFIG_SERVICE_PAYLOAD) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI) || IS_ENABLED(CONFIG_SERVICE_SPI)) { CMD_PAYLOAD, true, tinyCLI_CmdHandler_ }, #endif { CMD_SPI, true, tinyCLI_CmdHandler_ }, #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) { CMD_USBDMSC, true, tinyCLI_CmdHandler_ }, #endif #if IS_ENABLED(CONFIG_SERVICE_SCRUB) { CMD_SCRUB, false, tinyCLI_CmdHandler_ }, #endif }; static bool postInit = false; /***********************************************************************/ static bool tinyCLI_NameToKeyIndex_(struct tinycli_key const * const keys, size_t numKeys, char const * const pToken, size_t *pIndex) { bool result = false; size_t i; assert(keys); assert(pToken); assert(pIndex); for (i = 0u; i < numKeys; i++) { // check for full match if (strncasecmp(keys[i].name, pToken, strlen(keys[i].name)) == 0) { result = true; *pIndex = i; break; } } if (!result) { // if no match found, check for partial match size_t count = 0u; for (i = 0u; i < numKeys; i++) { if (strncasecmp(keys[i].name, pToken, strlen(pToken)) == 0) { *pIndex = i; count++; } } if (count == 1u) { result = true; // multiple matches => ambiguity } } return result; } static bool tinyCLI_CmdIdToCommandIndex_(enum CmdId tokenId, size_t * pIndex) { bool result = false; size_t i; for (i = 0; i < ARRAY_SIZE(commands); i++) { if (commands[i].tokenId == tokenId) { result = true; *pIndex = i; break; } } return result; } static unsigned long int tinyCLI_strtoul_wrapper_(const char *__restrict nptr) { int base = 10; int tolower(int __c); // normally in ctypes.h, but we don't have a _ctype_ defined if ((nptr[0] == '0') && (tolower((int)nptr[1]) == 'x')) { base = 16; } return strtoul(nptr, NULL, base); } static void tinyCLI_PrintUptime_(void) { HSSTicks_t timeVal = CSR_GetTime(); timeVal /= 1000000lu; uint32_t days = timeVal / (24lu * 3600lu); timeVal = timeVal - (days * (24 * 3600lu)); uint32_t hours = timeVal / 3600lu; timeVal = timeVal - (hours * 3600lu); uint32_t mins = timeVal / 60lu; uint32_t secs = timeVal - (mins * 60lu); mHSS_FANCY_PRINTF(LOG_STATUS, "Uptime is "); if (days) { mHSS_FANCY_PRINTF_EX("%lu day%s, ", days, days == 1lu ? "":"s"); } if (hours) { mHSS_FANCY_PRINTF_EX("%lu hour%s, ", hours, hours == 1lu ? "":"s"); } if (mins) { mHSS_FANCY_PRINTF_EX("%lu minute%s, ", mins, mins == 1lu ? "":"s"); } mHSS_FANCY_PRINTF_EX("%lu second%s", secs, secs == 1lu ? "":"s"); } static void tinyCLI_PrintVersion_(void) { (void)HSS_E51_Banner(); } #if IS_ENABLED(CONFIG_MEMTEST) static void tinyCLI_MemTest_(void) { bool status = false; if (argc_tokenCount > 1u) { size_t count = 256u; const uintptr_t startAddr = tinyCLI_strtoul_wrapper_(argv_tokenArray[1]); if (argc_tokenCount > 2u) { count = tinyCLI_strtoul_wrapper_(argv_tokenArray[2]); } status = HSS_MemTestDDR_Ex((uint64_t *)startAddr, count); } else { status = HSS_MemTestDDRFull(); } if (!status) { mHSS_FANCY_PRINTF(LOG_ERROR, "Failed!\n"); } else { mHSS_FANCY_PRINTF(LOG_STATUS, "Passed!\n"); } } #endif static void tinyCLI_PrintHelp_(void) { if (argc_tokenCount > 1u) { for (size_t i = 1u; i < argc_tokenCount; ++i) { size_t index; if (tinyCLI_NameToKeyIndex_(cmdKeys, ARRAY_SIZE(cmdKeys), argv_tokenArray[i], &index)) { mHSS_FANCY_PRINTF(LOG_NORMAL, "%s: %s\n", cmdKeys[index].name, cmdKeys[index].helpString); } } } else { mHSS_PUTS("Supported Commands:\n\t"); for (size_t i = 0u; i < ARRAY_SIZE(cmdKeys); i++) { size_t index = CMD_INVALID; if (tinyCLI_CmdIdToCommandIndex_(cmdKeys[i].tokenId, &index) && (commands[index].warnIfPostInit)) { HSS_Debug_Highlight(HSS_DEBUG_LOG_WARN); } mHSS_PUTS(cmdKeys[i].name); if ((index != CMD_INVALID) && (commands[index].warnIfPostInit)) { HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); } mHSS_PUTC(' '); } mHSS_PUTS("\n"); } } static void tinyCLI_Reset_(void) { #if IS_ENABLED(CONFIG_SERVICE_WDOG) HSS_Wdog_Reboot(HSS_HART_ALL); #endif } static void tinyCLI_Seg_(void) { (void)HSS_DDRPrintSegConfig(); } static void tinyCLI_OpenSBI_(void) { extern void sbi_domain_dump_all(char const * const suffix); sbi_domain_dump_all(" "); HSS_U54_DumpStates(); } static void tinyCLI_L2Cache_(void) { (void)HSS_DDRPrintL2CacheWaysConfig(); (void)HSS_DDRPrintL2CacheWayMasks(); } #if IS_ENABLED(CONFIG_SERVICE_BEU) static void tinyCLI_BEU_(void) { HSS_BEU_DumpStats(); } #endif #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) static void tinyCLI_PerfCtrs_(void) { HSS_PerfCtr_DumpAll(); } #endif static void tinyCLI_Debug_(void) { bool usageError = false; enum DebugKey { #if IS_ENABLED(CONFIG_SERVICE_BEU) DBG_BEU, #endif DBG_SM, DBG_IPI, DBG_CRC32, DBG_HEXDUMP, #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) DBG_MONITOR, #endif DBG_OPENSBI, DBG_SEG, DBG_L2CACHE, #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) DBG_PERFCTR, #endif DBG_WDOG, }; const struct tinycli_key debugKeys[] = { #if IS_ENABLED(CONFIG_SERVICE_BEU) { DBG_BEU, "BEU", "debug Bus Error Unit monitor" }, #endif { DBG_SM, "SM", "debug state machines" }, { DBG_IPI, "IPI", "debug HSS IPI Queues" }, { DBG_CRC32, "CRC32", "calculate CRC32 over memory region" }, { DBG_HEXDUMP, "HEXDUMP", "display memory as hex dump" }, #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) { DBG_MONITOR, "MONITOR", "monitor memory locations periodically" }, #endif { DBG_OPENSBI, "OPENSBI", "debug OpenSBI state" }, { DBG_SEG, "SEG", "display seg registers" }, { DBG_L2CACHE, "L2CACHE", "display l2cache settings" }, #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) { DBG_PERFCTR , "PERFCTR", "display perf counters" }, #endif { DBG_WDOG , "WDOG", "display watchdog statistics" }, }; size_t keyIndex; if ((argc_tokenCount > 1u) && (tinyCLI_NameToKeyIndex_(debugKeys, ARRAY_SIZE(debugKeys), argv_tokenArray[1], &keyIndex))) { switch (keyIndex) { #if IS_ENABLED(CONFIG_SERVICE_BEU) case DBG_BEU: tinyCLI_BEU_(); break; #endif case DBG_SM: DumpStateMachineStats(); break; case DBG_IPI: IPI_DebugDumpStats(); break; case DBG_CRC32: tinyCLI_CRC32_(); break; #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) case DBG_MONITOR: tinyCLI_Monitor_(); break; #endif case DBG_OPENSBI: tinyCLI_OpenSBI_(); break; case DBG_HEXDUMP: tinyCLI_HexDump_(); break; case DBG_SEG: tinyCLI_Seg_(); break; case DBG_L2CACHE: tinyCLI_L2Cache_(); break; #if IS_ENABLED(CONFIG_DEBUG_PERF_CTRS) case DBG_PERFCTR: tinyCLI_PerfCtrs_(); break; #endif case DBG_WDOG: #if IS_ENABLED(CONFIG_SERVICE_WDOG) HSS_Wdog_DumpStats(); #endif break; default: usageError = true; break; } } else { usageError = true; } if (usageError) { mHSS_PUTS("Supported options:\n"); for (size_t i = 0u; i < ARRAY_SIZE(debugKeys); i++) { mHSS_PRINTF("\t%s - %s\n", debugKeys[i].name, debugKeys[i].helpString); } } } #if IS_ENABLED(CONFIG_SERVICE_MMC) && IS_ENABLED(CONFIG_SERVICE_BOOT) extern struct HSS_Storage *HSS_BootGetActiveStorage(void); #endif extern struct HSS_BootImage *pBootImage; static void tinyCLI_Boot_Info_(void) { if ((pBootImage->magic == mHSS_BOOT_MAGIC) || (pBootImage->magic == mHSS_COMPRESSED_MAGIC)) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Set Name: %s\n", pBootImage->set_name); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Length: %" PRIu64 " bytes\n", pBootImage->bootImageLength); #if IS_ENABLED(CONFIG_CRYPTO_SIGNING) mHSS_DEBUG_PRINTF(LOG_ERROR, "Boot Image %s code signing\n", HSS_Boot_Secure_CheckCodeSigning(pBootImage) ? "passed" : "failed"); #endif } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Valid boot image not registered\n"); } } #if IS_ENABLED(CONFIG_SERVICE_MMC) static void tinyCLI_Boot_List_(void) { HSS_GPT_t gpt; if (IS_ENABLED(CONFIG_SERVICE_MMC) && IS_ENABLED(CONFIG_SERVICE_BOOT_MMC_USE_GPT)) { struct HSS_Storage *pStorage = HSS_BootGetActiveStorage(); assert(pStorage); uint32_t blockSize, eraseSize, blockCount; pStorage->getInfo(&blockSize, &eraseSize, &blockCount); gpt.lbaSize = blockSize; GPT_Init(&gpt, pStorage); bool result = GPT_ReadHeader(&gpt); if (result) { size_t srcIndex = 0u; HSS_GPT_PartitionEntry_t const * pGptPartitionEntry; result = GPT_FindBootSectorIndex(&gpt, &srcIndex, &pGptPartitionEntry); do { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Boot Partition found at index %lu\n", srcIndex); if (!result) { mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT_FindBootSectorIndex() failed\n"); } else { struct HSS_BootImage localBootImage; size_t srcLBAOffset; result = GPT_PartitionIdToLBAOffset(&gpt, srcIndex, &srcLBAOffset); if (!result) { //mHSS_DEBUG_PRINTF(LOG_ERROR, "GPT_PartitionIdToLBAOffset() failed\n"); } else { result = HSS_MMC_ReadBlock(&localBootImage, srcLBAOffset * gpt.lbaSize, sizeof(struct HSS_BootImage)); } if (!result) { //mHSS_DEBUG_PRINTF(LOG_ERROR, "HSS_MMC_ReadBlock() failed\n"); } else { if ((localBootImage.magic == mHSS_BOOT_MAGIC) || (localBootImage.magic == mHSS_COMPRESSED_MAGIC)) { mHSS_DEBUG_PRINTF(LOG_NORMAL, ">>%s<<\n", localBootImage.set_name); } else { //mHSS_DEBUG_PRINTF(LOG_ERROR, "magic failed\n"); } } } srcIndex++; result = GPT_FindBootSectorIndex(&gpt, &srcIndex, &pGptPartitionEntry); } while (result); } } } static void tinyCLI_Boot_Select_(void) { HSS_GPT_t gpt; if (argc_tokenCount > 2u) { size_t index = tinyCLI_strtoul_wrapper_(argv_tokenArray[2]); GPT_SetBootPartitionIndex(&gpt, index); } else { mHSS_PUTS("Usage:\n" "\tboot select \n" "\n"); } } #endif static bool tinyCLI_Boot_(void) { bool result = false; bool usageError = false; enum BootKey { BOOT_INFO, BOOT_LIST, BOOT_SELECT }; const struct tinycli_key bootKeys[] = { { BOOT_INFO, "INFO", "display info about currently registered boot image" }, { BOOT_LIST, "LIST", "list boot partitions" }, { BOOT_SELECT, "SELECT", "select active boot partition" }, }; size_t keyIndex; if (argc_tokenCount > 1u) { if (tinyCLI_NameToKeyIndex_(bootKeys, ARRAY_SIZE(bootKeys), argv_tokenArray[1], &keyIndex)) { switch (keyIndex) { case BOOT_INFO: tinyCLI_Boot_Info_(); break; #if IS_ENABLED(CONFIG_SERVICE_MMC) case BOOT_LIST: tinyCLI_Boot_List_(); break; case BOOT_SELECT: tinyCLI_Boot_Select_(); break; #endif default: usageError = true; break; } } else { usageError = true; } } else { result = true; // boot on its own } if (usageError) { mHSS_PUTS("Supported options:\n"); for (size_t i = 0u; i < ARRAY_SIZE(bootKeys); i++) { mHSS_PRINTF("\t%s - %s\n", bootKeys[i].name, bootKeys[i].helpString); } } return result; } #if IS_ENABLED(CONFIG_SERVICE_QSPI) extern uint32_t Flash_scan_for_bad_blocks(uint16_t* buf); extern void Flash_add_entry_to_bb_lut(uint16_t lba, uint16_t pba); static bool tinyCLI_QSPI_Erase_(void) { bool result = false; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Erasing QSPI Flash\n"); HSS_QSPIInit(); HSS_QSPI_FlashChipErase(); return result; } static bool tinyCLI_QSPI_Scan_(void) { bool result = false; HSS_QSPIInit(); HSS_QSPI_BadBlocksInfo(); return result; } static bool tinyCLI_QSPI_(void) { bool result = false; bool usageError = false; enum qspiKey { QSPI_ERASE, QSPI_SCAN, }; const struct tinycli_key qspiKeys[] = { { QSPI_ERASE, "ERASE", "ERASE QSPI Flash" }, { QSPI_SCAN, "SCAN", "Scan QSPI Flash for bad blocks" }, }; size_t keyIndex; if (argc_tokenCount > 1u) { if (tinyCLI_NameToKeyIndex_(qspiKeys, ARRAY_SIZE(qspiKeys), argv_tokenArray[1], &keyIndex)) { switch (keyIndex) { case QSPI_ERASE: tinyCLI_QSPI_Erase_(); break; case QSPI_SCAN: tinyCLI_QSPI_Scan_(); break; default: usageError = true; break; } } else { usageError = true; } } else { HSS_BootSelectQSPI(); result = true; // qspi on its own } if (usageError) { mHSS_PUTS("Supported options:\n"); for (size_t i = 0u; i < ARRAY_SIZE(qspiKeys); i++) { mHSS_PRINTF("\t%s - %s\n", qspiKeys[i].name, qspiKeys[i].helpString); } } return result; } #endif #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) static void tinyCLI_Monitor_(void) { bool usageError = false; enum MonitorKey { MONITOR_CREATE, MONITOR_DESTROY, MONITOR_ENABLE, MONITOR_DISABLE, MONITOR_LIST, }; const struct tinycli_key monitorKeys[] = { { MONITOR_CREATE, "CREATE", " 0x 0x" }, { MONITOR_DESTROY, "DESTROY", " " }, { MONITOR_ENABLE, "ENABLE", " " }, { MONITOR_DISABLE, "DISABLE", " " }, { MONITOR_LIST, "LIST", "" }, }; size_t keyIndex; if ((argc_tokenCount > 2) && (tinyCLI_NameToKeyIndex_(monitorKeys, ARRAY_SIZE(monitorKeys), argv_tokenArray[2], &keyIndex))) { switch (keyIndex) { case MONITOR_CREATE: if (argc_tokenCount > 5u) { size_t index; for (index = 0u; index < ARRAY_SIZE(monitors); index++) { if (!monitors[index].allocated) { break; } } if (index < ARRAY_SIZE(monitors)) { monitors[index].allocated = true; monitors[index].active = false; monitors[index].interval_sec = tinyCLI_strtoul_wrapper_(argv_tokenArray[3]); monitors[index].startAddr = tinyCLI_strtoul_wrapper_(argv_tokenArray[4]); monitors[index].count = tinyCLI_strtoul_wrapper_(argv_tokenArray[5]); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Allocated monitor index %lu\n", index); } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "All monitors are allocated\n"); } } else { usageError = true; } break; case MONITOR_DESTROY: if (argc_tokenCount > 3u) { size_t index = tinyCLI_strtoul_wrapper_(argv_tokenArray[3]); if (index < ARRAY_SIZE(monitors)) { if (monitors[index].allocated) { monitors[index].allocated = false; monitors[index].active = false; monitors[index].interval_sec = 0u; monitors[index].startAddr = 0u; monitors[index].count = 0u; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Destroyed monitor index %lu\n", index); } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "Monitor index %lu not allocated\n", index); } } else { usageError = true; } } else { usageError = true; } break; case MONITOR_ENABLE: if (argc_tokenCount > 3u) { size_t index = tinyCLI_strtoul_wrapper_(argv_tokenArray[3]); if (index < ARRAY_SIZE(monitors)) { if (monitors[index].allocated) { monitors[index].active = monitors[index].allocated; monitors[index].time = HSS_GetTime(); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Enabled monitor index %lu\n", index); } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "Monitor index %lu not allocated\n", index); } } else { usageError = true; } } else { usageError = true; } break; case MONITOR_DISABLE: if (argc_tokenCount > 3u) { size_t index = tinyCLI_strtoul_wrapper_(argv_tokenArray[3]); if (index < ARRAY_SIZE(monitors)) { if (monitors[index].allocated) { monitors[index].active = false; mHSS_DEBUG_PRINTF(LOG_NORMAL, "Disabled monitor index %lu\n", index); } else { mHSS_DEBUG_PRINTF(LOG_ERROR, "Monitor index %lu not allocated\n", index); } } else { usageError = true; } } else { usageError = true; } break; case MONITOR_LIST: mHSS_PUTS(" Index Active Allocated Interval Start_Addr Count\n" "===========================================================\n"); for (size_t index = 0; index < ARRAY_SIZE(monitors); ++index) { mHSS_PRINTF(" % 5lu % 6d % 9d % 8lu %16x %8x\n", index, monitors[index].active, monitors[index].allocated, monitors[index].interval_sec, monitors[index].startAddr, monitors[index].count); } break; default: usageError = true; break; } } else { usageError = true; } if (usageError) { mHSS_PUTS("Usage:\n"); for (size_t i = 0u; i < ARRAY_SIZE(monitorKeys); i++) { mHSS_PRINTF("\tDEBUG MONITOR %s - %s\n", monitorKeys[i].name, monitorKeys[i].helpString); } } } #endif static void tinyCLI_CRC32_(void) { if (argc_tokenCount > 2u) { size_t count = 256u; const uintptr_t startAddr = tinyCLI_strtoul_wrapper_(argv_tokenArray[2]); if (argc_tokenCount > 3u) { count = tinyCLI_strtoul_wrapper_(argv_tokenArray[3]); } uint32_t result = CRC32_calculate((const uint8_t *)startAddr, count); mHSS_PRINTF("CRC32: 0x%x\n", result); } else { mHSS_PUTS("Usage:\n" "\tcrc32 0x 0x\n" "\n"); } } static void tinyCLI_HexDump_(void) { static size_t hexdump_count = 256u; static uintptr_t hexdump_startAddr = 0u; if (argc_tokenCount == 2u) { // repeating hexdump command with no args => keep going with // same count if (hexdump_startAddr == 0u) { hexdump_startAddr = (const uintptr_t)HSS_DDR_GetStart() - hexdump_count; }; hexdump_startAddr = hexdump_startAddr + hexdump_count; HSS_TinyCLI_HexDump((uint8_t *)hexdump_startAddr, hexdump_count); } else if (argc_tokenCount > 2u) { hexdump_startAddr = tinyCLI_strtoul_wrapper_(argv_tokenArray[2]); if (argc_tokenCount > 3u) { hexdump_count = tinyCLI_strtoul_wrapper_(argv_tokenArray[3]); } HSS_TinyCLI_HexDump((uint8_t *)hexdump_startAddr, hexdump_count); } else { mHSS_PUTS("Usage:\n" "\thexdump 0x 0x\n" "\n"); } } static void tinyCLI_UnsupportedBootMechanism_(char const * const pName) { mHSS_PUTS(pName); mHSS_PUTS(" not supported in this build of the HSS.\n" "Supported boot mechanisms:\n"); HSS_BootListStorageProviders(); } static void tinyCLI_CmdHandler_(int tokenId) { #if IS_ENABLED(CONFIG_SERVICE_YMODEM) void hss_loader_ymodem_loop(void); #endif void _start(void); size_t index; switch (tokenId) { case CMD_HELP: tinyCLI_PrintHelp_(); break; case CMD_VERSION: tinyCLI_PrintVersion_(); break; case CMD_UPTIME: tinyCLI_PrintUptime_(); break; case CMD_DEBUG: tinyCLI_Debug_(); break; #if IS_ENABLED(CONFIG_SERVICE_YMODEM) case CMD_YMODEM: hss_loader_ymodem_loop(); break; #endif case CMD_RESET: tinyCLI_Reset_(); break; case CMD_QUIT: quitFlag = true; break; case CMD_BOOT: quitFlag = tinyCLI_Boot_(); break; #if IS_ENABLED(CONFIG_MEMTEST) case CMD_MEMTEST: tinyCLI_MemTest_(); break; #endif case CMD_QSPI: #if IS_ENABLED(CONFIG_SERVICE_QSPI) tinyCLI_QSPI_(); #else tinyCLI_UnsupportedBootMechanism_("QSPI"); #endif break; case CMD_EMMC: __attribute__((fallthrough)); // deliberate fallthrough case CMD_MMC: #if IS_ENABLED(CONFIG_SERVICE_MMC) HSS_BootSelectMMC(); #else tinyCLI_UnsupportedBootMechanism_("eMMC/SDCard"); #endif break; #if IS_ENABLED(CONFIG_SERVICE_PAYLOAD) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI) || IS_ENABLED(CONFIG_SERVICE_SPI)) case CMD_PAYLOAD: HSS_BootSelectPayload(); break; #endif case CMD_SPI: #if defined(CONFIG_SERVICE_SPI) HSS_BootSelectSPI(); #else tinyCLI_UnsupportedBootMechanism_("SPI"); #endif break; #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) case CMD_USBDMSC: { USBDMSC_Init(); USBDMSC_Start(); HSS_TinyCLI_WaitForUSBMSCDDone(); } break; #endif #if IS_ENABLED(CONFIG_SERVICE_SCRUB) case CMD_SCRUB: scrub_dump_stats(); break; #endif default: mHSS_DEBUG_PRINTF(LOG_NORMAL, "Unknown command %d (%lu tokens)\n", tokenId, argc_tokenCount); for (index = 1u; index < argc_tokenCount; index++) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Argument: %s\n", argv_tokenArray[index]); } break; } mHSS_PUTS("\n"); } #if !IS_ENABLED(CONFIG_SERVICE_TINYCLI_REGISTER) static bool tinyCLI_Getline_(char **pBuffer, size_t *pBufLen); static bool tinyCLI_Getline_(char **pBuffer, size_t *pBufLen) { bool result = false; ssize_t status = 0; status = uart_getline(pBuffer, pBufLen); if (status < 0) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Problem reading input\n"); } else { result = true; } return result; } #endif size_t HSS_TinyCLI_ParseIntoTokens(char *pBuffer) { size_t i = 0u; static char *strtok_string = NULL; char *pToken = strtok_r(pBuffer, "\n ", &strtok_string); while ((pToken != NULL) && (i < mMAX_NUM_TOKENS)) { argv_tokenArray[i] = pToken; i++; pToken = strtok_r(NULL, "\n ", &strtok_string); } argc_tokenCount = i; return i; } void HSS_TinyCLI_Execute(void) { size_t keyIndex, cmdIndex; bool matchFoundFlag = tinyCLI_NameToKeyIndex_(cmdKeys, ARRAY_SIZE(cmdKeys), argv_tokenArray[0], &keyIndex) && tinyCLI_CmdIdToCommandIndex_(cmdKeys[keyIndex].tokenId, &cmdIndex); if (matchFoundFlag) { if (commands[cmdIndex].warnIfPostInit && postInit) { mHSS_DEBUG_PRINTF(LOG_WARN, "Command %s may cause problems post boot.\n" "Please type it again if you definitely want to execute it" "\n\n", cmdKeys[keyIndex].name); commands[cmdIndex].warnIfPostInit = false; } else { commands[cmdIndex].handler(commands[cmdIndex].tokenId); } } else { mHSS_DEBUG_PRINTF(LOG_NORMAL, "Unknown command >>%s<<.\n\n", argv_tokenArray[0]); } } bool HSS_TinyCLI_IndicatePostInit(void) { postInit = true; return postInit; } bool HSS_TinyCLI_Parser(void) { bool keyPressedFlag = false; uint8_t rcv_buf; keyPressedFlag = HSS_ShowTimeout("Press a key to enter CLI, ESC to skip\n", CONFIG_SERVICE_TINYCLI_TIMEOUT, &rcv_buf); if (!keyPressedFlag) { mHSS_FANCY_PUTS(LOG_NORMAL, "CLI boot interrupt timeout\n"); } else { mHSS_FANCY_PUTS(LOG_NORMAL, "Type HELP for list of commands\n"); while (!quitFlag) { #if !IS_ENABLED(CONFIG_SERVICE_TINYCLI_REGISTER) static char *pBuffer = NULL; static size_t bufLen = 0u; mHSS_FANCY_PUTS(LOG_NORMAL, ">> "); bool result = tinyCLI_Getline_(&pBuffer, &bufLen); if (result && (pBuffer != NULL)) { if (HSS_TinyCLI_ParseIntoTokens(pBuffer)) { HSS_TinyCLI_Execute(); } } #else RunStateMachine(&tinycli_service); # if IS_ENABLED(CONFIG_SERVICE_USBDMSC) && (IS_ENABLED(CONFIG_SERVICE_MMC) || IS_ENABLED(CONFIG_SERVICE_QSPI)) RunStateMachine(&usbdmsc_service); # endif #endif } } return true; } #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) void HSS_TinyCLI_RunMonitors(void) { size_t i; for (i = 0u; i < ARRAY_SIZE(monitors); ++i) { if (monitors[i].active && HSS_Timer_IsElapsed(monitors[i].time, monitors[i].interval_sec * ONE_SEC)) { mHSS_DEBUG_PRINTF(LOG_STATUS,": "); HSS_TinyCLI_HexDump((uint8_t *)monitors[i].startAddr, monitors[i].count); monitors[0].time = HSS_GetTime(); } } } #endif hart-software-services-2022.10/services/tinycli/tinycli_hexdump.c000066400000000000000000000031301432224323300251310ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file Tiny CLI parser * \brief Tiny CLI parser */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "assert.h" #include #define STEP_SIZE 16 void HSS_TinyCLI_HexDump(uint8_t *pStart, ptrdiff_t count); void HSS_TinyCLI_HexDump(uint8_t *pStart, ptrdiff_t count) { if ((!pStart) || (count == 0u)) { return; } for (ptrdiff_t i = 0u; i < count; i+=STEP_SIZE) { mHSS_PRINTF("%08x:%08x ", (uint32_t)(((ptrdiff_t)pStart + i) >> 32), // upper 32-bits of address (uint32_t)(((ptrdiff_t)pStart + i) & ((1lu<<32)-1u))); // lower 32-bits of address for (ptrdiff_t j = 0u; j < STEP_SIZE; j++) { if ((i + j) >= count) { mHSS_PRINTF(" "); } else { mHSS_PRINTF("%02x ", *(pStart + i + j)); if ((j % 4) == 3) { mHSS_PRINTF(" "); } } } mHSS_PRINTF(" "); for (ptrdiff_t j = 0u; j < STEP_SIZE; j++) { if ((i + j) >= count) { mHSS_PRINTF(" "); } else { uint8_t octet = *(pStart + i + j); if ((octet > 31u) && (octet < 128u)) { ; } else { octet = '.'; } mHSS_PRINTF("%c", (char)octet); } } mHSS_PRINTF("\n"); } } hart-software-services-2022.10/services/tinycli/tinycli_hexdump.h000066400000000000000000000027511432224323300251460ustar00rootroot00000000000000#ifndef HSS_TINYCLI_HEXDUMP_H #define HSS_TINYCLI_HEXDUMP_H /******************************************************************************* * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Tiny CLI Parser * */ #ifdef __cplusplus extern "C" { #endif void HSS_TinyCLI_HexDump(uint8_t *pStart, ptrdiff_t count); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/tinycli/tinycli_service.c000066400000000000000000000230531432224323300251250ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file tinycli Driver State Machine * \brief Virtualised tinycli Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_clock.h" #include //memset #include #include "tinycli_service.h" #include "uart_helper.h" #include "mpfs_reg_map.h" #include "hss_boot_service.h" #include "usbdmsc_service.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) # include "usbdmsc_service.h" #endif static void tinycli_init_handler(struct StateMachine * const pMyMachine); static void tinycli_readline_onEntry(struct StateMachine * const pMyMachine); static void tinycli_readline_handler(struct StateMachine * const pMyMachine); static void tinycli_readline_onExit(struct StateMachine * const pMyMachine); static void tinycli_parseline_handler(struct StateMachine * const pMyMachine); static void tinycli_usbdmsc_handler(struct StateMachine * const pMyMachine); static void tinycli_uart_surrender_handler(struct StateMachine * const pMyMachine); /*! * \brief TINYCLI Driver States * */ enum UartStatesEnum { TINYCLI_INITIALIZATION, TINYCLI_READLINE, TINYCLI_PARSELINE, TINYCLI_USBDMSC, TINYCLI_UART_SURRENDER, TINYCLI_NUM_STATES = TINYCLI_UART_SURRENDER+1 }; /*! * \brief TINYCLI Driver State Descriptors * */ static const struct StateDesc tinycli_state_descs[] = { { (const stateType_t)TINYCLI_INITIALIZATION, (const char *)"init", NULL, NULL, &tinycli_init_handler }, { (const stateType_t)TINYCLI_READLINE, (const char *)"readline", &tinycli_readline_onEntry, &tinycli_readline_onExit, &tinycli_readline_handler }, { (const stateType_t)TINYCLI_PARSELINE, (const char *)"parseline", NULL, NULL, &tinycli_parseline_handler }, { (const stateType_t)TINYCLI_USBDMSC, (const char *)"usbdmsc", NULL, NULL, &tinycli_usbdmsc_handler }, { (const stateType_t)TINYCLI_UART_SURRENDER, (const char *)"uart_surrender", NULL, NULL, &tinycli_uart_surrender_handler } }; /*! * \brief TINYCLI Driver State Machine * */ struct StateMachine tinycli_service = { .state = (stateType_t)TINYCLI_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)TINYCLI_NUM_STATES, .pMachineName = (const char *)"tinycli_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = tinycli_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void tinycli_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state = TINYCLI_READLINE; } ///////////////// static char myPrevBuffer[HSS_UART_HELPER_MAX_GETLINE]; static char myBuffer[HSS_UART_HELPER_MAX_GETLINE]; const size_t bufferLen = ARRAY_SIZE(myBuffer)-1; ssize_t readStringLen = 0; ///////////////// const char* lineHeader = ">> "; static void tinycli_readline_onEntry(struct StateMachine * const pMyMachine) { (void)pMyMachine; //myBuffer[0] = '\0'; readStringLen = 0u; mHSS_PUTS(lineHeader); } static void tinycli_readline_handler(struct StateMachine * const pMyMachine) { uint8_t cBuf[1]; #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) HSS_TinyCLI_RunMonitors(); #endif static bool escapeActive = false; if (0 != MSS_UART_get_rx(&g_mss_uart0_lo, cBuf, 1)) { if (escapeActive) { switch (cBuf[0]) { case '[': // consume break; case 'A': // up arrow readStringLen = strlen(myBuffer); MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\r", 1); mHSS_PUTS(lineHeader); if (readStringLen) { memcpy(myBuffer, myPrevBuffer, readStringLen); MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)myBuffer, readStringLen); } else { myBuffer[0] = '\0'; } escapeActive = false; return; case 'B': // down arrow escapeActive = false; return; case 'C': // right arrow escapeActive = false; if (readStringLen < bufferLen) { readStringLen++; if (myBuffer[readStringLen] == 0) { myBuffer[readStringLen] = ' '; } MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[C", 4u); } return; case 'D': // left arrow if (readStringLen) { readStringLen--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[D", 4u); } escapeActive = false; return; default: escapeActive = false; break; } if (escapeActive) { return; } } switch (cBuf[0]) { case '\r': __attribute__((fallthrough)); // deliberate fallthrough case '\n': MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); if (readStringLen < bufferLen) { myBuffer[readStringLen] = '\0'; } if (readStringLen) { memcpy(myPrevBuffer, myBuffer, readStringLen+1); } else { // if just hit enter, as a convenience, reuse last command (a la GDB) //mHSS_DEBUG_PRINTF(LOG_WARN, "Convenience: copying >>%s<< into myBuffer\n", myPrevBuffer); readStringLen = strlen(myPrevBuffer); memcpy(myBuffer, myPrevBuffer, readStringLen+1); } pMyMachine->state = TINYCLI_PARSELINE; break; case 0x7Fu: // delete if (readStringLen) { readStringLen--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\033[D \033[D", 7u); myBuffer[readStringLen] = 0; } break; case 0x08u: // backspace - ^H if (readStringLen) { readStringLen--; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)" \033[D", 4u); myBuffer[readStringLen] = 0; } break; case 0x01u: // ^A readStringLen = 0; MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\r", 1); mHSS_PUTS(lineHeader); break; case 0x05u: // ^E readStringLen = strlen(myBuffer); MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)"\r", 1); mHSS_PUTS(lineHeader); MSS_UART_polled_tx(&g_mss_uart0_lo, (uint8_t const *)myBuffer, readStringLen); break; case 0x04u: // ^D if (readStringLen != 0) { break; } __attribute__((fallthrough)); // deliberate fallthrough case 0x03u: // intr - ^C readStringLen = -1; myBuffer[0] = 0; pMyMachine->state = TINYCLI_PARSELINE; break; case 0x1Bu: // ESC escapeActive = true; break; default: if (readStringLen < bufferLen) { MSS_UART_polled_tx(&g_mss_uart0_lo, cBuf, 1u); myBuffer[readStringLen] = cBuf[0]; readStringLen++; } break; } } } static void tinycli_readline_onExit(struct StateMachine * const pMyMachine) { (void)pMyMachine; const char crlf[] = "\n"; MSS_UART_polled_tx_string(&g_mss_uart0_lo, (const uint8_t *)crlf); if (readStringLen > 0) { } else { readStringLen = 0; myBuffer[0] = '\0'; } } ///////////////// static void tinycli_parseline_handler(struct StateMachine * const pMyMachine) { #if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) HSS_TinyCLI_RunMonitors(); #endif if (readStringLen > 0) { if (HSS_TinyCLI_ParseIntoTokens(myBuffer)) { HSS_TinyCLI_Execute(); } } if (pMyMachine->state == TINYCLI_PARSELINE) { pMyMachine->state = TINYCLI_READLINE; } } ///////////////// static void tinycli_usbdmsc_handler(struct StateMachine * const pMyMachine) { #if IS_ENABLED(CONFIG_SERVICE_USBDMSC) # if IS_ENABLED(CONFIG_SERVICE_TINYCLI_MONITOR) HSS_TinyCLI_RunMonitors(); # endif bool done = false; uint8_t cBuf[1]; done = !USBDMSC_IsActive(); if (!done && (0 != MSS_UART_get_rx(&g_mss_uart0_lo, cBuf, 1))) { done = (cBuf[0] == '\003') || (cBuf[0] == '\033'); } if (done) { USBDMSC_Deactivate(); pMyMachine->state = TINYCLI_READLINE; } #else pMyMachine->state = TINYCLI_READLINE; #endif } ///////////////// void HSS_TinyCLI_WaitForUSBMSCDDone(void) { tinycli_service.state = TINYCLI_USBDMSC; } static void tinycli_uart_surrender_handler(struct StateMachine * const pMyMachine) { ; // nothing to do here } void HSS_TinyCLI_SurrenderUART(void) { tinycli_service.state = TINYCLI_UART_SURRENDER; } hart-software-services-2022.10/services/tinycli/tinycli_service.h000066400000000000000000000035641432224323300251370ustar00rootroot00000000000000#ifndef HSS_TINYCLI_SERVICE_H #define HSS_TINYCLI_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Tiny CLI Parser * */ #ifdef __cplusplus extern "C" { #endif #include "ssmb_ipi.h" #include "hss_state_machine.h" #include "hss_debug.h" /** * \file Tiny CLI parser * \brief Tiny CLI parser */ bool HSS_TinyCLI_Parser(void); size_t HSS_TinyCLI_ParseIntoTokens(char *buffer); void HSS_TinyCLI_Execute(void); bool HSS_TinyCLI_IndicatePostInit(void); void HSS_TinyCLI_RunMonitors(void); void HSS_TinyCLI_WaitForUSBMSCDDone(void); void HSS_TinyCLI_SurrenderUART(void); extern struct StateMachine tinycli_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/uart/000077500000000000000000000000001432224323300210635ustar00rootroot00000000000000hart-software-services-2022.10/services/uart/Kconfig000066400000000000000000000002471432224323300223710ustar00rootroot00000000000000config SERVICE_UART bool "UART support" default n help This feature enables support for virtual UART. If you do not know what to do here, say Y. hart-software-services-2022.10/services/uart/Makefile000066400000000000000000000024541432224323300225300ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # Virtual UART Service SRCS-$(CONFIG_SERVICE_UART) += \ services/uart/uart_service.c \ services/uart/uart_api.c \ INCLUDES +=\ -I./services/uart \ hart-software-services-2022.10/services/uart/uart_api.c000066400000000000000000000025121432224323300230330ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Virtual UART API * \brief UART Driver State Machine API function definitions */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include "uart_service.h" enum IPIStatusCode HSS_UartTx_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { (void)transaction_id; (void)source; (void)immediate_arg; (void)p_extended_buffer_in_ddr; (void)p_ancilliary_buffer_in_ddr; // IPI received from one of the U54s... mHSS_DEBUG_PRINTF(LOG_NORMAL, "called\n"); return IPI_SUCCESS; } enum IPIStatusCode HSS_UartPollRx_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr) { (void)transaction_id; (void)source; (void)immediate_arg; (void)p_extended_buffer_in_ddr; (void)p_ancilliary_buffer_in_ddr; // IPI received from one of the U54s... mHSS_DEBUG_PRINTF(LOG_NORMAL, "called\n"); return IPI_SUCCESS; } hart-software-services-2022.10/services/uart/uart_service.c000066400000000000000000000045471432224323300237340ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file UART Driver State Machine * \brief Virtualised UART Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" static void uart_init_handler(struct StateMachine * const pMyMachine); static void uart_state1_handler(struct StateMachine * const pMyMachine); static void uart_lastState_handler(struct StateMachine * const pMyMachine); /*! * \brief UART Driver States */ enum UartStatesEnum { UART_INITIALIZATION, UART_STATE1_DO_SOMETHING, UART_LAST_STATE, UART_NUM_STATES = UART_LAST_STATE+1 }; /*! * \brief UART Driver State Descriptors */ static const struct StateDesc uart_state_descs[] = { { (const stateType_t)UART_INITIALIZATION, (const char *)"init", NULL, NULL, &uart_init_handler }, { (const stateType_t)UART_STATE1_DO_SOMETHING, (const char *)"state1", NULL, NULL, &uart_state1_handler }, { (const stateType_t)UART_LAST_STATE, (const char *)"lastState", NULL, NULL, &uart_lastState_handler } }; /*! * \brief UART Driver State Machine */ struct StateMachine uart_service = { (stateType_t)UART_INITIALIZATION, (stateType_t)SM_INVALID_STATE, (const uint32_t)UART_NUM_STATES, (const char *)"uart_service", 0u, 0u, 0u, uart_state_descs, false, 0u, NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void uart_init_handler(struct StateMachine * const pMyMachine) { //mHSS_DEBUG_PRINTF("\tcalled\n"); pMyMachine->state++; } ///////////////// static uint32_t i = HSS_HART_U54_1; static void uart_state1_handler(struct StateMachine * const pMyMachine) { //mHSS_DEBUG_PRINTF("\tcalled\n"); // check each core to see if it wants to transmit if (IPI_GetQueuePendingCount(i)) { IPI_ConsumeIntent(i, IPI_MSG_UART_TX); } i = (i + 1u) % HSS_HART_NUM_PEERS; //pMyMachine->state++; } ///////////////// static void uart_lastState_handler(struct StateMachine * const pMyMachine) { //mHSS_DEBUG_PRINTF("\tcalled\n"); pMyMachine->state = UART_INITIALIZATION; } hart-software-services-2022.10/services/uart/uart_service.h000066400000000000000000000037231432224323300237340ustar00rootroot00000000000000#ifndef HSS_UART_SERVICE_H #define HSS_UART_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Virtual UART API * */ /*! * \file Virtual UART API * \brief UART Driver State Machine API function declarations */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" enum IPIStatusCode HSS_UartTx_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); enum IPIStatusCode HSS_UartPollRx_IPIHandler(TxId_t transaction_id, enum HSSHartId source, uint32_t immediate_arg, void *p_extended_buffer_in_ddr, void *p_ancilliary_buffer_in_ddr); extern struct StateMachine uart_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/usbdmsc/000077500000000000000000000000001432224323300215505ustar00rootroot00000000000000hart-software-services-2022.10/services/usbdmsc/Kconfig000066400000000000000000000012041432224323300230500ustar00rootroot00000000000000config SERVICE_USBDMSC bool "USBD-MSC support" default n depends on SERVICE_TINYCLI && (SERVICE_MMC || SERVICE_QSPI) help This feature enables USBD-MSC support to expose eMMC/SDCard over USB. If you do not know what to do here, say N. menu "USB Device Mass Storage Class" visible if SERVICE_USBDMSC config SERVICE_USBDMSC_REGISTER depends on SERVICE_USBDMSC bool "Register USBDMSC as a state machine" default n help This feature enables the USBD-MSC support to be registered as a state machine, which makes it available at all times via the E51. If you do not know what to do here, say N. endmenu hart-software-services-2022.10/services/usbdmsc/Makefile000066400000000000000000000032251432224323300232120ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # USBDMSC service SRCS-$(CONFIG_SERVICE_USBDMSC) += \ services/usbdmsc/flash_drive/flash_drive_app.c \ services/usbdmsc/usbdmsc_api.c \ services/usbdmsc/usbdmsc_service.c \ services/usbdmsc/flash_drive/usb_user_descriptors.c \ INCLUDES +=\ -I./services/usbdmsc \ -I./services/usbdmsc/flash_drive \ services/usbdmsc/flash_drive/flash_drive_app.o: CFLAGS=$(CFLAGS_GCCEXT) services/usbdmsc/usbdmsc_api.o: CFLAGS=$(CFLAGS_GCCEXT) services/usbdmsc/flash_drive/usb_user_descriptors.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/usbdmsc/flash_drive/000077500000000000000000000000001432224323300240365ustar00rootroot00000000000000hart-software-services-2022.10/services/usbdmsc/flash_drive/flash_drive_app.c000066400000000000000000000217601432224323300273360ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * USB MSC Class Storage Device example application to demonstrate the * PolarFire MSS USB operations in device mode. * * Drivers used: * PolarFire MSS USB Driver stack (inclusive of USBD-MSC class driver). * mss_mmc driver is used to access on board flash SD or eMMC device. * */ #include "config.h" // undefine OPENSBI as we want to use MPFS_HAL types in this module #undef CONFIG_OPENSBI #include "mss_plic.h" #include "mss_clint.h" #include #include "flash_drive_app.h" #include "drivers/mss/mss_usb/mss_usb_device.h" #include "drivers/mss/mss_usb/mss_usb_device_msd.h" #include "hal/hal.h" #include "mss_hal.h" #include "mss_mpu.h" #include "drivers/mss/mss_mmc/mss_mmc.h" #ifdef __cplusplus extern "C" { #endif #define USE_SDMA_OPERATIONS /****************************************************************************** * * Private data structures * */ // Number of LUNs supported 1. LUN0 #define NUMBER_OF_LUNS_ON_DRIVE 1u /* Single block buffer size */ #define MMC_LBA_BLOCK_SIZE 512u #define MMC_NUM_LBA_BLOCKS 0xE90E80u // 15273600 => ~7.28GiB #define MMC_ERASE_SIZE 4096u #define SD_RD_WR_SIZE 32768u uint32_t g_host_connection_detected = 0u; /*Type to store information of each LUN*/ typedef struct flash_lun_data { uint32_t number_of_blocks; uint32_t erase_block_size; uint32_t lba_block_size; } flash_lun_data_t; /****************************************************************************** Private function declarations */ static uint8_t* usb_flash_media_inquiry(uint8_t lun, uint32_t *len); static uint8_t usb_flash_media_init (uint8_t lun); static uint8_t usb_flash_media_get_capacity(uint8_t lun, uint32_t *no_of_blocks, uint32_t *block_size); static uint8_t usb_flash_media_is_ready(uint8_t lun); static uint8_t usb_flash_media_is_write_protected(uint8_t lun); static uint32_t usb_flash_media_read(uint8_t lun, uint8_t **buf, uint64_t lba_addr, uint32_t len); static uint8_t* usb_flash_media_acquire_write_buf(uint8_t lun, uint64_t blk_addr, uint32_t *len); static uint32_t usb_flash_media_write_ready(uint8_t lun, uint64_t blk_addr, uint32_t len); static uint8_t usb_flash_media_release(uint8_t cfgidx); static uint8_t usb_flash_media_get_max_lun(void); /* Implementation of mss_usbd_msc_media_t needed by USB MSD Class Driver*/ static mss_usbd_msc_media_t usb_flash_media = { usb_flash_media_init, usb_flash_media_get_capacity, usb_flash_media_is_ready, usb_flash_media_is_write_protected, usb_flash_media_read, usb_flash_media_acquire_write_buf, usb_flash_media_write_ready, usb_flash_media_get_max_lun, usb_flash_media_inquiry, usb_flash_media_release }; extern mss_usbd_user_descr_cb_t flash_drive_descriptors_cb; /*This buffer is passed to the USB driver. When USB drivers are configured to use internal DMA, the address of this buffer must be modulo-4.Otherwise DMA Transfer will fail.*/ uint8_t lun0_data_buffer[SD_RD_WR_SIZE] __attribute__((aligned(8))) = { 0u }; flash_lun_data_t lun_data[NUMBER_OF_LUNS_ON_DRIVE] = {{MMC_NUM_LBA_BLOCKS, MMC_ERASE_SIZE, MMC_LBA_BLOCK_SIZE}}; static mss_usbd_msc_scsi_inq_resp_t usb_flash_media_inquiry_data[NUMBER_OF_LUNS_ON_DRIVE] = { { 0x00u, /* peripheral */ 0x80u, /* removable */ 0x04u, /* version */ 0x02u, /* resp_data_format */ 0x20u, /* additional_length */ 0x00u, /* sccstp */ 0x00u, /* bqueetc */ 0x00u, /* cmd_que */ "MSCC ", /* vendor_id[8] */ "PolarFireSoC_msd", /* product_id[16] */ "1234" /* product_rev[4] */ } }; /****************************************************************************** See flash_drive_app.h for details of how to use this function. */ bool FLASH_DRIVE_init(void) { bool result = false; bool HSS_Storage_Init(void); void HSS_Storage_GetInfo(uint32_t *pBlockSize, uint32_t *pEraseSize, uint32_t *pBlockCount); result = HSS_Storage_Init(); if (result) { HSS_Storage_GetInfo(&(lun_data[0].lba_block_size), &(lun_data[0].erase_block_size), &(lun_data[0].number_of_blocks)); g_host_connection_detected = 0u; // Assign call-back function Interface needed by USBD driver MSS_USBD_set_descr_cb_handler(&flash_drive_descriptors_cb); // Assign call-back function handler structure needed by MSD class driver MSS_USBD_MSC_init(&usb_flash_media, MSS_USB_DEVICE_HS); // Initialize USB driver MSS_USBD_init(MSS_USB_DEVICE_HS); } return result; } /****************************************************************************** Local function definitions */ #undef MIN #include "hss_types.h" #include "hss_clock.h" #include "hss_debug.h" static size_t writeCount = 0u, readCount = 0u; static size_t lastWriteCount = 0u, lastReadCount = 0u; HSSTicks_t last_sec_time = 0u; const char throbber[] = { '/', '-', '\\', '|' }; static size_t throbber_iterator = 0u; void FLASH_DRIVE_dump_xfer_status(void) { static char activeThrobber = '/'; if (HSS_Timer_IsElapsed(last_sec_time, 5*TICKS_PER_SEC) || ((lastWriteCount == writeCount) && (lastReadCount == readCount))) { activeThrobber = '.'; } else if (HSS_Timer_IsElapsed(last_sec_time, TICKS_PER_SEC)) { activeThrobber = throbber[throbber_iterator]; throbber_iterator++; throbber_iterator%= ARRAY_SIZE(throbber); } if (HSS_Timer_IsElapsed(last_sec_time, TICKS_PER_SEC)) { mHSS_DEBUG_PRINTF_EX("\r %c %lu bytes written, %lu bytes read", activeThrobber, writeCount, readCount); last_sec_time = HSS_GetTime(); } } static void update_write_count(size_t bytes) { writeCount += bytes; FLASH_DRIVE_dump_xfer_status(); } static void update_read_count(size_t bytes) { readCount += bytes; FLASH_DRIVE_dump_xfer_status(); } static uint8_t* usb_flash_media_inquiry(uint8_t lun, uint32_t *len) { if (lun != 0u) { return 0u; } *len = sizeof(usb_flash_media_inquiry_data[lun]); return ((uint8_t*)&usb_flash_media_inquiry_data[lun]); } static uint8_t usb_flash_media_release(uint8_t cfgidx) { (void)cfgidx; void HSS_Storage_FlushWriteBuffer(void); HSS_Storage_FlushWriteBuffer(); g_host_connection_detected = 0u; return 1u; } static uint8_t usb_flash_media_init(uint8_t lun) { return 1u; } static uint8_t usb_flash_media_get_max_lun(void) { return NUMBER_OF_LUNS_ON_DRIVE; } static uint8_t usb_flash_media_get_capacity(uint8_t lun, uint32_t *no_of_blocks, uint32_t *block_size) { uint8_t result; if (lun != 0) { result = 0u; } else { *no_of_blocks = lun_data[lun].number_of_blocks; *block_size = lun_data[lun].lba_block_size; g_host_connection_detected = 1u; result = 1u; } return result; } static void physical_device_read(uint64_t byte_address, uint8_t *p_rx_buffer, size_t size_in_bytes) { update_read_count(size_in_bytes); bool HSS_Storage_ReadBlock(void * p_rx_buffer, size_t byte_address, size_t size_in_bytes); (void)HSS_Storage_ReadBlock((void *)p_rx_buffer, (size_t)byte_address, size_in_bytes); } static uint32_t usb_flash_media_read(uint8_t lun, uint8_t **buf, uint64_t lba_addr, uint32_t len) { if (lun == 0) { if (len > SD_RD_WR_SIZE) { len = SD_RD_WR_SIZE; } physical_device_read(lba_addr, lun0_data_buffer, len); *buf = lun0_data_buffer; } return len; } static uint8_t* usb_flash_media_acquire_write_buf(uint8_t lun, uint64_t blk_addr, uint32_t *len) { uint8_t *result = NULL; *len = 0u; if ((blk_addr <= ((uint64_t)lun_data[0].number_of_blocks * lun_data[0].lba_block_size)) && (lun == 0u)) { *len = SD_RD_WR_SIZE; result = lun0_data_buffer; } return result; } static void physical_device_program(uint64_t byte_address, uint8_t * p_write_buffer, uint32_t size_in_bytes) { update_write_count(size_in_bytes); bool HSS_Storage_WriteBlock(size_t dstOffset, void * pSrc, size_t byteCount); (void)HSS_Storage_WriteBlock((size_t)byte_address, (void *)p_write_buffer, (size_t)size_in_bytes); } static uint32_t usb_flash_media_write_ready(uint8_t lun, uint64_t blk_addr, uint32_t len) { uint32_t result = 0u; if (lun == 0u) { if (len > SD_RD_WR_SIZE) { len = SD_RD_WR_SIZE; } physical_device_program(blk_addr, lun0_data_buffer, len); result = 1u; } return result; } static uint8_t usb_flash_media_is_ready(uint8_t lun) { (void)lun; return 1u; } static uint8_t usb_flash_media_is_write_protected(uint8_t lun) { (void)lun; return 1u; } uint32_t FLASH_DRIVE_is_host_connected(void) { return (g_host_connection_detected); } #ifdef __cplusplus } #endif hart-software-services-2022.10/services/usbdmsc/flash_drive/flash_drive_app.h000066400000000000000000000026261432224323300273430ustar00rootroot00000000000000/***************************************************************************//** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * USB MSC Class Storage Device example application to demonstrate the * PolarFire MSS USB operations in device mode. * * Header for flash_drive_app.h * */ #ifndef FLASH_DRIVE_APP_H_ #define FLASH_DRIVE_APP_H_ #ifdef __cplusplus extern "C" { #endif /****************************************************************************** Exported functions from this file */ /***************************************************************************//** @brief FLASH_DRIVE_init() @param This function does not take any parameters. @return This function returns true if initialization succeeded, else false Example: @code @endcode */ bool FLASH_DRIVE_init(void); /***************************************************************************//** @brief FLASH_DRIVE_init() @param This function does not take any parameters. @return This function returns a non-zero value when it has received GET_CAPACITY command from the host. This is taken as indication that the a working USB host connection is now established Example: @code @endcode */ uint32_t FLASH_DRIVE_is_host_connected(void); void FLASH_DRIVE_dump_xfer_status(void); #ifdef __cplusplus } #endif #endif /* FLASH_DRIVE_APP_H_*/ hart-software-services-2022.10/services/usbdmsc/flash_drive/usb_user_descriptors.c000066400000000000000000000227211432224323300304560ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * USB MSC Class Storage Device example application to demonstrate the * PolarFire MSS USB operations in USB Device mode. * * This file provides the Device Descriptor for the implemented USB Device. * This file implements Application call-back Interface structure type provided * by USBD driver. * */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "drivers/mss/mss_usb/mss_usb_device.h" #include "drivers/mss/mss_usb/mss_usb_std_def.h" #include "device_serial_number.h" #ifdef __cplusplus extern "C" { #endif /******************************************************************************* * Constant definitions */ #define USB_MAX_STRING_DESCRIPTOR_SIZE 64u /* String Descriptor Indexes */ #define USB_STRING_DESCRIPTOR_IDX_LANGID 0x00 #define USB_STRING_DESCRIPTOR_IDX_MANUFACTURER 0x01 #define USB_STRING_DESCRIPTOR_IDX_PRODUCT 0x02 #define USB_STRING_DESCRIPTOR_IDX_SERIAL 0x03 #define USB_STRING_DESCRIPTOR_IDX_CONFIG 0x04 #define USB_STRING_DESCRIPTOR_IDX_INTERFACE 0x05 #define USB_STRING_MANUFACTURER "Microchip Inc" #define USB_STRING_PRODUCT "PolarFireSoc-FlashDrive" #define USB_STRING_SERIAL "123456789ABCDEF151411111" #define USB_STRING_CONFIG "CFG-HS" #define USB_STRING_INTERFACE "Interface-MSD" /******************************************************************************* * Local functions. */ uint8_t* flash_drive_device_descriptor(uint32_t* length); uint8_t* flash_drive_device_qual_descriptor(mss_usb_device_speed_t speed, uint32_t* length); uint8_t* flash_drive_string_descriptor(uint8_t index, uint32_t* length); uint8_t flash_drive_get_string(uint8_t const * const string, uint8_t* dest); /***************************************************************************//** Device descriptor. */ uint8_t device_descriptor[USB_STD_DEVICE_DESCR_LEN] = { USB_STD_DEVICE_DESCR_LEN, /* bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00u, /* bcdUSB LSB */ 0x02u, /* bcdUSB MSB */ 0x00u, /* bDeviceClass */ 0x00u, /* bDeviceSubClass */ 0x00u, /* bDeviceProtocol */ 0x40u, /* bMaxPacketSize0 */ 0x14u, /* idVendor LSB */ 0x15u, /* idVendor MSB */ 0x01u, /* idProduct LSB */ 0x00u, /* idProduct MSB */ 0x00u, /* bcdDevice LSB */ 0x30u, /* bcdDevice MSB */ USB_STRING_DESCRIPTOR_IDX_MANUFACTURER, /* iManufacturer */ USB_STRING_DESCRIPTOR_IDX_PRODUCT, /* iProduct */ USB_STRING_DESCRIPTOR_IDX_SERIAL, /* iSerialNumber */ 0x01u /* bNumConfigurations */ }; /***************************************************************************//** Device qualifiers. */ uint8_t hs_dev_qualifier_descriptor[USB_STD_DEV_QUAL_DESCR_LENGTH] = { USB_STD_DEV_QUAL_DESCR_LENGTH, /* bLength */ USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00u, /* bcdUSB LSB */ 0x02u, /* bcdUSB MSB */ 0x00u, /* bDeviceClass */ 0x00u, /* bDeviceSubClass */ 0x00u, /* bDeviceProtocol */ 0x40u, /* bMaxPacketSize0 */ 0x01u, /* bNumConfigurations */ 0x00u /* Reserved */ }; uint8_t fs_dev_qualifier_descriptor[USB_STD_DEV_QUAL_DESCR_LENGTH] = { USB_STD_DEV_QUAL_DESCR_LENGTH, /* bLength */ USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x00u, /* bcdUSB LSB */ 0x02u, /* bcdUSB MSB */ 0x00u, /* bDeviceClass */ 0x00u, /* bDeviceSubClass */ 0x00u, /* bDeviceProtocol */ 0x40u, /* bMaxPacketSize0 */ 0x01u, /* bNumConfigurations */ 0x00u /* Reserved */ }; uint8_t lang_string_descriptor[] = { 0x04u, /* bLength */ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x09u, /* LangID-LSB */ 0x04u /* LangID-MSB */ }; mss_usbd_user_descr_cb_t flash_drive_descriptors_cb = { flash_drive_device_descriptor, flash_drive_device_qual_descriptor, flash_drive_string_descriptor, }; uint8_t g_string_descriptor[USB_MAX_STRING_DESCRIPTOR_SIZE]; uint8_t* flash_drive_device_descriptor(uint32_t* length) { *length = sizeof(device_descriptor); return (device_descriptor); } uint8_t* flash_drive_device_qual_descriptor(mss_usb_device_speed_t speed, uint32_t* length) { if (speed == MSS_USB_DEVICE_HS) { *length = sizeof(fs_dev_qualifier_descriptor); return (fs_dev_qualifier_descriptor); } else { *length = sizeof(hs_dev_qualifier_descriptor); return (hs_dev_qualifier_descriptor); } } static uint8_t nibble_to_hexchar_(uint8_t nibble) { uint8_t result; switch (nibble) { case 0u ... 9u: result = '0' + nibble; break; case 10u ... 15u: result = 'A' + (nibble - 10u); break; default: result = '?'; break; } return result; } static uint8_t* get_device_serial_(void) { // // for CI test purposes, we'll use the device serial number to give each // board a unique USBDMSC iSerial number... static uint8_t string_device_serial[USB_MAX_STRING_DESCRIPTOR_SIZE] = ""; static uint8_t* result = NULL; if (!result) { uint8_t* p_device_number_buffer; size_t serial_length; if (Get_Device_Serial_Number(&p_device_number_buffer, &serial_length)) { const size_t limit = MIN(MIN(USB_MAX_STRING_DESCRIPTOR_SIZE/2, serial_length), sizeof(USB_STRING_SERIAL)/2); for (size_t i = 0u; i < limit; i++) { string_device_serial[i*2u] = nibble_to_hexchar_(p_device_number_buffer[i] >> 4); string_device_serial[(i*2u) + 1u] = nibble_to_hexchar_(p_device_number_buffer[i] & 0xF); } result = string_device_serial; } else { result = (uint8_t*)USB_STRING_SERIAL; } } return result; } uint8_t* flash_drive_string_descriptor(uint8_t index, uint32_t* length) { switch (index) { case USB_STRING_DESCRIPTOR_IDX_LANGID: *length = sizeof(lang_string_descriptor); break; case USB_STRING_DESCRIPTOR_IDX_MANUFACTURER: *length = flash_drive_get_string((uint8_t*)USB_STRING_MANUFACTURER, g_string_descriptor); break; case USB_STRING_DESCRIPTOR_IDX_PRODUCT: *length = flash_drive_get_string((uint8_t*)USB_STRING_PRODUCT, g_string_descriptor); break; case USB_STRING_DESCRIPTOR_IDX_SERIAL: *length = flash_drive_get_string(get_device_serial_(), g_string_descriptor); break; case USB_STRING_DESCRIPTOR_IDX_CONFIG: *length = flash_drive_get_string((uint8_t*)USB_STRING_CONFIG, g_string_descriptor); break; case USB_STRING_DESCRIPTOR_IDX_INTERFACE: *length = flash_drive_get_string((uint8_t*)USB_STRING_INTERFACE, g_string_descriptor); break; default: /*Raise error*/ *length = 0; break; } if (USB_STRING_DESCRIPTOR_IDX_LANGID == index) { return (lang_string_descriptor); } return (g_string_descriptor); } uint8_t flash_drive_get_string(uint8_t const * const src_string, uint8_t* dest) { const uint8_t *idx = src_string ; uint8_t *cp_dest; cp_dest = dest; if ((dest != NULL) && (src_string != NULL)) { for (; *(idx); ++idx) { *(dest + 2u) = *(idx); dest++; *(dest + 2u) = 0x00u; dest++; } *cp_dest = ((idx - src_string) * 2u) + 2u; /*bLength*/ *(cp_dest + 1u) = USB_STRING_DESCRIPTOR_TYPE; /*bDesriptorType*/ } return (((idx - src_string) * 2u) + 2u); } #ifdef __cplusplus } #endif hart-software-services-2022.10/services/usbdmsc/usbdmsc_api.c000066400000000000000000000077321432224323300242160ustar00rootroot00000000000000/**************************************************************************//** * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * * SVN $Revision: 11522 $ * SVN $Date: 2019-06-26 10:14:17 +0530 (Wed, 26 Jun 2019) $ */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #undef ROUNDUP #undef ROUNDDOWN #include "mss_hal.h" #include "mss_assert.h" #include "flash_drive_app.h" #include "mss_plic.h" #include "uart_helper.h" #include "usbdmsc_service.h" #include "hss_init.h" /**************************************************************************//** */ void USBDMSC_Init(void) { SYSREG->SOFT_RESET_CR &= ~ (1u << 16u); PLIC_init(); PLIC_SetPriority(PLIC_USB_DMA_INT_OFFSET, 3); PLIC_SetPriority(PLIC_USB_MC_INT_OFFSET, 3); PLIC_EnableIRQ(PLIC_USB_DMA_INT_OFFSET); PLIC_EnableIRQ(PLIC_USB_MC_INT_OFFSET); PLIC_SetPriority(MMC_main_PLIC, 2u); PLIC_SetPriority(MMC_wakeup_PLIC, 2u); PLIC_EnableIRQ(MMC_main_PLIC); PLIC_EnableIRQ(MMC_wakeup_PLIC); HSS_USBInit(); MSS_MPU_configure(MSS_MPU_USB, MSS_MPU_PMP_REGION3, 0x08000000u, 0x200000u, MPU_MODE_READ_ACCESS|MPU_MODE_WRITE_ACCESS|MPU_MODE_EXEC_ACCESS, MSS_MPU_AM_NAPOT, 0u); /* DMA init for eMMC */ MSS_MPU_configure(MSS_MPU_MMC, MSS_MPU_PMP_REGION3, 0x08000000u, 0x200000u, MPU_MODE_READ_ACCESS|MPU_MODE_WRITE_ACCESS|MPU_MODE_EXEC_ACCESS, MSS_MPU_AM_NAPOT, 0u); } HSSTicks_t last_poll_time = 0u; bool USBDMSC_Poll(void) { bool done = false; #if !defined(CONFIG_SERVICE_USBDMSC_REGISTER) || !defined(CONFIG_SERVICE_TINYCLI_REGISTER) uint8_t rx_byte = 0; bool retval = uart_getchar(&rx_byte, 0, false); if (retval) { if ((rx_byte == '\003') || (rx_byte == '\033')) { done = true; } } else { #else { #endif //poll PLIC uint32_t source = PLIC_ClaimIRQ(); switch (source) { #if defined(CONFIG_SERVICE_MMC) case MMC_main_PLIC: // MMC interrupt PLIC_mmc_main_IRQHandler(); // interrupt 88 break; #endif case PLIC_USB_MC_INT_OFFSET: // main USB interrupt PLIC_usb_mc_IRQHandler(); // interrupt 87 break; case PLIC_USB_DMA_INT_OFFSET: // DMA USB interrupt PLIC_usb_dma_IRQHandler(); // interrupt 86 break; default: break; } if (source != INVALID_IRQn) { PLIC_CompleteIRQ(source); } } if (HSS_Timer_IsElapsed(last_poll_time, 5*TICKS_PER_SEC)) { FLASH_DRIVE_dump_xfer_status(); last_poll_time = HSS_GetTime(); } return done; } void USBDMSC_Shutdown(void) { #ifndef CONFIG_SERVICE_USBDMSC_REGISTER PLIC_ClearPendingIRQ(); USBDMSC_Deactivate(); #endif } void USBDMSC_Start(void) { bool done = !FLASH_DRIVE_init(); if (done) { mHSS_DEBUG_PRINTF(LOG_ERROR, "FLASH_DRIVE_init() returned false...\n"); } else { #if !defined(CONFIG_SERVICE_USBDMSC_REGISTER) || !defined(CONFIG_SERVICE_TINYCLI_REGISTER) bool isHostConnected = false; mHSS_PUTS("Waiting for USB Host to connect... (CTRL-C to quit)\n"); do { if (!isHostConnected) { // if we are not connected, wait until we are isHostConnected = FLASH_DRIVE_is_host_connected(); if (isHostConnected) { mHSS_PUTS("USB Host connected. Waiting for disconnect... (CTRL-C to quit)\n"); } } else { // else quit once we've disconnected again... isHostConnected = FLASH_DRIVE_is_host_connected(); if (!isHostConnected) { done = true; } } done = done || USBDMSC_Poll(); } while (!done); void HSS_Storage_FlushWriteBuffer(void); HSS_Storage_FlushWriteBuffer(); mHSS_PUTS("\nUSB Host disconnected...\n"); #else USBDMSC_Activate(); #endif } } hart-software-services-2022.10/services/usbdmsc/usbdmsc_service.c000066400000000000000000000104121432224323300250720ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file USB Device Mass Storage Class State Machine * \brief USB Device Mass Storage Class */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_clock.h" #include //memset #include #include "usbdmsc_service.h" #include "mpfs_reg_map.h" #include "hss_boot_service.h" #include "drivers/mss/mss_mmuart/mss_uart.h" static void usbdmsc_init_handler(struct StateMachine * const pMyMachine); static void usbdmsc_idle_handler(struct StateMachine * const pMyMachine); static void usbdmsc_waitForUSBHost_onEntry(struct StateMachine * const pMyMachine); static void usbdmsc_waitForUSBHost_handler(struct StateMachine * const pMyMachine); static void usbdmsc_active_handler(struct StateMachine * const pMyMachine); static void usbdmsc_active_onExit(struct StateMachine * const pMyMachine); /*! * \brief USBDMSC Driver States * */ enum UartStatesEnum { USBDMSC_INITIALIZATION, USBDMSC_IDLE, USBDMSC_WAIT_FOR_USB_HOST, USBDMSC_ACTIVE, USBDMSC_NUM_STATES = USBDMSC_ACTIVE+1 }; /*! * \brief USBDMSC Driver State Descriptors * */ static const struct StateDesc usbdmsc_state_descs[] = { { (const stateType_t)USBDMSC_INITIALIZATION, (const char *)"Init", NULL, NULL, &usbdmsc_init_handler }, { (const stateType_t)USBDMSC_IDLE, (const char *)"Idle", NULL, NULL, &usbdmsc_idle_handler }, { (const stateType_t)USBDMSC_WAIT_FOR_USB_HOST, (const char *)"WaitForUSBHost", &usbdmsc_waitForUSBHost_onEntry, NULL, &usbdmsc_waitForUSBHost_handler }, { (const stateType_t)USBDMSC_ACTIVE, (const char *)"Active", NULL, &usbdmsc_active_onExit, &usbdmsc_active_handler }, }; /*! * \brief USBDMSC Driver State Machine * */ struct StateMachine usbdmsc_service = { .state = (stateType_t)USBDMSC_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)USBDMSC_NUM_STATES, .pMachineName = (const char *)"usbdmsc_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = usbdmsc_state_descs, .debugFlag = true, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static void usbdmsc_init_handler(struct StateMachine * const pMyMachine) { pMyMachine->state = USBDMSC_IDLE; } ///////////////// static void usbdmsc_idle_handler(struct StateMachine * const pMyMachine) { (void)pMyMachine; } ///////////////// static void usbdmsc_waitForUSBHost_onEntry(struct StateMachine * const pMyMachine) { USBDMSC_Init(); mHSS_PUTS("Waiting for USB Host to connect... (CTRL-C to quit)\n"); } uint32_t FLASH_DRIVE_is_host_connected(void); //TODO: tidy static void usbdmsc_waitForUSBHost_handler(struct StateMachine * const pMyMachine) { if (FLASH_DRIVE_is_host_connected()) { mHSS_PUTS("USB Host connected. Waiting for disconnect... (CTRL-C to quit)\n"); pMyMachine->state = USBDMSC_ACTIVE; } USBDMSC_Poll(); } ///////////////// static void usbdmsc_active_handler(struct StateMachine * const pMyMachine) { if (!FLASH_DRIVE_is_host_connected()) { pMyMachine->state = USBDMSC_IDLE; } USBDMSC_Poll(); } static void usbdmsc_active_onExit(struct StateMachine * const pMyMachine) { (void)pMyMachine; void HSS_Storage_FlushWriteBuffer(void); HSS_Storage_FlushWriteBuffer(); mHSS_PUTS("\nUSB Host disconnected...\n"); } ///////////////// void USBDMSC_Activate(void) { usbdmsc_service.state = USBDMSC_WAIT_FOR_USB_HOST; } void USBDMSC_Deactivate(void) { if (usbdmsc_service.state != USBDMSC_IDLE) { usbdmsc_service.state = USBDMSC_IDLE; } } bool USBDMSC_IsActive(void) { return (usbdmsc_service.state != USBDMSC_IDLE); } hart-software-services-2022.10/services/usbdmsc/usbdmsc_service.h000066400000000000000000000035141432224323300251040ustar00rootroot00000000000000#ifndef HSS_USBDMSC_SERVICE_H #define HSS_USBDMSC_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - USB Device Mass Storage Class * */ #ifdef __cplusplus extern "C" { #endif #include "ssmb_ipi.h" #include "hss_state_machine.h" #include "hss_debug.h" /** * \file USB Device Mass Storage API * \brief USB Device Mass Storage API */ void USBDMSC_Init(void); bool USBDMSC_Poll(void); void USBDMSC_Start(void); void USBDMSC_Shutdown(void); void USBDMSC_Activate(void); void USBDMSC_Deactivate(void); bool USBDMSC_IsActive(void); extern struct StateMachine usbdmsc_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/wdog/000077500000000000000000000000001432224323300210505ustar00rootroot00000000000000hart-software-services-2022.10/services/wdog/Kconfig000066400000000000000000000020721432224323300223540ustar00rootroot00000000000000config SERVICE_WDOG bool "Virtual Watchdog support" default y help This feature enables support for E51-delegated virtual watchdog monitoring of the U54 application harts. If you do not know what to do here, say Y. menu "Watchdog Service" visible if SERVICE_WDOG config SERVICE_WDOG_DEBUG bool "Virtual Watchdog Debug Messages" default n depends on SERVICE_WDOG help This feature enabled support for debug messages from the virtual watchdog service. If you do not know what to do here, say N. config SERVICE_WDOG_DEBUG_TIMEOUT_SEC int "Time delay for debug output (seconds)" default 240 depends on SERVICE_WDOG help This feature determines the maximum number of queue messages supported for IPIs from different harts. config SERVICE_WDOG_ENABLE_E51 bool "Enable watchdog on E51" default y depends on SERVICE_WDOG help This feature enables the watchdog for the E51 Hart. This will cause the entire Hart Coreplex to restart if, for some reason, the E51 becomes unable to periodically update its watchdog. endmenu hart-software-services-2022.10/services/wdog/Makefile000066400000000000000000000024301432224323300225070ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # U54 Watchdog Monitor Service SRCS-$(CONFIG_SERVICE_WDOG) += \ services/wdog/wdog_service.c \ INCLUDES +=\ -I./services/wdog \ hart-software-services-2022.10/services/wdog/wdog_service.c000066400000000000000000000171021432224323300236750ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /*! * \file Watchdog Driver State Machine * \brief Virtualised Watchdog Service */ #include "config.h" #include "hss_types.h" #include "hss_state_machine.h" #include "hss_debug.h" #include "hss_clock.h" #include #include "wdog_service.h" #include "hss_boot_service.h" #include "mss_watchdog.h" static void wdog_init_handler(struct StateMachine * const pMyMachine); static void wdog_idle_handler(struct StateMachine * const pMyMachine); static void wdog_monitoring_handler(struct StateMachine * const pMyMachine); /*! * \brief WDOG Driver States * */ enum UartStatesEnum { WDOG_INITIALIZATION, WDOG_IDLE, WDOG_MONITORING, WDOG_NUM_STATES = WDOG_MONITORING+1 }; /*! * \brief WDOG Driver State Descriptors * */ static const struct StateDesc wdog_state_descs[] = { { (const stateType_t)WDOG_INITIALIZATION, (const char *)"init", NULL, NULL, &wdog_init_handler }, { (const stateType_t)WDOG_IDLE, (const char *)"idle", NULL, NULL, &wdog_idle_handler }, { (const stateType_t)WDOG_MONITORING, (const char *)"monitoring", NULL, NULL, &wdog_monitoring_handler } }; /*! * \brief WDOG Driver State Machine * */ struct StateMachine wdog_service = { .state = (stateType_t)WDOG_INITIALIZATION, .prevState = (stateType_t)SM_INVALID_STATE, .numStates = (const uint32_t)WDOG_NUM_STATES, .pMachineName = (const char *)"wdog_service", .startTime = 0u, .lastExecutionTime = 0u, .executionCount = 0u, .pStateDescs = wdog_state_descs, .debugFlag = false, .priority = 0u, .pInstanceData = NULL }; // -------------------------------------------------------------------------------------------------- // Handlers for each state in the state machine // static union HSSHartBitmask hartBitmask = { .uint = 0u }; static HSSTicks_t wdogInitTime[MAX_NUM_HARTS] = { 0u }; static void wdog_init_handler(struct StateMachine * const pMyMachine) { #if IS_ENABLED(CONFIG_SERVICE_WDOG_ENABLE_E51) mss_watchdog_config_t wd0lo_config; MSS_WD_get_config(MSS_WDOG0_LO, &wd0lo_config); wd0lo_config.forbidden_en = MSS_WDOG_ENABLE; wd0lo_config.mvrp_val = 0xFFFF000; MSS_WD_configure(MSS_WDOG0_LO, &wd0lo_config); #endif pMyMachine->state = WDOG_IDLE; } ///////////////// static void wdog_idle_handler(struct StateMachine * const pMyMachine) { (void) pMyMachine; if (hartBitmask.uint) { if (hartBitmask.s.u54_1) { wdogInitTime[HSS_HART_U54_1] = HSS_GetTime(); } if (hartBitmask.s.u54_2) { wdogInitTime[HSS_HART_U54_2] = HSS_GetTime(); } if (hartBitmask.s.u54_3) { wdogInitTime[HSS_HART_U54_3] = HSS_GetTime(); } if (hartBitmask.s.u54_4) { wdogInitTime[HSS_HART_U54_4] = HSS_GetTime(); } //mHSS_DEBUG_PRINTF("watchdog bitmask is 0x%x\n", hartBitmask.uint); pMyMachine->state = WDOG_MONITORING; } // nothing to do in this state } ///////////////// #if IS_ENABLED(CONFIG_SERVICE_WDOG_ENABLE_E51) # if IS_ENABLED(CONFIG_SERVICE_WDOG_DEBUG) static HSSTicks_t lastEntryTime = 0u; # endif #endif static void wdog_monitoring_handler(struct StateMachine * const pMyMachine) { (void) pMyMachine; #if IS_ENABLED(CONFIG_SERVICE_WDOG_ENABLE_E51) // tickle the E51 WDog to prevent it from firing... if (!MSS_WD_forbidden_status(MSS_WDOG0_LO)) { MSS_WD_reload(MSS_WDOG0_LO); } #endif #if IS_ENABLED(CONFIG_SERVICE_WDOG_DEBUG) if ((hartBitmask.uint) && (HSS_Timer_IsElapsed(lastEntryTime, (HSSTicks_t)CONFIG_SERVICE_WDOG_DEBUG_TIMEOUT_SEC * TICKS_PER_SEC))) { HSS_Wdog_DumpStats(); } #endif uint32_t status = mHSS_ReadRegU32(SYSREGSCB, MSS_STATUS); status = (status >> 4) & mHSS_BITMASK_ALL_U54; // move bits[8:4] to [4:0] status &= hartBitmask.uint; if (status) { // watchdog timer has triggered for a monitored hart.. mHSS_DEBUG_PRINTF(LOG_ERROR, "Watchdog has triggered - %02x\n", status); #if IS_ENABLED(CONFIG_SERVICE_BOOT) if (hartBitmask.s.u54_1) { HSS_Boot_RestartCore(HSS_HART_U54_1); wdogInitTime[HSS_HART_U54_1] = HSS_GetTime(); } if (hartBitmask.s.u54_2) { HSS_Boot_RestartCore(HSS_HART_U54_2); wdogInitTime[HSS_HART_U54_2] = HSS_GetTime(); } if (hartBitmask.s.u54_3) { HSS_Boot_RestartCore(HSS_HART_U54_3); wdogInitTime[HSS_HART_U54_3] = HSS_GetTime(); } if (hartBitmask.s.u54_4) { HSS_Boot_RestartCore(HSS_HART_U54_4); wdogInitTime[HSS_HART_U54_4] = HSS_GetTime(); } #endif } } ///////////////// void HSS_Wdog_MonitorHart(enum HSSHartId target) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "wdog_service monitoring "); switch (target) { case HSS_HART_U54_1: mHSS_DEBUG_PRINTF_EX("U54_1\n"); hartBitmask.s.u54_1 = 1; break; case HSS_HART_U54_2: mHSS_DEBUG_PRINTF_EX("U54_2\n"); hartBitmask.s.u54_2 = 1; break; case HSS_HART_U54_3: mHSS_DEBUG_PRINTF_EX("U54_3\n"); hartBitmask.s.u54_3 = 1; break; case HSS_HART_U54_4: mHSS_DEBUG_PRINTF_EX("U54_4\n"); hartBitmask.s.u54_4 = 1; break; case HSS_HART_ALL: mHSS_DEBUG_PRINTF_EX("U54_1 U54_2 U54_3 U54_4\n"); hartBitmask.s.u54_1 = 1; hartBitmask.s.u54_2 = 1; hartBitmask.s.u54_3 = 1; hartBitmask.s.u54_4 = 1; break; default: assert(1 == 0); // should never reach here!! LCOV_EXCL_LINE break; } } void HSS_Wdog_Reboot(enum HSSHartId target) { switch (target) { case HSS_HART_E51: MSS_WD_force_reset(MSS_WDOG0_LO); break; case HSS_HART_U54_1: MSS_WD_force_reset(MSS_WDOG1_LO); break; case HSS_HART_U54_2: MSS_WD_force_reset(MSS_WDOG2_LO); break; case HSS_HART_U54_3: MSS_WD_force_reset(MSS_WDOG3_LO); break; case HSS_HART_U54_4: MSS_WD_force_reset(MSS_WDOG4_LO); break; case HSS_HART_ALL: MSS_WD_force_reset(MSS_WDOG4_LO); MSS_WD_force_reset(MSS_WDOG3_LO); MSS_WD_force_reset(MSS_WDOG2_LO); MSS_WD_force_reset(MSS_WDOG1_LO); MSS_WD_force_reset(MSS_WDOG0_LO); while (1) { ; } break; default: assert(1 == 0); // should never reach here!! LCOV_EXCL_LINE break; } } void HSS_Wdog_DumpStats(void) { # if IS_ENABLED(CONFIG_SERVICE_WDOG_DEBUG) lastEntryTime = HSS_GetTime(); mHSS_DEBUG_PRINTF(LOG_NORMAL, "Watchdog Status Update: \n"); if (hartBitmask.s.u54_1) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "U54_1: %lu sec uptime\n", (lastEntryTime - wdogInitTime[HSS_HART_U54_1]) / TICKS_PER_SEC); } if (hartBitmask.s.u54_2) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "U54_2: %lu sec uptime\n", (lastEntryTime - wdogInitTime[HSS_HART_U54_2]) / TICKS_PER_SEC); } if (hartBitmask.s.u54_3) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "U54_3: %lu sec uptime \n", (lastEntryTime - wdogInitTime[HSS_HART_U54_3]) / TICKS_PER_SEC); } if (hartBitmask.s.u54_4) { mHSS_DEBUG_PRINTF(LOG_NORMAL, "U54_4: %lu sec uptime\n", (lastEntryTime - wdogInitTime[HSS_HART_U54_4]) / TICKS_PER_SEC); } mHSS_DEBUG_PRINTF_EX("\n"); #endif } hart-software-services-2022.10/services/wdog/wdog_service.h000066400000000000000000000034271432224323300237070ustar00rootroot00000000000000#ifndef HSS_WDOG_SERVICE_H #define HSS_WDOG_SERVICE_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - Virtual Watchdog Service * */ /*! * \file Watchdog Driver State Machine * \brief Virtualised Watchdog Service */ #ifdef __cplusplus extern "C" { #endif #include "hss_state_machine.h" #include "hss_debug.h" #include "ssmb_ipi.h" #include "mpfs_reg_map.h" void HSS_Wdog_MonitorHart(enum HSSHartId target); void HSS_Wdog_Reboot(enum HSSHartId target); void HSS_Wdog_DumpStats(void); extern struct StateMachine wdog_service; #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/ymodem/000077500000000000000000000000001432224323300214025ustar00rootroot00000000000000hart-software-services-2022.10/services/ymodem/Kconfig000066400000000000000000000003241432224323300227040ustar00rootroot00000000000000config SERVICE_YMODEM bool "YMODEM support" default n select SERVICE_TINYCLI help This feature enables support for YMODEM. If you do not know what to do here, say Y. hart-software-services-2022.10/services/ymodem/Makefile000066400000000000000000000027041432224323300230450ustar00rootroot00000000000000# # MPFS HSS Embedded Software # # Copyright 2019-2021 Microchip Corporation. # # SPDX-License-Identifier: MIT # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # # # YMODEM Service (NOTE: not a traditional super-loop service) ifdef CONFIG_SERVICE_YMODEM SRCS-$(CONFIG_PLATFORM_MPFS) += \ services/ymodem/hss_ymodem_loader.c \ services/ymodem/ymodem_protocol.c endif INCLUDES +=\ -I./services/ymodem \ services/ymodem/hss_ymodem_loader.o: CFLAGS=$(CFLAGS_GCCEXT) hart-software-services-2022.10/services/ymodem/hss_ymodem_loader.c000066400000000000000000000205531432224323300252500ustar00rootroot00000000000000/****************************************************************************************** * * MPFS HSS Embedded Software * * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ /*\! *\file E51 Glue for ymodem *\brief E51 Glue for ymodem */ #include "config.h" #include "hss_types.h" #include "hss_debug.h" #include "ddr_service.h" #include #include #include "fpga_design_config/fpga_design_config.h" #include "fpga_design_config/clocks/hw_mss_clks.h" #undef ROUNDUP #undef ROUNDDOWN #include "mss_util.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include "uart_helper.h" #include "ymodem.h" #include "drivers/mss/mss_sys_services/mss_sys_services.h" #include "mss_sysreg.h" #if IS_ENABLED(CONFIG_SERVICE_QSPI) # include "qspi_service.h" //# include "baremetal/drivers/micron_mt25q/micron_mt25q.h" # include "baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.h" #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) # include "mmc_service.h" # include "mss_mmc.h" #endif // // Local prototypes // #if IS_ENABLED(CONFIG_SERVICE_QSPI) static bool hss_loader_qspi_init(void); static bool hss_loader_qspi_program(uint8_t *pBuffer, size_t wrAddr, size_t receivedCount); static bool hss_loader_qspi_erase(void); #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) static bool hss_loader_mmc_init(void); static bool hss_loader_mmc_program(uint8_t *pBuffer, size_t wrAddr, size_t receivedCount); #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI) static bool hss_loader_qspi_init(void) { static bool initialized = false; bool result = false; if (!initialized) { result = HSS_QSPIInit(); initialized = true; } return result; } static bool hss_loader_qspi_program(uint8_t *pBuffer, size_t wrAddr, size_t receivedCount) { bool result = HSS_QSPI_WriteBlock(wrAddr, pBuffer, receivedCount); return result; } static bool hss_loader_qspi_erase(void) { HSS_QSPI_FlashChipErase(); return true; } #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) bool hss_loader_mmc_init(void) { bool result = false; SYSREG->SUBBLK_CLOCK_CR |= (uint32_t)SUBBLK_CLOCK_CR_MMC_MASK; SYSREG->SOFT_RESET_CR |= (uint32_t)SOFT_RESET_CR_MMC_MASK; SYSREG->SOFT_RESET_CR &= ~(uint32_t)SOFT_RESET_CR_MMC_MASK; result = HSS_MMCInit(); return result; } bool hss_loader_mmc_program(uint8_t *pBuffer, size_t wrAddr, size_t receivedCount) { bool result = HSS_MMC_WriteBlock(wrAddr, pBuffer, receivedCount); return result; } #endif void hss_loader_ymodem_loop(void); void hss_loader_ymodem_loop(void) { uint8_t rx_byte; bool done = false; uint32_t receivedCount = 0u; uint8_t *pBuffer = (uint8_t *)HSS_DDR_GetStart(); uint32_t g_rx_size = HSS_DDR_GetSize(); while (!done) { #if IS_ENABLED(CONFIG_SERVICE_QSPI) || IS_ENABLED(CONFIG_SERVICE_MMC) bool result = false; #endif static const char menuText[] = "\n" #if IS_ENABLED(CONFIG_SERVICE_QSPI) "QSPI" #endif #if IS_ENABLED(CONFIG_SERVICE_QSPI) && IS_ENABLED(CONFIG_SERVICE_MMC) "/" #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) "MMC" #endif " Utility\n" #if IS_ENABLED(CONFIG_SERVICE_QSPI) " 1. QSPI Erase Bulk -- erase all sectors\n" #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) " 2. MMC Init -- initialize MMC driver\n" #endif " 3. YMODEM Receive -- receive application file\n" #if IS_ENABLED(CONFIG_SERVICE_QSPI) " 4. QSPI Write -- write application file to the Device\n" #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) " 5. MMC Write -- write application file to the Device\n" #endif " 6. Quit -- quit QSPI Utility\n\n" " Select a number:\n"; mHSS_PUTS(menuText); if (uart_getchar(&rx_byte, -1, false)) { switch (rx_byte) { #if IS_ENABLED(CONFIG_SERVICE_QSPI) case '1': mHSS_PUTS("\nInitializing QSPI ... "); result = hss_loader_qspi_init(); if (result) { mHSS_PUTS(" Success\n"); mHSS_PUTS("\nErasing all of QSPI ... "); result = hss_loader_qspi_erase(); if (result) { mHSS_PUTS(" Success\n"); } } if (!result) { HSS_Debug_Highlight(HSS_DEBUG_LOG_ERROR); mHSS_PUTS(" FAILED\n"); HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); } break; #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) case '2': mHSS_PUTS("\nInitializing MMC ... "); result = hss_loader_mmc_init(); if (result) { mHSS_PUTS(" Success\n"); } if (!result) { HSS_Debug_Highlight(HSS_DEBUG_LOG_ERROR); mHSS_PUTS(" FAILED\n"); HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); } break; #endif case '3': mHSS_PUTS("\nAttempting to receive .bin file using YMODEM (CTRL-C to cancel)" "\n"); receivedCount = ymodem_receive(pBuffer, g_rx_size); if (receivedCount == 0) { HSS_Debug_Highlight(HSS_DEBUG_LOG_ERROR); mHSS_PUTS("\nYMODEM failed to receive file successfully\n\n"); HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); } break; #if IS_ENABLED(CONFIG_SERVICE_QSPI) case '4': mHSS_PRINTF("\nAttempting to flash received data (%u bytes)\n", receivedCount); mHSS_PUTS("\nInitializing QSPI ... "); result = hss_loader_qspi_init(); if (result) { mHSS_PUTS(" Success\n"); mHSS_PUTS("\nProgramming QSPI ... "); result = hss_loader_qspi_program((uint8_t *)pBuffer, 0u, receivedCount); if (result) { mHSS_PUTS(" Success\n"); } } if (!result) { HSS_Debug_Highlight(HSS_DEBUG_LOG_ERROR); mHSS_PUTS(" FAILED\n"); HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); } break; #endif #if IS_ENABLED(CONFIG_SERVICE_MMC) case '5': mHSS_PRINTF("\nAttempting to flash received data (%u bytes)\n", receivedCount); mHSS_PUTS("\nInitializing MMC ... "); result = hss_loader_mmc_init(); if (result) { mHSS_PUTS(" Success\n"); mHSS_PUTS("\nProgramming MMC ... "); result = hss_loader_mmc_program((uint8_t *)pBuffer, 0u, receivedCount); if (result) { mHSS_PUTS(" Success\n"); } } if (!result) { HSS_Debug_Highlight(HSS_DEBUG_LOG_ERROR); mHSS_PUTS(" FAILED\n"); HSS_Debug_Highlight(HSS_DEBUG_LOG_NORMAL); } break; #endif case '6': done = true; break; default: // ignore break; } } } } hart-software-services-2022.10/services/ymodem/ymodem.h000066400000000000000000000027261432224323300230540ustar00rootroot00000000000000#ifndef HSS_YMODEM_H #define HSS_YMODEM_H /******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * * Hart Software Services - YMODEM Receiver * */ #ifdef __cplusplus extern "C" { #endif size_t ymodem_receive(uint8_t *buffer, size_t bufferSize); #ifdef __cplusplus } #endif #endif hart-software-services-2022.10/services/ymodem/ymodem.txt000066400000000000000000002037321432224323300234440ustar00rootroot00000000000000 - 1 - XMODEM/YMODEM PROTOCOL REFERENCE A compendium of documents describing the XMODEM and YMODEM File Transfer Protocols This document was formatted 10-14-88. Edited by Chuck Forsberg This file may be redistributed without restriction provided the text is not altered. Please distribute as widely as possible. Questions to Chuck Forsberg Omen Technology Inc The High Reliability Software 17505-V Sauvie Island Road Portland Oregon 97231 VOICE: 503-621-3406 :VOICE TeleGodzilla BBS: 503-621-3746 Speed 19200(Telebit PEP),2400,1200,300 CompuServe: 70007,2304 GEnie: CAF UUCP: ...!tektronix!reed!omen!caf - 2 - 1. TOWER OF BABEL A "YMODEM Tower of Babel" has descended on the microcomputing community bringing with it confusion, frustration, bloated phone bills, and wasted man hours. Sadly, I (Chuck Forsberg) am partly to blame for this mess. As author of the early 1980s batch and 1k XMODEM extensions, I assumed readers of earlier versions of this document would implement as much of the YMODEM protocol as their programming skills and computing environments would permit. This proved a rather naive assumption as programmers motivated by competitive pressure implemented as little of YMODEM as possible. Some have taken whatever parts of YMODEM that appealed to them, applied them to MODEM7 Batch, Telink, XMODEM or whatever, and called the result YMODEM. Jeff Garbers (Crosstalk package development director) said it all: "With protocols in the public domain, anyone who wants to dink around with them can go ahead." [1] Documents containing altered examples derived from YMODEM.DOC have added to the confusion. In one instance, some self styled rewriter of history altered the heading in YMODEM.DOC's Figure 1 from "1024 byte Packets" to "YMODEM/CRC File Transfer Protocol". None of the XMODEM and YMODEM examples shown in that document were correct. To put an end to this confusion, we must make "perfectly clear" what YMODEM stands for, as Ward Christensen defined it in his 1985 coining of the term. To the majority of you who read, understood, and respected Ward's definition of YMODEM, I apologize for the inconvenience. 1.1 Definitions ARC ARC is a program that compresses one or more files into an archive and extracts files from such archives. XMODEM refers to the file transfer etiquette introduced by Ward Christensen's 1977 MODEM.ASM program. The name XMODEM comes from Keith Petersen's XMODEM.ASM program, an adaptation of MODEM.ASM for Remote CP/M (RCPM) systems. It's also called the MODEM or MODEM2 protocol. Some who are unaware of MODEM7's unusual batch file mode call it MODEM7. Other aliases include "CP/M Users' Group" and "TERM II FTP 3". The name XMODEM caught on partly because it is distinctive and partly because of media interest in __________ 1. Page C/12, PC-WEEK July 12, 1987 Chapter 1 X/YMODEM Protocol Reference June 18 1988 3 bulletin board and RCPM systems where it was accessed with an "XMODEM" command. This protocol is supported by every serious communications program because of its universality, simplicity, and reasonable performance. XMODEM/CRC replaces XMODEM's 1 byte checksum with a two byte Cyclical Redundancy Check (CRC-16), giving modern error detection protection. XMODEM-1k Refers to the XMODEM/CRC protocol with 1024 byte data blocks. YMODEM Refers to the XMODEM/CRC (optional 1k blocks) protocol with batch transmission as described below. In a nutshell, YMODEM means BATCH. YMODEM-g Refers to the streaming YMODEM variation described below. True YMODEM(TM) In an attempt to sort out the YMODEM Tower of Babel, Omen Technology has trademarked the term True YMODEM(TM) to represent the complete YMODEM protocol described in this document, including pathname, length, and modification date transmitted in block 0. Please contact Omen Technology about certifying programs for True YMODEM(TM) compliance. ZMODEM uses familiar XMODEM/CRC and YMODEM technology in a new protocol that provides reliability, throughput, file management, and user amenities appropriate to contemporary data communications. ZOO Like ARC, ZOO is a program that compresses one or more files into a "zoo archive". ZOO supports many different operating systems including Unix and VMS. Chapter 1 X/YMODEM Protocol Reference June 18 1988 4 2. YMODEM MINIMUM REQUIREMENTS All programs claiming to support YMODEM must meet the following minimum requirements: + The sending program shall send the pathname (file name) in block 0. + The pathname shall be a null terminated ASCII string as described below. For those who are too lazy to read the entire document: + Unless specifically requested, only the file name portion is sent. + No drive letter is sent. + Systems that do not distinguish between upper and lower case letters in filenames shall send the pathname in lower case only. + The receiving program shall use this pathname for the received file name, unless explicitly overridden. + When the receiving program receives this block and successfully opened the output file, it shall acknowledge this block with an ACK character and then proceed with a normal XMODEM file transfer beginning with a "C" or NAK tranmsitted by the receiver. + The sending program shall use CRC-16 in response to a "C" pathname nak, otherwise use 8 bit checksum. + The receiving program must accept any mixture of 128 and 1024 byte blocks within each file it receives. Sending programs may arbitrarily switch between 1024 and 128 byte blocks. + The sending program must not change the length of an unacknowledged block. + At the end of each file, the sending program shall send EOT up to ten times until it receives an ACK character. (This is part of the XMODEM spec.) + The end of a transfer session shall be signified by a null (empty) pathname, this pathname block shall be acknowledged the same as other pathname blocks. Programs not meeting all of these requirements are not YMODEM compatible, and shall not be described as supporting YMODEM. Meeting these MINIMUM requirements does not guarantee reliable file Chapter 2 X/YMODEM Protocol Reference June 18 1988 5 transfers under stress. Particular attention is called to XMODEM's single character supervisory messages that are easily corrupted by transmission errors. Chapter 2 X/YMODEM Protocol Reference June 18 1988 6 3. WHY YMODEM? Since its development half a decade ago, the Ward Christensen modem protocol has enabled a wide variety of computer systems to interchange data. There is hardly a communications program that doesn't at least claim to support this protocol. Advances in computing, modems and networking have revealed a number of weaknesses in the original protocol: + The short block length caused throughput to suffer when used with timesharing systems, packet switched networks, satellite circuits, and buffered (error correcting) modems. + The 8 bit arithmetic checksum and other aspects allowed line impairments to interfere with dependable, accurate transfers. + Only one file could be sent per command. The file name had to be given twice, first to the sending program and then again to the receiving program. + The transmitted file could accumulate as many as 127 extraneous bytes. + The modification date of the file was lost. A number of other protocols have been developed over the years, but none have displaced XMODEM to date: + Lack of public domain documentation and example programs have kept proprietary protocols such as Blast, Relay, and others tightly bound to the fortunes of their suppliers. + Complexity discourages the widespread application of BISYNC, SDLC, HDLC, X.25, and X.PC protocols. + Performance compromises and complexity have limited the popularity of the Kermit protocol, which was developed to allow file transfers in environments hostile to XMODEM. The XMODEM protocol extensions and YMODEM Batch address some of these weaknesses while maintaining most of XMODEM's simplicity. YMODEM is supported by the public domain programs YAM (CP/M), YAM(CP/M-86), YAM(CCPM-86), IMP (CP/M), KMD (CP/M), rz/sz (Unix, Xenix, VMS, Berkeley Unix, Venix, Xenix, Coherent, IDRIS, Regulus). Commercial implementations include MIRROR, and Professional-YAM.[1] Communications Chapter 3 X/YMODEM Protocol Reference June 18 1988 7 programs supporting these extensions have been in use since 1981. The 1k block length (XMODEM-1k) described below may be used in conjunction with YMODEM Batch Protocol, or with single file transfers identical to the XMODEM/CRC protocol except for minimal changes to support 1k blocks. Another extension is the YMODEM-g protocol. YMODEM-g provides batch transfers with maximum throughput when used with end to end error correcting media, such as X.PC and error correcting modems, including 9600 bps units by TeleBit, U.S.Robotics, Hayes, Electronic Vaults, Data Race, and others. To complete this tome, edited versions of Ward Christensen's original protocol document and John Byrns's CRC-16 document are included for reference. References to the MODEM or MODEM7 protocol have been changed to XMODEM to accommodate the vernacular. In Australia, it is properly called the Christensen Protocol. 3.1 Some Messages from the Pioneer #: 130940 S0/Communications 25-Apr-85 18:38:47 Sb: my protocol Fm: Ward Christensen 76703,302 [2] To: all Be aware the article[3] DID quote me correctly in terms of the phrases like "not robust", etc. It was a quick hack I threw together, very unplanned (like everything I do), to satisfy a personal need to communicate with "some other" people. ONLY the fact that it was done in 8/77, and that I put it in the public domain immediately, made it become the standard that it is. __________________________________________________________________________ 1. Available for IBM PC,XT,AT, Unix and Xenix 2. Edited for typesetting appearance 3. Infoworld April 29 p. 16 Chapter 3 X/YMODEM Protocol Reference June 18 1988 8 I think its time for me to (1) document it; (people call me and say "my product is going to include it - what can I 'reference'", or "I'm writing a paper on it, what do I put in the bibliography") and (2) propose an "incremental extension" to it, which might take "exactly" the form of Chuck Forsberg's YAM protocol. He wrote YAM in C for CP/M and put it in the public domain, and wrote a batch protocol for Unix[4] called rb and sb (receive batch, send batch), which was basically XMODEM with (a) a record 0 containing filename date time and size (b) a 1K block size option (c) CRC-16. He did some clever programming to detect false ACK or EOT, but basically left them the same. People who suggest I make SIGNIFICANT changes to the protocol, such as "full duplex", "multiple outstanding blocks", "multiple destinations", etc etc don't understand that the incredible simplicity of the protocol is one of the reasons it survived to this day in as many machines and programs as it may be found in! Consider the PC-NET group back in '77 or so - documenting to beat the band - THEY had a protocol, but it was "extremely complex", because it tried to be "all things to all people" - i.e. send binary files on a 7-bit system, etc. I was not that "benevolent". I (emphasize > I < ) had an 8-bit UART, so "my protocol was an 8-bit protocol", and I would just say "sorry" to people who were held back by 7-bit limitations. ... Block size: Chuck Forsberg created an extension of my protocol, called YAM, which is also supported via his public domain programs for UNIX called rb and sb - receive batch and send batch. They cleverly send a "block 0" which contains the filename, date, time, and size. Unfortunately, its UNIX style, and is a bit weird[5] - octal numbers, etc. BUT, it is a nice way to overcome the kludgy "echo the chars of the name" introduced with MODEM7. Further, chuck uses CRC-16 and optional 1K blocks. Thus the record 0, 1K, and CRC, make it a "pretty slick new protocol" which is not significantly different from my own. Also, there is a catchy name - YMODEM. That means to some that it is the "next thing after XMODEM", and to others that it is the Y(am)MODEM __________ 4. VAX/VMS versions of these programs are also available. 5. The file length, time, and file mode are optional. The pathname and file length may be sent alone if desired. Chapter 3 X/YMODEM Protocol Reference June 18 1988 9 protocol. I don't want to emphasize that too much - out of fear that other mfgrs might think it is a "competitive" protocol, rather than an "unaffiliated" protocol. Chuck is currently selling a much-enhanced version of his CP/M-80 C program YAM, calling it Professional Yam, and its for the PC - I'm using it right now. VERY slick! 32K capture buffer, script, scrolling, previously captured text search, plus built-in commands for just about everything - directory (sorted every which way), XMODEM, YMODEM, KERMIT, and ASCII file upload/download, etc. You can program it to "behave" with most any system - for example when trying a number for CIS it detects the "busy" string back from the modem and substitutes a diff phone # into the dialing string and branches back to try it. Chapter 3 X/YMODEM Protocol Reference June 18 1988 10 4. XMODEM PROTOCOL ENHANCEMENTS This chapter discusses the protocol extensions to Ward Christensen's 1982 XMODEM protocol description document. The original document recommends the user be asked whether to continue trying or abort after 10 retries. Most programs no longer ask the operator whether he wishes to keep retrying. Virtually all correctable errors are corrected within the first few retransmissions. If the line is so bad that ten attempts are insufficient, there is a significant danger of undetected errors. If the connection is that bad, it's better to redial for a better connection, or mail a floppy disk. 4.1 Graceful Abort The YAM and Professional-YAM X/YMODEM routines recognize a sequence of two consecutive CAN (Hex 18) characters without modem errors (overrun, framing, etc.) as a transfer abort command. This sequence is recognized when is waiting for the beginning of a block or for an acknowledgement to a block that has been sent. The check for two consecutive CAN characters reduces the number of transfers aborted by line hits. YAM sends eight CAN characters when it aborts an XMODEM, YMODEM, or ZMODEM protocol file transfer. Pro-YAM then sends eight backspaces to delete the CAN characters from the remote's keyboard input buffer, in case the remote had already aborted the transfer and was awaiting a keyboarded command. 4.2 CRC-16 Option The XMODEM protocol uses an optional two character CRC-16 instead of the one character arithmetic checksum used by the original protocol and by most commercial implementations. CRC-16 guarantees detection of all single and double bit errors, all errors with an odd number of error bits, all burst errors of length 16 or less, 99.9969% of all 17-bit error bursts, and 99.9984 per cent of all possible longer error bursts. By contrast, a double bit error, or a burst error of 9 bits or more can sneak past the XMODEM protocol arithmetic checksum. The XMODEM/CRC protocol is similar to the XMODEM protocol, except that the receiver specifies CRC-16 by sending C (Hex 43) instead of NAK when requesting the FIRST block. A two byte CRC is sent in place of the one byte arithmetic checksum. YAM's c option to the r command enables CRC-16 in single file reception, corresponding to the original implementation in the MODEM7 series programs. This remains the default because many commercial communications programs and bulletin board systems still do not support CRC-16, especially those written in Basic or Pascal. XMODEM protocol with CRC is accurate provided both sender and receiver Chapter 4 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 11 both report a successful transmission. The protocol is robust in the presence of characters lost by buffer overloading on timesharing systems. The single character ACK/NAK responses generated by the receiving program adapt well to split speed modems, where the reverse channel is limited to ten per cent or less of the main channel's speed. XMODEM and YMODEM are half duplex protocols which do not attempt to transmit information and control signals in both directions at the same time. This avoids buffer overrun problems that have been reported by users attempting to exploit full duplex asynchronous file transfer protocols such as Blast. Professional-YAM adds several proprietary logic enhancements to XMODEM's error detection and recovery. These compatible enhancements eliminate most of the bad file transfers other programs make when using the XMODEM protocol under less than ideal conditions. 4.3 XMODEM-1k 1024 Byte Block Disappointing throughput downloading from Unix with YMODEM[1] lead to the development of 1024 byte blocks in 1982. 1024 byte blocks reduce the effect of delays from timesharing systems, modems, and packet switched networks on throughput by 87.5 per cent in addition to decreasing XMODEM's 3 per cent overhead (block number, CRC, etc.). Some environments cannot accept 1024 byte bursts, including some networks and minicomputer ports. The longer block length should be an option. The choice to use 1024 byte blocks is expressed to the sending program on its command line or selection menu.[2] 1024 byte blocks improve throughput in many applications. An STX (02) replaces the SOH (01) at the beginning of the transmitted block to notify the receiver of the longer block length. The transmitted block contains 1024 bytes of data. The receiver should be able to accept any mixture of 128 and 1024 byte blocks. The block number (in the second and third bytes of the block) is incremented by one for each block regardless of the block length. The sender must not change between 128 and 1024 byte block lengths if it has not received a valid ACK for the current block. Failure to observe __________ 1. The name hadn't been coined yet, but the protocol was the same. 2. See "KMD/IMP Exceptions to YMODEM" below. Chapter 4 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 12 this restriction allows transmission errors to pass undetected. If 1024 byte blocks are being used, it is possible for a file to "grow" up to the next multiple of 1024 bytes. This does not waste disk space if the allocation granularity is 1k or greater. With YMODEM batch transmission, the optional file length transmitted in the file name block allows the receiver to discard the padding, preserving the exact file length and contents. 1024 byte blocks may be used with batch file transmission or with single file transmission. CRC-16 should be used with the k option to preserve data integrity over phone lines. If a program wishes to enforce this recommendation, it should cancel the transfer, then issue an informative diagnostic message if the receiver requests checksum instead of CRC-16. Under no circumstances may a sending program use CRC-16 unless the receiver commands CRC-16. Figure 1. XMODEM-1k Blocks SENDER RECEIVER "sx -k foo.bar" "foo.bar open x.x minutes" C STX 01 FE Data[1024] CRC CRC ACK STX 02 FD Data[1024] CRC CRC ACK STX 03 FC Data[1000] CPMEOF[24] CRC CRC ACK EOT ACK Figure 2. Mixed 1024 and 128 byte Blocks SENDER RECEIVER "sx -k foo.bar" "foo.bar open x.x minutes" C STX 01 FE Data[1024] CRC CRC ACK STX 02 FD Data[1024] CRC CRC ACK SOH 03 FC Data[128] CRC CRC ACK SOH 04 FB Data[100] CPMEOF[28] CRC CRC ACK EOT ACK Chapter 4 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 13 5. YMODEM Batch File Transmission The YMODEM Batch protocol is an extension to the XMODEM/CRC protocol that allows 0 or more files to be transmitted with a single command. (Zero files may be sent if none of the requested files is accessible.) The design approach of the YMODEM Batch protocol is to use the normal routines for sending and receiving XMODEM blocks in a layered fashion similar to packet switching methods. Why was it necessary to design a new batch protocol when one already existed in MODEM7?[1] The batch file mode used by MODEM7 is unsuitable because it does not permit full pathnames, file length, file date, or other attribute information to be transmitted. Such a restrictive design, hastily implemented with only CP/M in mind, would not have permitted extensions to current areas of personal computing such as Unix, DOS, and object oriented systems. In addition, the MODEM7 batch file mode is somewhat susceptible to transmission impairments. As in the case of single a file transfer, the receiver initiates batch file transmission by sending a "C" character (for CRC-16). The sender opens the first file and sends block number 0 with the following information.[2] Only the pathname (file name) part is required for batch transfers. To maintain upwards compatibility, all unused bytes in block 0 must be set to null. Pathname The pathname (conventionally, the file name) is sent as a null terminated ASCII string. This is the filename format used by the handle oriented MSDOS(TM) functions and C library fopen functions. An assembly language example follows: DB 'foo.bar',0 No spaces are included in the pathname. Normally only the file name stem (no directory prefix) is transmitted unless the sender has selected YAM's f option to send the full pathname. The source drive (A:, B:, etc.) is not sent. Filename Considerations: __________ 1. The MODEM7 batch protocol transmitted CP/M FCB bytes f1...f8 and t1...t3 one character at a time. The receiver echoed these bytes as received, one at a time. 2. Only the data part of the block is described here. Chapter 5 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 14 + File names are forced to lower case unless the sending system supports upper/lower case file names. This is a convenience for users of systems (such as Unix) which store filenames in upper and lower case. + The receiver should accommodate file names in lower and upper case. + When transmitting files between different operating systems, file names must be acceptable to both the sender and receiving operating systems. If directories are included, they are delimited by /; i.e., "subdir/foo" is acceptable, "subdir\foo" is not. Length The file length and each of the succeeding fields are optional.[3] The length field is stored in the block as a decimal string counting the number of data bytes in the file. The file length does not include any CPMEOF (^Z) or other garbage characters used to pad the last block. If the file being transmitted is growing during transmission, the length field should be set to at least the final expected file length, or not sent. The receiver stores the specified number of characters, discarding any padding added by the sender to fill up the last block. Modification Date The mod date is optional, and the filename and length may be sent without requiring the mod date to be sent. Iff the modification date is sent, a single space separates the modification date from the file length. The mod date is sent as an octal number giving the time the contents of the file were last changed, measured in seconds from Jan 1 1970 Universal Coordinated Time (GMT). A date of 0 implies the modification date is unknown and should be left as the date the file is received. This standard format was chosen to eliminate ambiguities arising from transfers between different time zones. __________ 3. Fields may not be skipped. Chapter 5 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 15 Mode Iff the file mode is sent, a single space separates the file mode from the modification date. The file mode is stored as an octal string. Unless the file originated from a Unix system, the file mode is set to 0. rb(1) checks the file mode for the 0x8000 bit which indicates a Unix type regular file. Files with the 0x8000 bit set are assumed to have been sent from another Unix (or similar) system which uses the same file conventions. Such files are not translated in any way. Serial Number Iff the serial number is sent, a single space separates the serial number from the file mode. The serial number of the transmitting program is stored as an octal string. Programs which do not have a serial number should omit this field, or set it to 0. The receiver's use of this field is optional. Other Fields YMODEM was designed to allow additional header fields to be added as above without creating compatibility problems with older YMODEM programs. Please contact Omen Technology if other fields are needed for special application requirements. The rest of the block is set to nulls. This is essential to preserve upward compatibility.[4] If the filename block is received with a CRC or other error, a retransmission is requested. After the filename block has been received, it is ACK'ed if the write open is successful. If the file cannot be opened for writing, the receiver cancels the transfer with CAN characters as described above. The receiver then initiates transfer of the file contents with a "C" character, according to the standard XMODEM/CRC protocol. After the file contents and XMODEM EOT have been transmitted and acknowledged, the receiver again asks for the next pathname. Transmission of a null pathname terminates batch file transmission. Note that transmission of no files is not necessarily an error. This is possible if none of the files requested of the sender could be opened for reading. __________ 4. If, perchance, this information extends beyond 128 bytes (possible with Unix 4.2 BSD extended file names), the block should be sent as a 1k block as described above. Chapter 5 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 16 Most YMODEM receivers request CRC-16 by default. The Unix programs sz(1) and rz(1) included in the source code file RZSZ.ZOO should answer other questions about YMODEM batch protocol. Figure 3. YMODEM Batch Transmission Session (1 file) SENDER RECEIVER "sb foo.*" "sending in batch mode etc." C (command:rb) SOH 00 FF foo.c NUL[123] CRC CRC ACK C SOH 01 FE Data[128] CRC CRC ACK SOH 02 FC Data[128] CRC CRC ACK SOH 03 FB Data[100] CPMEOF[28] CRC CRC ACK EOT NAK EOT ACK C SOH 00 FF NUL[128] CRC CRC ACK Figure 7. YMODEM Header Information and Features _____________________________________________________________ | Program | Length | Date | Mode | S/N | 1k-Blk | YMODEM-g | |___________|________|______|______|_____|________|__________| |Unix rz/sz | yes | yes | yes | no | yes | sb only | |___________|________|______|______|_____|________|__________| |VMS rb/sb | yes | no | no | no | yes | no | |___________|________|______|______|_____|________|__________| |Pro-YAM | yes | yes | no | yes | yes | yes | |___________|________|______|______|_____|________|__________| |CP/M YAM | no | no | no | no | yes | no | |___________|________|______|______|_____|________|__________| |KMD/IMP | ? | no | no | no | yes | no | |___________|________|______|______|_____|________|__________| 5.1 KMD/IMP Exceptions to YMODEM KMD and IMP use a "CK" character sequence emitted by the receiver to trigger the use of 1024 byte blocks as an alternative to specifying this option to the sending program. This two character sequence generally works well on single process micros in direct communication, provided the programs rigorously adhere to all the XMODEM recommendations included Chapter 5 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 17 Figure 4. YMODEM Batch Transmission Session (2 files) SENDER RECEIVER "sb foo.c baz.c" "sending in batch mode etc." C (command:rb) SOH 00 FF foo.c NUL[123] CRC CRC ACK C SOH 01 FE Data[128] CRC CRC ACK SOH 02 FC Data[128] CRC CRC ACK SOH 03 FB Data[100] CPMEOF[28] CRC CRC ACK EOT NAK EOT ACK C SOH 00 FF baz.c NUL[123] CRC CRC ACK C SOH 01 FB Data[100] CPMEOF[28] CRC CRC ACK EOT NAK EOT ACK C SOH 00 FF NUL[128] CRC CRC ACK Figure 5. YMODEM Batch Transmission Session-1k Blocks SENDER RECEIVER "sb -k foo.*" "sending in batch mode etc." C (command:rb) SOH 00 FF foo.c NUL[123] CRC CRC ACK C STX 01 FD Data[1024] CRC CRC ACK SOH 02 FC Data[128] CRC CRC ACK SOH 03 FB Data[100] CPMEOF[28] CRC CRC ACK EOT NAK EOT Chapter 5 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 18 ACK C SOH 00 FF NUL[128] CRC CRC ACK Figure 6. YMODEM Filename block transmitted by sz -rw-r--r-- 6347 Jun 17 1984 20:34 bbcsched.txt 00 0100FF62 62637363 6865642E 74787400 |...bbcsched.txt.| 10 36333437 20333331 34373432 35313320 |6347 3314742513 | 20 31303036 34340000 00000000 00000000 |100644..........| 30 00000000 00000000 00000000 00000000 40 00000000 00000000 00000000 00000000 50 00000000 00000000 00000000 00000000 60 00000000 00000000 00000000 00000000 70 00000000 00000000 00000000 00000000 80 000000CA 56 herein. Programs with marginal XMODEM implementations do not fare so well. Timesharing systems and packet switched networks can separate the successive characters, rendering this method unreliable. Sending programs may detect the CK sequence if the operating enviornment does not preclude reliable implementation. Instead of the standard YMODEM file length in decimal, KMD and IMP transmit the CP/M record count in the last two bytes of the header block. 6. YMODEM-g File Transmission Developing technology is providing phone line data transmission at ever higher speeds using very specialized techniques. These high speed modems, as well as session protocols such as X.PC, provide high speed, nearly error free communications at the expense of considerably increased delay time. This delay time is moderate compared to human interactions, but it cripples the throughput of most error correcting protocols. The g option to YMODEM has proven effective under these circumstances. The g option is driven by the receiver, which initiates the batch transfer by transmitting a G instead of C. When the sender recognizes the G, it bypasses the usual wait for an ACK to each transmitted block, sending succeeding blocks at full speed, subject to XOFF/XON or other flow control exerted by the medium. The sender expects an inital G to initiate the transmission of a particular file, and also expects an ACK on the EOT sent at the end of each file. This synchronization allows the receiver time to open and Chapter 6 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 19 close files as necessary. If an error is detected in a YMODEM-g transfer, the receiver aborts the transfer with the multiple CAN abort sequence. The ZMODEM protocol should be used in applications that require both streaming throughput and error recovery. Figure 8. YMODEM-g Transmission Session SENDER RECEIVER "sb foo.*" "sending in batch mode etc..." G (command:rb -g) SOH 00 FF foo.c NUL[123] CRC CRC G SOH 01 FE Data[128] CRC CRC STX 02 FD Data[1024] CRC CRC SOH 03 FC Data[128] CRC CRC SOH 04 FB Data[100] CPMEOF[28] CRC CRC EOT ACK G SOH 00 FF NUL[128] CRC CRC Chapter 6 XMODEM Protocol Enhancements X/YMODEM Protocol Reference June 18 1988 20 7. XMODEM PROTOCOL OVERVIEW 8/9/82 by Ward Christensen. I will maintain a master copy of this. Please pass on changes or suggestions via CBBS/Chicago at (312) 545-8086, CBBS/CPMUG (312) 849-1132 or by voice at (312) 849-6279. 7.1 Definitions 01H 04H 06H 15H 18H 43H 7.2 Transmission Medium Level Protocol Asynchronous, 8 data bits, no parity, one stop bit. The protocol imposes no restrictions on the contents of the data being transmitted. No control characters are looked for in the 128-byte data messages. Absolutely any kind of data may be sent - binary, ASCII, etc. The protocol has not formally been adopted to a 7-bit environment for the transmission of ASCII-only (or unpacked-hex) data , although it could be simply by having both ends agree to AND the protocol-dependent data with 7F hex before validating it. I specifically am referring to the checksum, and the block numbers and their ones- complement. Those wishing to maintain compatibility of the CP/M file structure, i.e. to allow modemming ASCII files to or from CP/M systems should follow this data format: + ASCII tabs used (09H); tabs set every 8. + Lines terminated by CR/LF (0DH 0AH) + End-of-file indicated by ^Z, 1AH. (one or more) + Data is variable length, i.e. should be considered a continuous stream of data bytes, broken into 128-byte chunks purely for the purpose of transmission. + A CP/M "peculiarity": If the data ends exactly on a 128-byte boundary, i.e. CR in 127, and LF in 128, a subsequent sector containing the ^Z EOF character(s) is optional, but is preferred. Some utilities or user programs still do not handle EOF without ^Zs. Chapter 7 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 21 + The last block sent is no different from others, i.e. there is no "short block". Figure 9. XMODEM Message Block Level Protocol Each block of the transfer looks like: <255-blk #><--128 data bytes--> in which: = 01 hex = binary number, starts at 01 increments by 1, and wraps 0FFH to 00H (not to 01) <255-blk #> = blk # after going thru 8080 "CMA" instr, i.e. each bit complemented in the 8-bit block number. Formally, this is the "ones complement". = the sum of the data bytes only. Toss any carry. 7.3 File Level Protocol 7.3.1 Common_to_Both_Sender_and_Receiver All errors are retried 10 times. For versions running with an operator (i.e. NOT with XMODEM), a message is typed after 10 errors asking the operator whether to "retry or quit". Some versions of the protocol use , ASCII ^X, to cancel transmission. This was never adopted as a standard, as having a single "abort" character makes the transmission susceptible to false termination due to an or being corrupted into a and aborting transmission. The protocol may be considered "receiver driven", that is, the sender need not automatically re-transmit, although it does in the current implementations. 7.3.2 Receive_Program_Considerations The receiver has a 10-second timeout. It sends a every time it times out. The receiver's first timeout, which sends a , signals the transmitter to start. Optionally, the receiver could send a immediately, in case the sender was ready. This would save the initial 10 second timeout. However, the receiver MUST continue to timeout every 10 seconds in case the sender wasn't ready. Once into a receiving a block, the receiver goes into a one-second timeout for each character and the checksum. If the receiver wishes to a block for any reason (invalid header, timeout receiving data), it must wait for the line to clear. See "programming tips" for ideas Synchronizing: If a valid block number is received, it will be: 1) the expected one, in which case everything is fine; or 2) a repeat of the previously received block. This should be considered OK, and only indicates that the receivers got glitched, and the sender re- transmitted; 3) any other block number indicates a fatal loss of synchronization, such as the rare case of the sender getting a line-glitch Chapter 7 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 22 that looked like an . Abort the transmission, sending a 7.3.3 Sending_program_considerations While waiting for transmission to begin, the sender has only a single very long timeout, say one minute. In the current protocol, the sender has a 10 second timeout before retrying. I suggest NOT doing this, and letting the protocol be completely receiver-driven. This will be compatible with existing programs. When the sender has no more data, it sends an , and awaits an , resending the if it doesn't get one. Again, the protocol could be receiver-driven, with the sender only having the high-level 1-minute timeout to abort. Here is a sample of the data flow, sending a 3-block message. It includes the two most common line hits - a garbaged block, and an reply getting garbaged. represents the checksum byte. Figure 10. Data flow including Error Recovery SENDER RECEIVER times out after 10 seconds, <--- 01 FE -data- ---> <--- 02 FD -data- xx ---> (data gets line hit) <--- 02 FD -data- xx ---> <--- 03 FC -data- xx ---> (ack gets garbaged) <--- 03 FC -data- xx ---> ---> <--- ---> <--- (finished) 7.4 Programming Tips + The character-receive subroutine should be called with a parameter specifying the number of seconds to wait. The receiver should first call it with a time of 10, then and try again, 10 times. After receiving the , the receiver should call the character receive subroutine with a 1-second timeout, for the remainder of the message and the . Since they are sent as a continuous stream, timing out of this implies a serious like glitch that caused, say, 127 characters to be seen instead of 128. Chapter 7 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 23 + When the receiver wishes to , it should call a "PURGE" subroutine, to wait for the line to clear. Recall the sender tosses any characters in its UART buffer immediately upon completing sending a block, to ensure no glitches were mis- interpreted. The most common technique is for "PURGE" to call the character receive subroutine, specifying a 1-second timeout,[1] and looping back to PURGE until a timeout occurs. The is then sent, ensuring the other end will see it. + You may wish to add code recommended by John Mahr to your character receive routine - to set an error flag if the UART shows framing error, or overrun. This will help catch a few more glitches - the most common of which is a hit in the high bits of the byte in two consecutive bytes. The comes out OK since counting in 1-byte produces the same result of adding 80H + 80H as with adding 00H + 00H. __________ 1. These times should be adjusted for use with timesharing systems. Chapter 7 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 24 8. XMODEM/CRC Overview Original 1/13/85 by John Byrns -- CRC option. Please pass on any reports of errors in this document or suggestions for improvement to me via Ward's/CBBS at (312) 849-1132, or by voice at (312) 885-1105. The CRC used in the Modem Protocol is an alternate form of block check which provides more robust error detection than the original checksum. Andrew S. Tanenbaum says in his book, Computer Networks, that the CRC- CCITT used by the Modem Protocol will detect all single and double bit errors, all errors with an odd number of bits, all burst errors of length 16 or less, 99.997% of 17-bit error bursts, and 99.998% of 18-bit and longer bursts.[1] The changes to the Modem Protocol to replace the checksum with the CRC are straight forward. If that were all that we did we would not be able to communicate between a program using the old checksum protocol and one using the new CRC protocol. An initial handshake was added to solve this problem. The handshake allows a receiving program with CRC capability to determine whether the sending program supports the CRC option, and to switch it to CRC mode if it does. This handshake is designed so that it will work properly with programs which implement only the original protocol. A description of this handshake is presented in section 10. Figure 11. Message Block Level Protocol, CRC mode Each block of the transfer in CRC mode looks like: <255-blk #><--128 data bytes--> in which: = 01 hex = binary number, starts at 01 increments by 1, and wraps 0FFH to 00H (not to 01) <255-blk #> = ones complement of blk #. = byte containing the 8 hi order coefficients of the CRC. = byte containing the 8 lo order coefficients of the CRC. 8.1 CRC Calculation 8.1.1 Formal_Definition To calculate the 16 bit CRC the message bits are considered to be the coefficients of a polynomial. This message polynomial is first multiplied by X^16 and then divided by the generator polynomial (X^16 + X^12 + X^5 + __________ 1. This reliability figure is misleading because XMODEM's critical supervisory functions are not protected by this CRC. Chapter 8 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 25 1) using modulo two arithmetic. The remainder left after the division is the desired CRC. Since a message block in the Modem Protocol is 128 bytes or 1024 bits, the message polynomial will be of order X^1023. The hi order bit of the first byte of the message block is the coefficient of X^1023 in the message polynomial. The lo order bit of the last byte of the message block is the coefficient of X^0 in the message polynomial. Figure 12. Example of CRC Calculation written in C The following XMODEM crc routine is taken from "rbsb.c". Please refer to the source code for these programs (contained in RZSZ.ZOO) for usage. A fast table driven version is also included in this file. /* update CRC */ unsigned short updcrc(c, crc) register c; register unsigned crc; { register count; for (count=8; --count>=0;) { if (crc & 0x8000) { crc <<= 1; crc += (((c<<=1) & 0400) != 0); crc ^= 0x1021; } else { crc <<= 1; crc += (((c<<=1) & 0400) != 0); } } return crc; } 8.2 CRC File Level Protocol Changes 8.2.1 Common_to_Both_Sender_and_Receiver The only change to the File Level Protocol for the CRC option is the initial handshake which is used to determine if both the sending and the receiving programs support the CRC mode. All Modem Programs should support the checksum mode for compatibility with older versions. A receiving program that wishes to receive in CRC mode implements the mode setting handshake by sending a in place of the initial . If the sending program supports CRC mode it will recognize the and will set itself into CRC mode, and respond by sending the first block as if a had been received. If the sending program does not support CRC mode it will not respond to the at all. After the receiver has sent the it will wait up to 3 seconds for the that starts the first block. If it receives a within 3 seconds it will assume the sender supports CRC mode and will proceed with the file exchange in CRC mode. If no is Chapter 8 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 26 received within 3 seconds the receiver will switch to checksum mode, send a , and proceed in checksum mode. If the receiver wishes to use checksum mode it should send an initial and the sending program should respond to the as defined in the original Modem Protocol. After the mode has been set by the initial or the protocol follows the original Modem Protocol and is identical whether the checksum or CRC is being used. 8.2.2 Receive_Program_Considerations There are at least 4 things that can go wrong with the mode setting handshake. 1. the initial can be garbled or lost. 2. the initial can be garbled. 3. the initial can be changed to a . 4. the initial from a receiver which wants to receive in checksum can be changed to a . The first problem can be solved if the receiver sends a second after it times out the first time. This process can be repeated several times. It must not be repeated too many times before sending a and switching to checksum mode or a sending program without CRC support may time out and abort. Repeating the will also fix the second problem if the sending program cooperates by responding as if a were received instead of ignoring the extra . It is possible to fix problems 3 and 4 but probably not worth the trouble since they will occur very infrequently. They could be fixed by switching modes in either the sending or the receiving program after a large number of successive s. This solution would risk other problems however. 8.2.3 Sending_Program_Considerations The sending program should start in the checksum mode. This will insure compatibility with checksum only receiving programs. Anytime a is received before the first or the sending program should set itself into CRC mode and respond as if a were received. The sender should respond to additional s as if they were s until the first is received. This will assist the receiving program in determining the correct mode when the is lost or garbled. After the first is received the sending program should ignore s. Chapter 8 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 27 8.3 Data Flow Examples with CRC Option Here is a data flow example for the case where the receiver requests transmission in the CRC mode but the sender does not support the CRC option. This example also includes various transmission errors. represents the checksum byte. Figure 13. Data Flow: Receiver has CRC Option, Sender Doesn't SENDER RECEIVER <--- times out after 3 seconds, <--- times out after 3 seconds, <--- times out after 3 seconds, <--- times out after 3 seconds, <--- 01 FE -data- ---> <--- 02 FD -data- ---> (data gets line hit) <--- 02 FD -data- ---> <--- 03 FC -data- ---> (ack gets garbaged) <--- times out after 10 seconds, <--- 03 FC -data- ---> <--- ---> <--- Here is a data flow example for the case where the receiver requests transmission in the CRC mode and the sender supports the CRC option. This example also includes various transmission errors. represents the 2 CRC bytes. Chapter 8 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 28 Figure 14. Receiver and Sender Both have CRC Option SENDER RECEIVER <--- 01 FE -data- ---> <--- 02 FD -data- ---> (data gets line hit) <--- 02 FD -data- ---> <--- 03 FC -data- ---> (ack gets garbaged) <--- times out after 10 seconds, <--- 03 FC -data- ---> <--- ---> <--- Chapter 8 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 29 9. MORE INFORMATION Please contact Omen Technology for troff source files and typeset copies of this document. 9.1 TeleGodzilla Bulletin Board More information may be obtained by calling TeleGodzilla at 503-621-3746. Speed detection is automatic for 1200, 2400 and 19200(Telebit PEP) bps. TrailBlazer modem users may issue the TeleGodzilla trailblazer command to swith to 19200 bps once they have logged in. Interesting files include RZSZ.ZOO (C source code), YZMODEM.ZOO (Official XMODEM, YMODEM, and ZMODEM protocol descriptions), ZCOMMEXE.ARC, ZCOMMDOC.ARC, and ZCOMMHLP.ARC (PC-DOS shareware comm program with XMODEM, True YMODEM(TM), ZMODEM, Kermit Sliding Windows, Telink, MODEM7 Batch, script language, etc.). 9.2 Unix UUCP Access UUCP sites can obtain the current version of this file with uucp omen!/u/caf/public/ymodem.doc /tmp A continually updated list of available files is stored in /usr/spool/uucppublic/FILES. When retrieving these files with uucp, remember that the destination directory on your system must be writeable by anyone, or the UUCP transfer will fail. The following L.sys line calls TeleGodzilla (Pro-YAM in host operation). TeleGodzilla determines the incoming speed automatically. In response to "Name Please:" uucico gives the Pro-YAM "link" command as a user name. The password (Giznoid) controls access to the Xenix system connected to the IBM PC's other serial port. Communications between Pro-YAM and Xenix use 9600 bps; YAM converts this to the caller's speed. Finally, the calling uucico logs in as uucp. omen Any ACU 2400 1-503-621-3746 se:--se: link ord: Giznoid in:--in: uucp 10. REVISIONS 6-18-88 Further revised for clarity. Corrected block numbering in two examples. 10-27-87 Optional fields added for number of files remaining to be sent and total number of bytes remaining to be sent. 10-18-87 Flow control discussion added to 1024 byte block descritpion, minor revisions for clarity per user comments. Chapter 10 Xmodem Protocol Overview X/YMODEM Protocol Reference June 18 1988 30 8-03-87 Revised for clarity. 5-31-1987 emphasizes minimum requirements for YMODEM, and updates information on accessing files. 9-11-1986 clarifies nomenclature and some minor points. The April 15 1986 edition clarifies some points concerning CRC calculations and spaces in the header. 11. YMODEM Programs ZCOMM, A shareware little brother to Professional-YAM, is available as ZCOMMEXE.ARC on TeleGodzilla and other bulletin board systems. ZCOMM may be used to test YMODEM amd ZMODEM implementations. Unix programs supporting YMODEM are available on TeleGodzilla in RZSZ.ZOO. This ZOO archive includes a ZCOMM/Pro-YAM/PowerCom script ZUPL.T to upload a bootstrap program MINIRB.C, compile it, and then upload the rest of the files using the compiled MINIRB. Most Unix like systems are supported, including V7, Xenix, Sys III, 4.2 BSD, SYS V, Idris, Coherent, and Regulus. A version for VAX-VMS is available in VRBSB.SHQ. Irv Hoff has added 1k blocks and basic YMODEM batch transfers to the KMD and IMP series programs, which replace the XMODEM and MODEM7/MDM7xx series respectively. Overlays are available for a wide variety of CP/M systems. Questions about Professional-YAM communications software may be directed to: Chuck Forsberg Omen Technology Inc 17505-V Sauvie Island Road Portland Oregon 97231 VOICE: 503-621-3406 :VOICE Modem: 503-621-3746 Speed: 19200(Telebit PEP),2400,1200,300 Usenet: ...!tektronix!reed!omen!caf CompuServe: 70007,2304 GEnie: CAF Unlike ZMODEM and Kermit, XMODEM and YMODEM place obstacles in the path of a reliable high performance implementation, evidenced by poor reliability under stress of the industry leaders' XMODEM and YMODEM programs. Omen Technology provides consulting and other services to those wishing to implement XMODEM, YMODEM, and ZMODEM with state of the art features and reliability. Chapter 11 Xmodem Protocol Overview CONTENTS 1. TOWER OF BABEL................................................... 2 1.1 Definitions................................................. 2 2. YMODEM MINIMUM REQUIREMENTS...................................... 4 3. WHY YMODEM?...................................................... 6 3.1 Some Messages from the Pioneer.............................. 7 4. XMODEM PROTOCOL ENHANCEMENTS..................................... 10 4.1 Graceful Abort.............................................. 10 4.2 CRC-16 Option............................................... 10 4.3 XMODEM-1k 1024 Byte Block................................... 11 5. YMODEM Batch File Transmission................................... 13 5.1 KMD/IMP Exceptions to YMODEM................................ 16 6. YMODEM-g File Transmission....................................... 18 7. XMODEM PROTOCOL OVERVIEW......................................... 20 7.1 Definitions................................................. 20 7.2 Transmission Medium Level Protocol.......................... 20 7.3 File Level Protocol......................................... 21 7.4 Programming Tips............................................ 22 8. XMODEM/CRC Overview.............................................. 24 8.1 CRC Calculation............................................. 24 8.2 CRC File Level Protocol Changes............................. 25 8.3 Data Flow Examples with CRC Option.......................... 27 9. MORE INFORMATION................................................. 29 9.1 TeleGodzilla Bulletin Board................................. 29 9.2 Unix UUCP Access............................................ 29 10. REVISIONS........................................................ 29 11. YMODEM Programs.................................................. 30 - i - LIST OF FIGURES Figure 1. XMODEM-1k Blocks.......................................... 12 Figure 2. Mixed 1024 and 128 byte Blocks............................ 12 Figure 3. YMODEM Batch Transmission Session (1 file)................ 16 Figure 4. YMODEM Batch Transmission Session (2 files)............... 16 Figure 5. YMODEM Batch Transmission Session-1k Blocks............... 16 Figure 6. YMODEM Filename block transmitted by sz................... 16 Figure 7. YMODEM Header Information and Features.................... 16 Figure 8. YMODEM-g Transmission Session............................. 19 Figure 9. XMODEM Message Block Level Protocol....................... 21 Figure 10. Data flow including Error Recovery........................ 22 Figure 11. Message Block Level Protocol, CRC mode.................... 24 Figure 12. Example of CRC Calculation written in C................... 25 Figure 13. Data Flow: Receiver has CRC Option, Sender Doesn't........ 27 Figure 14. Receiver and Sender Both have CRC Option.................. 28 - ii - hart-software-services-2022.10/services/ymodem/ymodem_protocol.c000066400000000000000000000343741432224323300247740ustar00rootroot00000000000000/******************************************************************************* * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * * MPFS HSS Embedded Software * */ /** * \file HSS Software Initalization * \brief Full System Initialization */ #include "config.h" #include "hss_types.h" #include #include #include "hss_debug.h" #include "hss_crc32.h" #include "hss_crc16.h" #include "hss_clock.h" #include "ymodem.h" #include "drivers/mss/mss_mmuart/mss_uart.h" #include "uart_helper.h" /////////////////////////////////////////////////////////////////////////////////////////////////// #define HSS_XYMODEM_PROTOCOL_XMODEM 1 #define HSS_XYMODEM_PROTOCOL_YMODEM 2 #define HSS_XYMODEM_MAX_FILENAME_LENGTH 64u #define HSS_XYMODEM_MAX_SYNC_ATTEMPTS 20u #define HSS_XYMODEM_CAN_COUNT_REQUIRED 2u #define HSS_XYMODEM_PRE_SYNC_TIMEOUT_SEC 2 #define HSS_XYMODEM_POST_SYNC_TIMEOUT_SEC 1 #define HSS_XYMODEM_BAD_PACKET_RETRIES 10u #define HSS_XYMODEM_PACKET_HEADER_LEN 3u #define HSS_XYMODEM_PACKET_TRAILER 2u enum XYModem_Signals { XYMODEM_SOH = 0x01, XYMODEM_STX = 0x02, XYMODEM_ETX = 0x03, XYMODEM_EOT = 0x04, XYMODEM_ACK = 0x06, XYMODEM_NAK = 0x15, XYMODEM_CAN = 0x18, XYMODEM_C = 0x43, XYMODEM_GETCHAR_TIMEOUT = -1 }; /* * Each block of the transfer looks like: * <255-blk #><--128 data bytes--> * in which: * = 0x01 hex * = binary number, starts at 0x01 increments by 0x01, and * wraps 0FFH to 00H (not to 0x01) * <255-blk #> = blk # after going thru 8080 "CMA" instruction, i.e. * each bit complemented in the 8-bit block number. * Formally, this is the "ones complement". * * */ /***************************************************************************/ mss_uart_instance_t *g_my_uart = &g_mss_uart0_lo; static int16_t getchar_with_timeout_(int32_t timeout_sec) { uint8_t rx_byte = 0; int16_t result = 0; bool retval = uart_getchar(&rx_byte, timeout_sec, false); if (retval) { result = rx_byte; } else { result = -1; } return result; } static void putchar_(uint8_t tx_byte) { MSS_UART_polled_tx(g_my_uart, &tx_byte, 1); } /////////////////////////////////////////////////////////////////////////////////////////////////// struct XYModem_Packet { uint8_t startByte; uint8_t blkNum; uint8_t blkNumOnesComplement; char buffer[1024 + HSS_XYMODEM_PACKET_TRAILER]; // //uint8_t padding[3]; size_t length; }; struct XYModem_State { int protocol; union { struct { int syncFail:1; int endOfSession:1; int abort:1; } s; int done; } status; bool eotReceived; uint8_t lastReceivedBlkNum; uint8_t expectedBlkNum; size_t totalReceivedSize; size_t numReceivedPackets; size_t numNAKs; char filename[HSS_XYMODEM_MAX_FILENAME_LENGTH]; size_t expectedSize; size_t maxSize; }; /////////////////////////////////////////////////////////////////////////////////////////////////// static void XYMODEM_SendReadyChar(struct XYModem_State *pState) { if (pState->protocol == HSS_XYMODEM_PROTOCOL_YMODEM) { putchar_(XYMODEM_C); // explicitly request CRC16 mode } else { pState->numNAKs++; putchar_(XYMODEM_NAK); } } static void XYMODEM_SendCAN(void) { // two consequtive CAN characters without modem errors is transfer abort putchar_(XYMODEM_CAN); putchar_(XYMODEM_CAN); // YAM sends 8, for good measure putchar_(XYMODEM_CAN); putchar_(XYMODEM_CAN); putchar_(XYMODEM_CAN); putchar_(XYMODEM_CAN); putchar_(XYMODEM_CAN); putchar_(XYMODEM_CAN); } static void XYMODEM_Purge(int32_t timeout_sec) { // wait for line to clear // to prevent infinite loop here, we count down uint32_t max_loop_counter = 10u; while (getchar_with_timeout_(timeout_sec) != XYMODEM_GETCHAR_TIMEOUT) { --max_loop_counter; if (0u == max_loop_counter) { break; } } } static bool XYMODEM_ValidatePacket(struct XYModem_Packet *pPacket, struct XYModem_State *pState) { bool result = true; uint16_t crc16 = CRC16_calculate((const unsigned char *)pPacket->buffer, pPacket->length + HSS_XYMODEM_PACKET_TRAILER); if (crc16 != 0u) { // CRC failure result = false; } else if (pPacket->blkNum != (pPacket->blkNumOnesComplement ^ 0xFFu)) { // sequence failure result = false; } else if (pPacket->blkNum != pState->expectedBlkNum) { // sequence failure result = false; } return result; } static bool XYMODEM_ReadPacket(struct XYModem_Packet *pPacket, struct XYModem_State *pState) { bool result = true; bool synced = false; unsigned int syncAttempt = 0u; int timeout_sec = HSS_XYMODEM_PRE_SYNC_TIMEOUT_SEC; unsigned int can_rx_count = 0u; if (pState->status.done) { result = false; } else { // // Attempt to synchronize up to HSS_XYMODEM_MAX_SYNC_ATTEMPTS times // while (!synced && (syncAttempt < HSS_XYMODEM_MAX_SYNC_ATTEMPTS)) { int16_t rawStartByte = getchar_with_timeout_(timeout_sec); if ((rawStartByte >= 0) && (rawStartByte < 256)) { pPacket->startByte = (uint8_t)rawStartByte; } else { pPacket->startByte = 0u; } switch (rawStartByte) { case XYMODEM_SOH: can_rx_count = 0u; pPacket->length = 128u; synced = true; break; case XYMODEM_STX: can_rx_count = 0u; pPacket->length = 1024u; synced = true; break; case XYMODEM_EOT: can_rx_count = 0u; pPacket->length = 0u; //pState->status.s.endOfSession = true; pState->eotReceived= true; synced = true; syncAttempt = HSS_XYMODEM_MAX_SYNC_ATTEMPTS; break; case XYMODEM_ETX: // interactive CTRL-C pPacket->length = 0u; pState->status.s.abort = true; synced = false; syncAttempt = HSS_XYMODEM_MAX_SYNC_ATTEMPTS; break; case XYMODEM_CAN: // check again ++can_rx_count; if (can_rx_count == HSS_XYMODEM_CAN_COUNT_REQUIRED) { pPacket->length = 0u; pState->status.s.abort = true; synced = false; syncAttempt = HSS_XYMODEM_MAX_SYNC_ATTEMPTS; } else { ++syncAttempt; } break; case XYMODEM_GETCHAR_TIMEOUT: __attribute__((fallthrough)); // deliberate fallthrough default: //mHSS_DEBUG_PRINTF("%s(): %d: char is %0x\n", __func__, syncAttempt, // pPacket->startByte); can_rx_count = 0u; ++syncAttempt; synced = false; XYMODEM_SendReadyChar(pState); break; } } // // if synchronized, extract packet and validate it // if (pState->status.s.endOfSession) { result = true; } else if (synced) { timeout_sec = HSS_XYMODEM_POST_SYNC_TIMEOUT_SEC; pPacket->blkNum = getchar_with_timeout_(timeout_sec); pPacket->blkNumOnesComplement = getchar_with_timeout_(timeout_sec); ++(pState->numReceivedPackets); size_t i = 0u; while (i < pPacket->length) { pPacket->buffer[i] = getchar_with_timeout_(timeout_sec); ++i; } pPacket->buffer[i] = getchar_with_timeout_(timeout_sec); ++i; //crc_hi pPacket->buffer[i] = getchar_with_timeout_(timeout_sec); ++i; //crc_lo if (pState->status.done) { ; } else { if (pState->eotReceived) { ; } else if (XYMODEM_ValidatePacket(pPacket, pState)) { pState->lastReceivedBlkNum = pPacket->blkNum; ++(pState->expectedBlkNum); } else { // corrupt packet? result = false; } } } else { // not synchronized if (pState->status.s.abort) { result = true; } else { result = synced; } pPacket->length = 0u; pState->status.s.syncFail = true; } } //mHSS_DEBUG_PRINTF("%s(): returning %d\n", __func__, result); return result; } static size_t XYMODEM_GetFileSize(char *pStart, char *pEnd) { char *pChar = pStart; bool hunting = true; bool finished = false; size_t fileSize = 0u; // need to be careful not to go outside bounds while ((pChar < pEnd) && (!finished)) { switch (*pChar) { case 0: if (!hunting) { finished = true; } hunting = false; // found end of filename break; case '0' ... '9': if (!hunting) { fileSize = (fileSize * 10u) + (uint8_t)(*pChar - '0'); } break; case 32: if (!hunting) { finished = true; } break; default: if (!hunting) { finished = true; } break; } ++pChar; } return fileSize; } static size_t XYMODEM_Receive(int protocol, struct XYModem_State *pState, char *buffer, size_t bufferSize) { size_t result; uint8_t retries = 0u; // initialize state pState->status.done = 0; pState->lastReceivedBlkNum = 0u; pState->expectedBlkNum = 0u; pState->totalReceivedSize = 0u; pState->numReceivedPackets = 0u; pState->expectedSize = 0u; pState->maxSize = bufferSize; pState->protocol = protocol; // // Protocol starts with receiver sending a character to indicate to the sender that it is ready... // XYMODEM_SendReadyChar(pState); if (pState->protocol != HSS_XYMODEM_PROTOCOL_YMODEM) { pState->expectedBlkNum = 1; } static struct XYModem_Packet packet; // make this static, as it is contains a large buffer, //which is not friendly to the stack memset(&packet, 0, sizeof(packet)); // // main receive loop // retries = 0u; while (!pState->status.done && (retries < HSS_XYMODEM_BAD_PACKET_RETRIES)) { if (XYMODEM_ReadPacket(&packet, pState)) { putchar_(XYMODEM_ACK); if (!pState->status.done) { if ((pState->protocol == HSS_XYMODEM_PROTOCOL_YMODEM) && (pState->lastReceivedBlkNum == 0) && (pState->numReceivedPackets == 1u)) { memcpy(pState->filename, packet.buffer, HSS_XYMODEM_MAX_FILENAME_LENGTH-1); pState->expectedSize = XYMODEM_GetFileSize(packet.buffer, packet.buffer + ARRAY_SIZE(packet.buffer)); // if expected file size is known a priori, ensure we have enough buffer // space to receive and abort transfer early if (pState->expectedSize > pState->maxSize) { pState->status.s.abort = true; pState->totalReceivedSize = 0u; XYMODEM_SendCAN(); break; } } else if (pState->eotReceived) { // end of session pState->status.s.endOfSession = true; putchar_(XYMODEM_ACK); } else if ((pState->totalReceivedSize + packet.length) < pState->maxSize) { // dynamically ensure we have enough buffer space to receive, on each received chunk memcpy(buffer + pState->totalReceivedSize, packet.buffer, packet.length); pState->totalReceivedSize += packet.length; } else { pState->status.s.abort = true; pState->totalReceivedSize = 0u; XYMODEM_SendCAN(); break; } } else { // transfer is done if (pState->status.s.abort) { pState->totalReceivedSize = 0u; XYMODEM_SendCAN(); break; } else if (pState->status.s.endOfSession) { putchar_(XYMODEM_ACK); XYMODEM_Purge(HSS_XYMODEM_POST_SYNC_TIMEOUT_SEC); } } } else { // bad packet read ++retries; if (pState->numReceivedPackets) { XYMODEM_Purge(HSS_XYMODEM_POST_SYNC_TIMEOUT_SEC); pState->numNAKs++; putchar_(XYMODEM_NAK); } } } if (pState->expectedSize != 0u) { result = MIN(pState->expectedSize, pState->totalReceivedSize); } else { result = pState->totalReceivedSize; } XYMODEM_Purge(HSS_XYMODEM_POST_SYNC_TIMEOUT_SEC); if (retries >= HSS_XYMODEM_BAD_PACKET_RETRIES) { mHSS_DEBUG_PRINTF(LOG_ERROR, "maximum retries exceeded\n"); } if (pState->status.s.abort) { mHSS_DEBUG_PRINTF(LOG_ERROR, "Transfer aborted\n"); } return result; } size_t ymodem_receive(uint8_t *buffer, size_t bufferSize) { size_t result = 0u; struct XYModem_State state = { 0 }; memset(state.filename, 0, HSS_XYMODEM_MAX_FILENAME_LENGTH); result = XYMODEM_Receive(HSS_XYMODEM_PROTOCOL_YMODEM, &state, (char *)buffer, bufferSize); if (result != 0) { uint32_t crc32 = CRC32_calculate((const unsigned char *)buffer, result); mHSS_PRINTF("\n\nReceived %lu bytes from %s (CRC32 is 0x%08X)\n", result, state.filename, crc32); //mHSS_PRINTF("\n\nExpected %lu bytes in %lu packets (%lu NAKs)\n", state.expectedSize, // state.numReceivedPackets, state.numNAKs); } return result; } hart-software-services-2022.10/thirdparty/000077500000000000000000000000001432224323300204575ustar00rootroot00000000000000hart-software-services-2022.10/thirdparty/Kconfiglib/000077500000000000000000000000001432224323300225265ustar00rootroot00000000000000hart-software-services-2022.10/thirdparty/Kconfiglib/LICENSE.txt000066400000000000000000000013671432224323300243600ustar00rootroot00000000000000Copyright (c) 2011-2019, Ulf Magnusson Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. hart-software-services-2022.10/thirdparty/Kconfiglib/MANIFEST.in000066400000000000000000000001071432224323300242620ustar00rootroot00000000000000# Include the license file in source distributions include LICENSE.txt hart-software-services-2022.10/thirdparty/Kconfiglib/README.rst000066400000000000000000001130401432224323300242140ustar00rootroot00000000000000.. contents:: Table of contents :backlinks: none News ---- Dependency loop with recent linux-next kernels ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To fix issues with dependency loops on recent linux-next kernels, apply `this patch `_. Hopefully, it will be in ``linux-next`` soon. ``windows-curses`` is no longer automatically installed on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Starting with Kconfiglib 13.0.0, the `windows-curses `__ package is no longer automatically installed on Windows, and needs to be installed manually for the terminal ``menuconfig`` to work. This fixes installation of Kconfiglib on MSYS2, which is not compatible with ``windows-curses``. See `this issue `__. The ``menuconfig`` now shows a hint re. installing ``windows-curses`` when the ``curses`` module can't be imported on Windows. Sorry if this change caused problems! Overview -------- Kconfiglib is a `Kconfig `__ implementation in Python 2/3. It started out as a helper library, but now has a enough functionality to also work well as a standalone Kconfig implementation (including `terminal and GUI menuconfig interfaces `_ and `Kconfig extensions`_). The entire library is contained in `kconfiglib.py `_. The bundled scripts are implemented on top of it. Implementing your own scripts should be relatively easy, if needed. Kconfiglib is used exclusively by e.g. the `Zephyr `__, `esp-idf `__, and `ACRN `__ projects. It is also used for many small helper scripts in various projects. Since Kconfiglib is based around a library, it can be used e.g. to generate a `Kconfig cross-reference `_, using the same robust Kconfig parser used for other Kconfig tools, instead of brittle ad-hoc parsing. The documentation generation script can be found `here `__. Kconfiglib implements the recently added `Kconfig preprocessor `__. For backwards compatibility, environment variables can be referenced both as ``$(FOO)`` (the new syntax) and as ``$FOO`` (the old syntax). The old syntax is deprecated, but will probably be supported for a long time, as it's needed to stay compatible with older Linux kernels. The major version will be increased if support is ever dropped. Using the old syntax with an undefined environment variable keeps the string as is. Note: See `this issue `__ if you run into a "macro expanded to blank string" error with kernel 4.18+. See `this page `__ for some Kconfig tips and best practices. Installation ------------ Installation with pip ~~~~~~~~~~~~~~~~~~~~~ Kconfiglib is available on `PyPI `_ and can be installed with e.g. .. code:: $ pip(3) install kconfiglib Microsoft Windows is supported. The ``pip`` installation will give you both the base library and the following executables. All but two (``genconfig`` and ``setconfig``) mirror functionality available in the C tools. - `menuconfig `_ - `guiconfig `_ - `oldconfig `_ - `olddefconfig `_ - `savedefconfig `_ - `defconfig `_ - `alldefconfig `_ - `allnoconfig `_ - `allmodconfig `_ - `allyesconfig `_ - `listnewconfig `_ - `genconfig `_ - `setconfig `_ ``genconfig`` is intended to be run at build time. It generates a C header from the configuration and (optionally) information that can be used to rebuild only files that reference Kconfig symbols that have changed value. Starting with Kconfiglib version 12.2.0, all utilities are compatible with both Python 2 and Python 3. Previously, ``menuconfig.py`` only ran under Python 3 (i.e., it's now more backwards compatible than before). **Note:** If you install Kconfiglib with ``pip``'s ``--user`` flag, make sure that your ``PATH`` includes the directory where the executables end up. You can list the installed files with ``pip(3) show -f kconfiglib``. All releases have a corresponding tag in the git repository, e.g. ``v14.1.0`` (the latest version). `Semantic versioning `_ is used. There's been ten small changes to the behavior of the API, a Windows packaging change, and a hashbang change to use ``python3`` (`1 `_, `2 `_, `3 `_, `4 `_, `5 `_, `6 `_, `7 `_, `8 `_, `9 `_, `10 `_, `Windows packaging change `_, `Python 3 hashbang change `_), which is why the major version is at 14 rather than 2. I do major version bumps for all behavior changes, even tiny ones, and most of these were fixes for baby issues in the early days of the Kconfiglib 2 API. Manual installation ~~~~~~~~~~~~~~~~~~~ Just drop ``kconfiglib.py`` and the scripts you want somewhere. There are no third-party dependencies, but the terminal ``menuconfig`` won't work on Windows unless a package like `windows-curses `__ is installed. Installation for the Linux kernel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See the module docstring at the top of `kconfiglib.py `_. Python version compatibility (2.7/3.2+) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Kconfiglib and all utilities run under both Python 2.7 and Python 3.2 and later. The code mostly uses basic Python features and has no third-party dependencies, so keeping it backwards-compatible is pretty low effort. The 3.2 requirement comes from ``argparse``. ``format()`` with unnumbered ``{}`` is used as well. A recent Python 3 version is recommended if you have a choice, as it'll give you better Unicode handling. Getting started --------------- 1. `Install `_ the library and the utilities. 2. Write `Kconfig `__ files that describe the available configuration options. See `this page `__ for some general Kconfig advice. 3. Generate an initial configuration with e.g. ``menuconfig``/``guiconfig`` or ``alldefconfig``. The configuration is saved as ``.config`` by default. For more advanced projects, the ``defconfig`` utility can be used to generate the initial configuration from an existing configuration file. Usually, this existing configuration file would be a minimal configuration file, as generated by e.g. ``savedefconfig``. 4. Run ``genconfig`` to generate a header file. By default, it is saved as ``config.h``. Normally, ``genconfig`` would be run automatically as part of the build. Before writing a header file or other configuration output, Kconfiglib compares the old contents of the file against the new contents. If there's no change, the write is skipped. This avoids updating file metadata like the modification time, and might save work depending on your build setup. Adding new configuration output formats should be relatively straightforward. See the implementation of ``write_config()`` in `kconfiglib.py `_. The documentation for the ``Symbol.config_string`` property has some tips as well. 5. To update an old ``.config`` file after the Kconfig files have changed (e.g. to add new options), run ``oldconfig`` (prompts for values for new options) or ``olddefconfig`` (gives new options their default value). Entering the ``menuconfig`` or ``guiconfig`` interface and saving the configuration will also update it (the configuration interfaces always prompt for saving on exit if it would modify the contents of the ``.config`` file). Due to Kconfig semantics, simply loading an old ``.config`` file performs an implicit ``olddefconfig``, so building will normally not be affected by having an outdated configuration. Whenever ``.config`` is overwritten, the previous version of the file is saved to ``.config.old`` (or, more generally, to ``$KCONFIG_CONFIG.old``). Using ``.config`` files as Make input ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``.config`` files use Make syntax and can be included directly in Makefiles to read configuration values from there. This is why ``n``-valued ``bool``/``tristate`` values are written out as ``# CONFIG_FOO is not set`` (a Make comment) in ``.config``, allowing them to be tested with ``ifdef`` in Make. If you make use of this, you might want to pass ``--config-out `` to ``genconfig`` and include the configuration file it generates instead of including ``.config`` directly. This has the advantage that the generated configuration file will always be a "full" configuration file, even if ``.config`` is outdated. Otherwise, it might be necessary to run ``old(def)config`` or ``menuconfig``/``guiconfig`` before rebuilding with an outdated ``.config``. If you use ``--sync-deps`` to generate incremental build information, you can include ``deps/auto.conf`` instead, which is also a full configuration file. Useful helper macros ~~~~~~~~~~~~~~~~~~~~ The `include/linux/kconfig.h `_ header in the Linux kernel defines some useful helper macros for testing Kconfig configuration values. ``IS_ENABLED()`` is generally useful, allowing configuration values to be tested in ``if`` statements with no runtime overhead. Incremental building ~~~~~~~~~~~~~~~~~~~~ See the docstring for ``Kconfig.sync_deps()`` in `kconfiglib.py `_ for hints on implementing incremental builds (rebuilding just source files that reference changed configuration values). Running the ``scripts/basic/fixdep.c`` tool from the kernel on the output of ``gcc -MD `` might give you an idea of how it all fits together. Library documentation --------------------- Kconfiglib comes with extensive documentation in the form of docstrings. To view it, run e.g. the following command: .. code:: sh $ pydoc(3) kconfiglib For HTML output, add ``-w``: .. code:: sh $ pydoc(3) -w kconfiglib This will also work after installing Kconfiglib with ``pip(3)``. Documentation for other modules can be viewed in the same way (though a plain ``--help`` will work when they're run as executables): .. code:: sh $ pydoc(3) menuconfig/guiconfig/... A good starting point for learning the library is to read the module docstring (which you could also just read directly at the beginning of `kconfiglib.py `_). It gives an introduction to symbol values, the menu tree, and expressions. After reading the module docstring, a good next step is to read the ``Kconfig`` class documentation, and then the documentation for the ``Symbol``, ``Choice``, and ``MenuNode`` classes. Please tell me if something is unclear or can be explained better. Library features ---------------- Kconfiglib can do the following, among other things: - **Programmatically get and set symbol values** See `allnoconfig.py `_ and `allyesconfig.py `_, which are automatically verified to produce identical output to the standard ``make allnoconfig`` and ``make allyesconfig``. - **Read and write .config and defconfig files** The generated ``.config`` and ``defconfig`` (minimal configuration) files are character-for-character identical to what the C implementation would generate (except for the header comment). The test suite relies on this, as it compares the generated files. - **Write C headers** The generated headers use the same format as ``include/generated/autoconf.h`` from the Linux kernel. Output for symbols appears in the order that they're defined, unlike in the C tools (where the order depends on the hash table implementation). - **Implement incremental builds** This uses the same scheme as the ``include/config`` directory in the kernel: Symbols are translated into files that are touched when the symbol's value changes between builds, which can be used to avoid having to do a full rebuild whenever the configuration is changed. See the ``sync_deps()`` function for more information. - **Inspect symbols** Printing a symbol or other item (which calls ``__str__()``) returns its definition in Kconfig format. This also works for symbols defined in multiple locations. A helpful ``__repr__()`` is on all objects too. All ``__str__()`` and ``__repr__()`` methods are deliberately implemented with just public APIs, so all symbol information can be fetched separately as well. - **Inspect expressions** Expressions use a simple tuple-based format that can be processed manually if needed. Expression printing and evaluation functions are provided, implemented with public APIs. - **Inspect the menu tree** The underlying menu tree is exposed, including submenus created implicitly from symbols depending on preceding symbols. This can be used e.g. to implement menuconfig-like functionality. See `menuconfig.py `_/`guiconfig.py `_ and the minimalistic `menuconfig_example.py `_ example. Kconfig extensions ~~~~~~~~~~~~~~~~~~ The following Kconfig extensions are available: - ``source`` supports glob patterns and includes each matching file. A pattern is required to match at least one file. A separate ``osource`` statement is available for cases where it's okay for the pattern to match no files (in which case ``osource`` turns into a no-op). - A relative ``source`` statement (``rsource``) is available, where file paths are specified relative to the directory of the current Kconfig file. An ``orsource`` statement is available as well, analogous to ``osource``. - Preprocessor user functions can be defined in Python, which makes it simple to integrate information from existing Python tools into Kconfig (e.g. to have Kconfig symbols depend on hardware information stored in some other format). See the *Kconfig extensions* section in the `kconfiglib.py `_ module docstring for more information. - ``def_int``, ``def_hex``, and ``def_string`` are available in addition to ``def_bool`` and ``def_tristate``, allowing ``int``, ``hex``, and ``string`` symbols to be given a type and a default at the same time. These can be useful in projects that make use of symbols defined in multiple locations, and remove some Kconfig inconsistency. - Environment variables are expanded directly in e.g. ``source`` and ``mainmenu`` statements, meaning ``option env`` symbols are redundant. This is the standard behavior with the new `Kconfig preprocessor `__, which Kconfiglib implements. ``option env`` symbols are accepted but ignored, which leads the caveat that they must have the same name as the environment variables they reference (Kconfiglib warns if the names differ). This keeps Kconfiglib compatible with older Linux kernels, where the name of the ``option env`` symbol always matched the environment variable. Compatibility with older Linux kernels is the main reason ``option env`` is still supported. The C tools have dropped support for ``option env``. - Two extra optional warnings can be enabled by setting environment variables, covering cases that are easily missed when making changes to Kconfig files: * ``KCONFIG_WARN_UNDEF``: If set to ``y``, warnings will be generated for all references to undefined symbols within Kconfig files. The only gotcha is that all hex literals must be prefixed with ``0x`` or ``0X``, to make it possible to distinguish them from symbol references. Some projects (e.g. the Linux kernel) use multiple Kconfig trees with many shared Kconfig files, leading to some safe undefined symbol references. ``KCONFIG_WARN_UNDEF`` is useful in projects that only have a single Kconfig tree though. ``KCONFIG_STRICT`` is an older alias for this environment variable, supported for backwards compatibility. * ``KCONFIG_WARN_UNDEF_ASSIGN``: If set to ``y``, warnings will be generated for all assignments to undefined symbols within ``.config`` files. By default, no such warnings are generated. This warning can also be enabled/disabled by setting ``Kconfig.warn_assign_undef`` to ``True``/``False``. Other features -------------- - **Single-file implementation** The entire library is contained in `kconfiglib.py `_. The tools implemented on top of it are one file each. - **Robust and highly compatible with the C Kconfig tools**  The `test suite `_ automatically compares output from Kconfiglib and the C tools by diffing the generated ``.config`` files for the real kernel Kconfig and defconfig files, for all ARCHes. This currently involves comparing the output for 36 ARCHes and 498 defconfig files (or over 18000 ARCH/defconfig combinations in "obsessive" test suite mode). All tests are expected to pass. A comprehensive suite of selftests is included as well. - **Not horribly slow despite being a pure Python implementation** The `allyesconfig.py `_ script currently runs in about 1.3 seconds on the Linux kernel on a Core i7 2600K (with a warm file cache), including the ``make`` overhead from ``make scriptconfig``. Note that the Linux kernel Kconfigs are absolutely massive (over 14k symbols for x86) compared to most projects, and also have overhead from running shell commands via the Kconfig preprocessor. Kconfiglib is especially speedy in cases where multiple ``.config`` files need to be processed, because the ``Kconfig`` files will only need to be parsed once. For long-running jobs, `PyPy `_ gives a big performance boost. CPython is faster for short-running jobs as PyPy needs some time to warm up. Kconfiglib also works well with the `multiprocessing `_ module. No global state is kept. - **Generates more warnings than the C implementation** Generates the same warnings as the C implementation, plus additional ones. Also detects dependency and ``source`` loops. All warnings point out the location(s) in the ``Kconfig`` files where a symbol is defined, where applicable. - **Unicode support** Unicode characters in string literals in ``Kconfig`` and ``.config`` files are correctly handled. This support mostly comes for free from Python. - **Windows support** Nothing Linux-specific is used. Universal newlines mode is used for both Python 2 and Python 3. The `Zephyr `_ project uses Kconfiglib to generate ``.config`` files and C headers on Linux as well as Windows. - **Internals that (mostly) mirror the C implementation** While being simpler to understand and tweak. Menuconfig interfaces --------------------- Three configuration interfaces are currently available: - `menuconfig.py `_ is a terminal-based configuration interface implemented using the standard Python ``curses`` module. ``xconfig`` features like showing invisible symbols and showing symbol names are included, and it's possible to jump directly to a symbol in the menu tree (even if it's currently invisible). .. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/menuconfig.gif *There is now also a show-help mode that shows the help text of the currently selected symbol in the help window at the bottom.* Starting with Kconfiglib 12.2.0, ``menuconfig.py`` runs under both Python 2 and Python 3 (previously, it only ran under Python 3, so this was a backport). Running it under Python 3 provides better support for Unicode text entry (``get_wch()`` is not available in the ``curses`` module on Python 2). There are no third-party dependencies on \*nix. On Windows, the ``curses`` modules is not available by default, but support can be added by installing the ``windows-curses`` package: .. code-block:: shell $ pip install windows-curses This uses wheels built from `this repository `_, which is in turn based on Christoph Gohlke's `Python Extension Packages for Windows `_. See the docstring at the top of `menuconfig.py `_ for more information about the terminal menuconfig implementation. - `guiconfig.py `_ is a graphical configuration interface written in `Tkinter `_. Like ``menuconfig.py``, it supports showing all symbols (with invisible symbols in red) and jumping directly to symbols. Symbol values can also be changed directly from the jump-to dialog. When single-menu mode is enabled, a single menu is shown at a time, like in the terminal menuconfig. Only this mode distinguishes between symbols defined with ``config`` and symbols defined with ``menuconfig``. ``guiconfig.py`` has been tested on X11, Windows, and macOS, and is compatible with both Python 2 and Python 3. Despite being part of the Python standard library, ``tkinter`` often isn't included by default in Python installations on Linux. These commands will install it on a few different distributions: - Ubuntu: ``sudo apt install python-tk``/``sudo apt install python3-tk`` - Fedora: ``dnf install python2-tkinter``/``dnf install python3-tkinter`` - Arch: ``sudo pacman -S tk`` - Clear Linux: ``sudo swupd bundle-add python3-tcl`` Screenshot below, with show-all mode enabled and the jump-to dialog open: .. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/guiconfig.png To avoid having to carry around a bunch of GIFs, the image data is embedded in ``guiconfig.py``. To use separate GIF files instead, change ``_USE_EMBEDDED_IMAGES`` to ``False`` in ``guiconfig.py``. The image files can be found in the `screenshots `_ branch. I did my best with the images, but some are definitely only art adjacent. Touch-ups are welcome. :) - `pymenuconfig `_, built by `RomaVis `_, is an older portable Python 2/3 TkInter menuconfig implementation. Screenshot below: .. image:: https://raw.githubusercontent.com/RomaVis/pymenuconfig/master/screenshot.PNG While working on the terminal menuconfig implementation, I added a few APIs to Kconfiglib that turned out to be handy. ``pymenuconfig`` predates ``menuconfig.py`` and ``guiconfig.py``, and so didn't have them available. Blame me for any workarounds. Examples -------- Example scripts ~~~~~~~~~~~~~~~ The `examples/ `_ directory contains some simple example scripts. Among these are the following ones. Make sure you run them with the latest version of Kconfiglib, as they might make use of newly added features. - `eval_expr.py `_ evaluates an expression in the context of a configuration. - `find_symbol.py `_ searches through expressions to find references to a symbol, also printing a "backtrace" with parents for each reference found. - `help_grep.py `_ searches for a string in all help texts. - `print_tree.py `_ prints a tree of all configuration items. - `print_config_tree.py `_ is similar to ``print_tree.py``, but dumps the tree as it would appear in ``menuconfig``, including values. This can be handy for visually diffing between ``.config`` files and different versions of ``Kconfig`` files. - `list_undefined.py `_ finds references to symbols that are not defined by any architecture in the Linux kernel. - `merge_config.py `_ merges configuration fragments to produce a complete .config, similarly to ``scripts/kconfig/merge_config.sh`` from the kernel. - `menuconfig_example.py `_ implements a configuration interface that uses notation similar to ``make menuconfig``. It's deliberately kept as simple as possible to demonstrate just the core concepts. Real-world examples ~~~~~~~~~~~~~~~~~~~ - `kconfig.py `_ from the `Zephyr `_ project handles ``.config`` and header file generation, also doing configuration fragment merging - `genrest.py `_ generates a Kconfig symbol cross-reference, which can be viewed `here `__ - `CMake and IDE integration `_ from the ESP-IDF project, via a configuration server program. - `A script for turning on USB-related options `_, from the `syzkaller `_ project. - `Various automated checks `_, including a check for references to undefined Kconfig symbols in source code. See the ``KconfigCheck`` class. - `Various utilities `_ from the `ACRN `_ project These use the older Kconfiglib 1 API, which was clunkier and not as general (functions instead of properties, no direct access to the menu structure or properties, uglier ``__str__()`` output): - `genboardscfg.py `_ from `Das U-Boot `_ generates some sort of legacy board database by pulling information from a newly added Kconfig-based configuration system (as far as I understand it :). - `gen-manual-lists.py `_ generated listings for an appendix in the `Buildroot `_ manual. (The listing has since been removed.) - `gen_kconfig_doc.py `_ from the `esp-idf `_ project generates documentation from Kconfig files. - `SConf `_ builds an interactive configuration interface (like ``menuconfig``) on top of Kconfiglib, for use e.g. with `SCons `_. - `kconfig-diff.py `_ -- a script by `dubiousjim `_ that compares kernel configurations. - Originally, Kconfiglib was used in chapter 4 of my `master's thesis `_ to automatically generate a "minimal" kernel for a given system. Parts of it bother me a bit now, but that's how it goes with old work. Sample ``make iscriptconfig`` session ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following log should give some idea of the functionality available in the API: .. code-block:: $ make iscriptconfig A Kconfig instance 'kconf' for the architecture x86 has been created. >>> kconf # Calls Kconfig.__repr__() >>> kconf.mainmenu_text # Expanded main menu text 'Linux/x86 4.14.0-rc7 Kernel Configuration' >>> kconf.top_node # The implicit top-level menu >>> kconf.top_node.list # First child menu node >>> print(kconf.top_node.list) # Calls MenuNode.__str__() config SRCARCH string option env="SRCARCH" default "x86" >>> sym = kconf.top_node.list.next.item # Item contained in next menu node >>> print(sym) # Calls Symbol.__str__() config 64BIT bool "64-bit kernel" if ARCH = "x86" default ARCH != "i386" help Say yes to build a 64-bit kernel - formerly known as x86_64 Say no to build a 32-bit kernel - formerly known as i386 >>> sym # Calls Symbol.__repr__() >>> sym.assignable # Currently assignable values (0, 1, 2 = n, m, y) (0, 2) >>> sym.set_value(0) # Set it to n True >>> sym.tri_value # Check the new value 0 >>> sym = kconf.syms["X86_MPPARSE"] # Look up symbol by name >>> print(sym) config X86_MPPARSE bool "Enable MPS table" if (ACPI || SFI) && X86_LOCAL_APIC default y if X86_LOCAL_APIC help For old smp systems that do not have proper acpi support. Newer systems (esp with 64bit cpus) with acpi support, MADT and DSDT will override it >>> default = sym.defaults[0] # Fetch its first default >>> sym = default[1] # Fetch the default's condition (just a Symbol here) >>> print(sym) config X86_LOCAL_APIC bool default y select IRQ_DOMAIN_HIERARCHY select PCI_MSI_IRQ_DOMAIN if PCI_MSI depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI >>> sym.nodes # Show the MenuNode(s) associated with it [] >>> kconfiglib.expr_str(sym.defaults[0][1]) # Print the default's condition 'X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI' >>> kconfiglib.expr_value(sym.defaults[0][1]) # Evaluate it (0 = n) 0 >>> kconf.syms["64BIT"].set_value(2) True >>> kconfiglib.expr_value(sym.defaults[0][1]) # Evaluate it again (2 = y) 2 >>> kconf.write_config("myconfig") # Save a .config >>> ^D $ cat myconfig # Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) CONFIG_64BIT=y CONFIG_X86_64=y CONFIG_X86=y CONFIG_INSTRUCTION_DECODER=y CONFIG_OUTPUT_FORMAT="elf64-x86-64" CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" CONFIG_LOCKDEP_SUPPORT=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_MMU=y ... Test suite ---------- The test suite is run with .. code:: $ python(3) Kconfiglib/testsuite.py `pypy `_ works too, and is much speedier for everything except ``allnoconfig.py``/``allnoconfig_simpler.py``/``allyesconfig.py``, where it doesn't have time to warm up since the scripts are run via ``make scriptconfig``. The test suite must be run from the top-level kernel directory. It requires that the Kconfiglib git repository has been cloned into it and that the makefile patch has been applied. To get rid of warnings generated for the kernel ``Kconfig`` files, add ``2>/dev/null`` to the command to discard ``stderr``. **NOTE: Forgetting to apply the Makefile patch will cause some tests that compare generated configurations to fail** **NOTE: The test suite overwrites .config in the kernel root, so make sure to back it up.** The test suite consists of a set of selftests and a set of compatibility tests that compare configurations generated by Kconfiglib with configurations generated by the C tools, for a number of cases. See `testsuite.py `_ for the available options. The `tests/reltest `_ script runs the test suite and all the example scripts for both Python 2 and Python 3, verifying that everything works. Rarely, the output from the C tools is changed slightly (most recently due to a `change `_ I added). If you get test suite failures, try running the test suite again against the `linux-next tree `_, which has all the latest changes. I will make it clear if any non-backwards-compatible changes appear. A lot of time is spent waiting around for ``make`` and the C utilities (which need to reparse all the Kconfig files for each defconfig test). Adding some multiprocessing to the test suite would make sense too. Notes ----- * This is version 2 of Kconfiglib, which is not backwards-compatible with Kconfiglib 1. A summary of changes between Kconfiglib 1 and Kconfiglib 2 can be found `here `__. * I sometimes see people add custom output formats, which is pretty straightforward to do (see the implementations of ``write_autoconf()`` and ``write_config()`` for a template, and also the documentation of the ``Symbol.config_string`` property). If you come up with something you think might be useful to other people, I'm happy to take it in upstream. Batteries included and all that. * Kconfiglib assumes the modules symbol is ``MODULES``, which is backwards-compatible. A warning is printed by default if ``option modules`` is set on some other symbol. Let me know if you need proper ``option modules`` support. It wouldn't be that hard to add. Thanks ------ - To `RomaVis `_, for making `pymenuconfig `_ and suggesting the ``rsource`` keyword. - To `Mitja Horvat `_, for adding support for user-defined styles to the terminal menuconfig. - To `Philip Craig `_ for adding support for the ``allnoconfig_y`` option and fixing an obscure issue with ``comment``\s inside ``choice``\s (that didn't affect correctness but made outputs differ). ``allnoconfig_y`` is used to force certain symbols to ``y`` during ``make allnoconfig`` to improve coverage. License ------- See `LICENSE.txt `_. SPDX license identifiers are used in the source code. hart-software-services-2022.10/thirdparty/Kconfiglib/alldefconfig.py000077500000000000000000000011371432224323300255220ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2018-2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Writes a configuration file where all symbols are set to their their default values. The default output filename is '.config'. A different filename can be passed in the KCONFIG_CONFIG environment variable. Usage for the Linux kernel: $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/alldefconfig.py """ import kconfiglib def main(): kconf = kconfiglib.standard_kconfig(__doc__) kconf.load_allconfig("alldef.config") print(kconf.write_config()) if __name__ == "__main__": main() hart-software-services-2022.10/thirdparty/Kconfiglib/allmodconfig.py000077500000000000000000000023061432224323300255420ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2018-2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Writes a configuration file where as many symbols as possible are set to 'm'. The default output filename is '.config'. A different filename can be passed in the KCONFIG_CONFIG environment variable. Usage for the Linux kernel: $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/allmodconfig.py """ import kconfiglib def main(): kconf = kconfiglib.standard_kconfig(__doc__) # See allnoconfig.py kconf.warn = False for sym in kconf.unique_defined_syms: if sym.orig_type == kconfiglib.BOOL: # 'bool' choice symbols get their default value, as determined by # e.g. 'default's on the choice if not sym.choice: # All other bool symbols get set to 'y', like for allyesconfig sym.set_value(2) elif sym.orig_type == kconfiglib.TRISTATE: sym.set_value(1) for choice in kconf.unique_choices: choice.set_value(2 if choice.orig_type == kconfiglib.BOOL else 1) kconf.warn = True kconf.load_allconfig("allmod.config") print(kconf.write_config()) if __name__ == "__main__": main() hart-software-services-2022.10/thirdparty/Kconfiglib/allnoconfig.py000077500000000000000000000023021432224323300253730ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2018-2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Writes a configuration file where as many symbols as possible are set to 'n'. The default output filename is '.config'. A different filename can be passed in the KCONFIG_CONFIG environment variable. Usage for the Linux kernel: $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/allnoconfig.py """ # See examples/allnoconfig_walk.py for another way to implement this script import kconfiglib def main(): kconf = kconfiglib.standard_kconfig(__doc__) # Avoid warnings that would otherwise get printed by Kconfiglib for the # following: # # 1. Assigning a value to a symbol without a prompt, which never has any # effect # # 2. Assigning values invalid for the type (only bool/tristate symbols # accept 0/1/2, for n/m/y). The assignments will be ignored for other # symbol types, which is what we want. kconf.warn = False for sym in kconf.unique_defined_syms: sym.set_value(2 if sym.is_allnoconfig_y else 0) kconf.warn = True kconf.load_allconfig("allno.config") print(kconf.write_config()) if __name__ == "__main__": main() hart-software-services-2022.10/thirdparty/Kconfiglib/allyesconfig.py000077500000000000000000000032261432224323300255650ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2018-2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Writes a configuration file where as many symbols as possible are set to 'y'. The default output filename is '.config'. A different filename can be passed in the KCONFIG_CONFIG environment variable. Usage for the Linux kernel: $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/allyesconfig.py """ import kconfiglib def main(): kconf = kconfiglib.standard_kconfig(__doc__) # See allnoconfig.py kconf.warn = False # Try to set all symbols to 'y'. Dependencies might truncate the value down # later, but this will at least give the highest possible value. # # Assigning 0/1/2 to non-bool/tristate symbols has no effect (int/hex # symbols still take a string, because they preserve formatting). for sym in kconf.unique_defined_syms: # Set choice symbols to 'm'. This value will be ignored for choices in # 'y' mode (the "normal" mode), which will instead just get their # default selection, but will set all symbols in m-mode choices to 'm', # which is as high as they can go. # # Here's a convoluted example of how you might get an m-mode choice # even during allyesconfig: # # choice # tristate "weird choice" # depends on m sym.set_value(1 if sym.choice else 2) # Set all choices to the highest possible mode for choice in kconf.unique_choices: choice.set_value(2) kconf.warn = True kconf.load_allconfig("allyes.config") print(kconf.write_config()) if __name__ == "__main__": main() hart-software-services-2022.10/thirdparty/Kconfiglib/defconfig.py000077500000000000000000000022001432224323300250210ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Reads a specified configuration file, then writes a new configuration file. This can be used to initialize the configuration from e.g. an arch-specific configuration file. This input configuration file would usually be a minimal configuration file, as generated by e.g. savedefconfig. The default output filename is '.config'. A different filename can be passed in the KCONFIG_CONFIG environment variable. """ import argparse import kconfiglib def main(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__) parser.add_argument( "--kconfig", default="Kconfig", help="Top-level Kconfig file (default: Kconfig)") parser.add_argument( "config", metavar="CONFIGURATION", help="Input configuration file") args = parser.parse_args() kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True) print(kconf.load_config(args.config)) print(kconf.write_config()) if __name__ == "__main__": main() hart-software-services-2022.10/thirdparty/Kconfiglib/examples/000077500000000000000000000000001432224323300243445ustar00rootroot00000000000000hart-software-services-2022.10/thirdparty/Kconfiglib/examples/Kmenuconfig000066400000000000000000000030001432224323300265250ustar00rootroot00000000000000mainmenu "Example Kconfig configuration" config MODULES bool "Enable loadable module support" option modules default y menu "Bool and tristate symbols" config BOOL bool "Bool symbol" default y config BOOL_DEP bool "Dependent bool symbol" depends on BOOL # Mix it up a bit with an 'if' instead of a 'depends on' if BOOL config TRI_DEP tristate "Dependent tristate symbol" select SELECTED_BY_TRI_DEP imply IMPLIED_BY_TRI_DEP endif config TWO_MENU_NODES bool "First prompt" depends on BOOL config TRI tristate "Tristate symbol" config TWO_MENU_NODES bool "Second prompt" comment "These are selected by TRI_DEP" config SELECTED_BY_TRI_DEP tristate "Tristate selected by TRI_DEP" config IMPLIED_BY_TRI_DEP tristate "Tristate implied by TRI_DEP" endmenu menu "String, int, and hex symbols" config STRING string "String symbol" default "foo" config INT int "Int symbol" default 747 config HEX hex "Hex symbol" default 0xABC endmenu menu "Various choices" choice BOOL_CHOICE bool "Bool choice" config BOOL_CHOICE_SYM_1 bool "Bool choice sym 1" config BOOL_CHOICE_SYM_2 bool "Bool choice sym 2" endchoice choice TRI_CHOICE tristate "Tristate choice" config TRI_CHOICE_SYM_1 tristate "Tristate choice sym 1" config TRI_CHOICE_SYM_2 tristate "Tristate choice sym 2" endchoice choice OPT_BOOL_CHOICE bool "Optional bool choice" optional config OPT_BOOL_CHOICE_SYM_1 bool "Optional bool choice sym 1" config OPT_BOOL_CHOICE_SYM_2 bool "Optional bool choice sym 2" endchoice endmenu hart-software-services-2022.10/thirdparty/Kconfiglib/examples/allnoconfig_walk.py000066400000000000000000000036701432224323300302350ustar00rootroot00000000000000# This is tree-walking version of allnoconfig.py, for demonstration purposes. # Verified by the test suite to generate identical output to 'make allnoconfig' # for all ARCHes. # # Note: A more practical version would use Kconfig.node_iter(). The manual tree # walking is for demonstration purposes. # # Usage for the Linux kernel: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/allnoconfig_walk.py import sys from kconfiglib import Kconfig, Symbol def do_allnoconfig(node): global changed # Walk the tree of menu nodes. You can imagine this as going down/into menu # entries in the menuconfig interface, setting each to n (or the lowest # assignable value). while node: if isinstance(node.item, Symbol): sym = node.item # Is the symbol a non-allnoconfig_y symbol that can be set to a # lower value than its current value? if (not sym.is_allnoconfig_y and sym.assignable and sym.assignable[0] < sym.tri_value): # Yup, lower it sym.set_value(sym.assignable[0]) changed = True # Recursively lower children if node.list: do_allnoconfig(node.list) node = node.next # Parse the Kconfig files kconf = Kconfig(sys.argv[1]) # Do an initial pass to set 'option allnoconfig_y' symbols to y for sym in kconf.unique_defined_syms: if sym.is_allnoconfig_y: sym.set_value(2) while True: # Changing later symbols in the configuration can sometimes allow earlier # symbols to be lowered, e.g. if a later symbol 'select's an earlier # symbol. To handle such situations, we do additional passes over the tree # until we're no longer able to change the value of any symbol in a pass. changed = False do_allnoconfig(kconf.top_node) # Did the pass change any symbols? if not changed: break print(kconf.write_config()) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/defconfig_oldconfig.py000066400000000000000000000016061432224323300306710ustar00rootroot00000000000000# Produces exactly the same output as the following script: # # make defconfig # echo CONFIG_ETHERNET=n >> .config # make oldconfig # echo CONFIG_ETHERNET=y >> .config # yes n | make oldconfig # # This came up in https://github.com/ulfalizer/Kconfiglib/issues/15. # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/defconfig_oldconfig.py import sys import kconfiglib kconf = kconfiglib.Kconfig(sys.argv[1]) # Mirrors defconfig kconf.load_config("arch/x86/configs/x86_64_defconfig") kconf.write_config() # Mirrors the first oldconfig kconf.load_config() kconf.syms["ETHERNET"].set_value(0) kconf.write_config() # Mirrors the second oldconfig kconf.load_config() kconf.syms["ETHERNET"].set_value(2) for s in kconf.unique_defined_syms: if s.user_value is None and 0 in s.assignable: s.set_value(0) # Write the final configuration print(kconf.write_config()) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/dumpvars.py000066400000000000000000000007171432224323300265640ustar00rootroot00000000000000# Prints all (set) environment variables referenced in the Kconfig files # together with their values, as a list of assignments. # # Note: This only works for environment variables referenced via the $(FOO) # preprocessor syntax. The older $FOO syntax is maintained for backwards # compatibility. import os import sys import kconfiglib print(" ".join("{}='{}'".format(var, os.environ[var]) for var in kconfiglib.Kconfig(sys.argv[1]).env_vars)) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/eval_expr.py000066400000000000000000000012031432224323300266770ustar00rootroot00000000000000# Evaluates an expression (e.g. "X86_64 || (X86_32 && X86_LOCAL_APIC)") in the # context of a configuration. Note that this always yields a tristate value (n, # m, or y). # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/eval_expr.py SCRIPT_ARG= import sys import kconfiglib if len(sys.argv) < 3: sys.exit("Pass the expression to evaluate with SCRIPT_ARG=") kconf = kconfiglib.Kconfig(sys.argv[1]) expr = sys.argv[2] # Enable modules so that m doesn't get demoted to n kconf.modules.set_value(2) print("the expression '{}' evaluates to {}" .format(expr, kconf.eval_string(expr))) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/find_symbol.py000066400000000000000000000065551432224323300272360ustar00rootroot00000000000000# Prints all menu nodes that reference a given symbol any of their properties # or property conditions, along with their parent menu nodes. # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/find_symbol.py SCRIPT_ARG= # # Example output for SCRIPT_ARG=X86: # # Found 470 locations that reference X86: # # ========== Location 1 (init/Kconfig:1108) ========== # # config SGETMASK_SYSCALL # bool # prompt "sgetmask/ssetmask syscalls support" if EXPERT # default PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH # help # sys_sgetmask and sys_ssetmask are obsolete system calls # no longer supported in libc but still enabled by default in some # architectures. # # If unsure, leave the default option here. # # ---------- Parent 1 (init/Kconfig:1077) ---------- # # menuconfig EXPERT # bool # prompt "Configure standard kernel features (expert users)" # select DEBUG_KERNEL # help # This option allows certain base kernel options and settings # to be disabled or tweaked. This is for specialized # environments which can tolerate a "non-standard" kernel. # Only use this if you really know what you are doing. # # ---------- Parent 2 (init/Kconfig:39) ---------- # # menu "General setup" # # ========== Location 2 (arch/Kconfig:29) ========== # # config OPROFILE_EVENT_MULTIPLEX # bool # prompt "OProfile multiplexing support (EXPERIMENTAL)" # default "n" # depends on OPROFILE && X86 # help # The number of hardware counters is limited. The multiplexing # feature enables OProfile to gather more events than counters # are provided by the hardware. This is realized by switching # between events at a user specified time interval. # # If unsure, say N. # # ---------- Parent 1 (arch/Kconfig:16) ---------- # # config OPROFILE # tristate # prompt "OProfile system profiling" # select RING_BUFFER # select RING_BUFFER_ALLOW_SWAP # depends on PROFILING && HAVE_OPROFILE # help # OProfile is a profiling system capable of profiling the # whole system, include the kernel, kernel modules, libraries, # and applications. # # If unsure, say N. # # ---------- Parent 2 (init/Kconfig:39) ---------- # # menu "General setup" # # ... (tons more) import sys import kconfiglib if len(sys.argv) < 3: sys.exit('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=') kconf = kconfiglib.Kconfig(sys.argv[1]) sym_name = sys.argv[2] if sym_name not in kconf.syms: print("No symbol {} exists in the configuration".format(sym_name)) sys.exit(0) referencing = [node for node in kconf.node_iter() if kconf.syms[sym_name] in node.referenced] if not referencing: print("No references to {} found".format(sym_name)) sys.exit(0) print("Found {} locations that reference {}:\n" .format(len(referencing), sym_name)) for i, node in enumerate(referencing, 1): print("========== Location {} ({}:{}) ==========\n\n{}" .format(i, node.filename, node.linenr, node)) # Print the parents of the menu node too node = node.parent parent_i = 1 while node is not kconf.top_node: print("---------- Parent {} ({}:{}) ----------\n\n{}" .format(parent_i, node.filename, node.linenr, node)) node = node.parent parent_i += 1 hart-software-services-2022.10/thirdparty/Kconfiglib/examples/help_grep.py000066400000000000000000000031471432224323300266700ustar00rootroot00000000000000# Does a case-insensitive search for a regular expression in the help texts of # symbols and choices and the prompts of menus and comments. Prints the # matching items together with their locations and the matching text. # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/help_grep.py SCRIPT_ARG= # # Shortened example output for SCRIPT_ARG=general: # # menu "General setup" # location: init/Kconfig:39 # # config SYSVIPC # bool # prompt "System V IPC" # help # ... # exchange information. It is generally considered to be a good thing, # ... # # location: init/Kconfig:233 # # config BSD_PROCESS_ACCT # bool # prompt "BSD Process Accounting" if MULTIUSER # help # ... # information. This is generally a good idea, so say Y. # # location: init/Kconfig:403 # # ... import re import sys from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT if len(sys.argv) < 3: sys.exit("Pass the regex with SCRIPT_ARG=") search = re.compile(sys.argv[2], re.IGNORECASE).search for node in Kconfig(sys.argv[1]).node_iter(): match = False if isinstance(node.item, (Symbol, Choice)) and \ node.help is not None and search(node.help): print(node.item) match = True elif node.item == MENU and search(node.prompt[0]): print('menu "{}"'.format(node.prompt[0])) match = True elif node.item == COMMENT and search(node.prompt[0]): print('comment "{}"'.format(node.prompt[0])) match = True if match: print("location: {}:{}\n".format(node.filename, node.linenr)) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/kconfiglib.py000077700000000000000000000000001432224323300317142../kconfiglib.pyustar00rootroot00000000000000hart-software-services-2022.10/thirdparty/Kconfiglib/examples/list_undefined.py000066400000000000000000000116361432224323300277210ustar00rootroot00000000000000# Prints a list of symbols that are referenced in the Kconfig files of some # architecture but not defined by the Kconfig files of any architecture. # # A Kconfig file might be shared between many architectures and legitimately # reference undefined symbols for some of them, but if no architecture defines # the symbol, it usually indicates a problem or potential cleanup. # # This script could be sped up a lot if needed. See the comment near the # referencing_nodes() call. # # Run with the following command in the kernel root: # # $ python(3) Kconfiglib/examples/list_undefined.py # # Example output: # # Registering defined and undefined symbols for all arches # Processing mips # Processing ia64 # Processing metag # ... # # Finding references to each undefined symbol # Processing mips # Processing ia64 # Processing metag # ... # # The following globally undefined symbols were found, listed here # together with the locations of the items that reference them. # References might come from enclosing menus and ifs. # # ARM_ERRATA_753970: arch/arm/mach-mvebu/Kconfig:56, arch/arm/mach-mvebu/Kconfig:39 # SUNXI_CCU_MP: drivers/clk/sunxi-ng/Kconfig:14 # SUNXI_CCU_DIV: drivers/clk/sunxi-ng/Kconfig:14 # AC97: sound/ac97/Kconfig:6 # ... import os import subprocess from kconfiglib import Kconfig # Referenced inside the Kconfig files os.environ["KERNELVERSION"] = str( subprocess.check_output(("make", "kernelversion")).decode("utf-8").rstrip() ) def all_arch_srcarch_pairs(): """ Generates all valid (ARCH, SRCARCH) tuples for the kernel, corresponding to different architectures. SRCARCH holds the arch/ subdirectory. """ for srcarch in os.listdir("arch"): # Each subdirectory of arch/ containing a Kconfig file corresponds to # an architecture if os.path.exists(os.path.join("arch", srcarch, "Kconfig")): yield (srcarch, srcarch) # Some architectures define additional ARCH settings with ARCH != SRCARCH # (search for "Additional ARCH settings for" in the top-level Makefile) yield ("i386", "x86") yield ("x86_64", "x86") yield ("sparc32", "sparc") yield ("sparc64", "sparc") yield ("sh64", "sh") yield ("um", "um") def all_arch_srcarch_kconfigs(): """ Generates Kconfig instances for all the architectures in the kernel """ os.environ["srctree"] = "." os.environ["HOSTCC"] = "gcc" os.environ["HOSTCXX"] = "g++" os.environ["CC"] = "gcc" os.environ["LD"] = "ld" for arch, srcarch in all_arch_srcarch_pairs(): print(" Processing " + arch) os.environ["ARCH"] = arch os.environ["SRCARCH"] = srcarch # um (User Mode Linux) uses a different base Kconfig file yield Kconfig("Kconfig" if arch != "um" else "arch/x86/um/Kconfig", warn=False) print("Registering defined and undefined symbols for all arches") # Sets holding the names of all defined and undefined symbols, for all # architectures defined = set() undefined = set() for kconf in all_arch_srcarch_kconfigs(): for name, sym in kconf.syms.items(): if sym.nodes: # If the symbol has a menu node, it is defined defined.add(name) else: # Undefined symbol. We skip some of the uninteresting ones. # Due to how Kconfig works, integer literals show up as symbols # (from e.g. 'default 1'). Skip those. try: int(name, 0) continue except ValueError: # Interesting undefined symbol undefined.add(name) print("\nFinding references to each undefined symbol") def referencing_nodes(kconf, name): # Returns a list of all menu nodes that reference a symbol named 'name' in # any of their properties or property conditions res = [] for node in kconf.node_iter(): for ref in node.referenced: if ref.name == name: res.append(node) return res # Maps each globally undefined symbol to the menu nodes that reference it undef_sym_refs = [(name, set()) for name in undefined - defined] for kconf in all_arch_srcarch_kconfigs(): for name, refs in undef_sym_refs: # This means that we search the entire configuration tree for each # undefined symbol, which is terribly inefficient. We could speed # things up by tweaking referencing_nodes() to compare each symbol to # multiple symbols while walking the configuration tree. for node in referencing_nodes(kconf, name): refs.add("{}:{}".format(node.filename, node.linenr)) print("\nThe following globally undefined symbols were found, listed here\n" "together with the locations of the items that reference them.\n" "References might come from enclosing menus and ifs.\n") for name, refs in undef_sym_refs: print(" {}: {}".format(name, ", ".join(refs))) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/menuconfig_example.py000077500000000000000000000274141432224323300305760ustar00rootroot00000000000000#!/usr/bin/env python3 # Implements a simple configuration interface on top of Kconfiglib to # demonstrate concepts for building a menuconfig-like. Emulates how the # standard menuconfig prints menu entries. # # Always displays the entire Kconfig tree to keep things as simple as possible # (all symbols, choices, menus, and comments). # # Usage: # # $ python(3) Kconfiglib/examples/menuconfig.py # # A sample Kconfig is available in Kconfiglib/examples/Kmenuconfig. # # Here's a notation guide. The notation matches the one used by menuconfig # (scripts/kconfig/mconf): # # [ ] prompt - Bool # < > prompt - Tristate # {M} prompt - Tristate selected to m. Can only be set to m or y. # -*- prompt - Bool/tristate selected to y, pinning it # -M- prompt - Tristate selected to m that also has m visibility, # pinning it to m # (foo) prompt - String/int/hex symbol with value "foo" # --> prompt - The selected symbol in a choice in y mode. This # syntax is unique to this example. # # When modules are disabled, the .type attribute of TRISTATE symbols and # choices automatically changes to BOOL. This trick is used by the C # implementation as well, and gives the expected behavior without having to do # anything extra here. The original type is available in .orig_type if needed. # # The Kconfiglib/examples/Kmenuconfig example uses named choices to be able to # refer to choices by name. Named choices are supported in the C tools too, but # I don't think I've ever seen them used in the wild. # # Sample session: # # $ python Kconfiglib/examples/menuconfig.py Kconfiglib/examples/Kmenuconfig # # ======== Example Kconfig configuration ======== # # [*] Enable loadable module support (MODULES) # Bool and tristate symbols # [*] Bool symbol (BOOL) # [ ] Dependent bool symbol (BOOL_DEP) # < > Dependent tristate symbol (TRI_DEP) # [ ] First prompt (TWO_MENU_NODES) # < > Tristate symbol (TRI) # [ ] Second prompt (TWO_MENU_NODES) # *** These are selected by TRI_DEP *** # < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP) # < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP) # String, int, and hex symbols # (foo) String symbol (STRING) # (747) Int symbol (INT) # (0xABC) Hex symbol (HEX) # Various choices # -*- Bool choice (BOOL_CHOICE) # --> Bool choice sym 1 (BOOL_CHOICE_SYM_1) # Bool choice sym 2 (BOOL_CHOICE_SYM_2) # {M} Tristate choice (TRI_CHOICE) # < > Tristate choice sym 1 (TRI_CHOICE_SYM_1) # < > Tristate choice sym 2 (TRI_CHOICE_SYM_2) # [ ] Optional bool choice (OPT_BOOL_CHOICE) # # Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): BOOL # Value for BOOL (available: n, y): n # # ======== Example Kconfig configuration ======== # # [*] Enable loadable module support (MODULES) # Bool and tristate symbols # [ ] Bool symbol (BOOL) # < > Tristate symbol (TRI) # [ ] Second prompt (TWO_MENU_NODES) # *** These are selected by TRI_DEP *** # < > Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP) # < > Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP) # String, int, and hex symbols # (foo) String symbol (STRING) # (747) Int symbol (INT) # (0xABC) Hex symbol (HEX) # Various choices # -*- Bool choice (BOOL_CHOICE) # --> Bool choice sym 1 (BOOL_CHOICE_SYM_1) # Bool choice sym 2 (BOOL_CHOICE_SYM_2) # {M} Tristate choice (TRI_CHOICE) # < > Tristate choice sym 1 (TRI_CHOICE_SYM_1) # < > Tristate choice sym 2 (TRI_CHOICE_SYM_2) # [ ] Optional bool choice (OPT_BOOL_CHOICE) # # Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): MODULES # Value for MODULES (available: n, y): n # # ======== Example Kconfig configuration ======== # # [ ] Enable loadable module support (MODULES) # Bool and tristate symbols # [ ] Bool symbol (BOOL) # [ ] Tristate symbol (TRI) # [ ] Second prompt (TWO_MENU_NODES) # *** These are selected by TRI_DEP *** # [ ] Tristate selected by TRI_DEP (SELECTED_BY_TRI_DEP) # [ ] Tristate implied by TRI_DEP (IMPLIED_BY_TRI_DEP) # String, int, and hex symbols # (foo) String symbol (STRING) # (747) Int symbol (INT) # (0xABC) Hex symbol (HEX) # Various choices # -*- Bool choice (BOOL_CHOICE) # --> Bool choice sym 1 (BOOL_CHOICE_SYM_1) # Bool choice sym 2 (BOOL_CHOICE_SYM_2) # -*- Tristate choice (TRI_CHOICE) # --> Tristate choice sym 1 (TRI_CHOICE_SYM_1) # Tristate choice sym 2 (TRI_CHOICE_SYM_2) # [ ] Optional bool choice (OPT_BOOL_CHOICE) # # Enter a symbol/choice name, "load_config", or "write_config" (or press CTRL+D to exit): ^D from __future__ import print_function import readline import sys from kconfiglib import Kconfig, \ Symbol, MENU, COMMENT, \ BOOL, TRISTATE, STRING, INT, HEX, UNKNOWN, \ expr_value, \ TRI_TO_STR # Python 2/3 compatibility hack if sys.version_info[0] < 3: input = raw_input def indent_print(s, indent): print(indent*" " + s) def value_str(sc): """ Returns the value part ("[*]", "", "(foo)" etc.) of a menu entry. sc: Symbol or Choice. """ if sc.type in (STRING, INT, HEX): return "({})".format(sc.str_value) # BOOL or TRISTATE # The choice mode is an upper bound on the visibility of choice symbols, so # we can check the choice symbols' own visibility to see if the choice is # in y mode if isinstance(sc, Symbol) and sc.choice and sc.visibility == 2: # For choices in y mode, print '-->' next to the selected symbol return "-->" if sc.choice.selection is sc else " " tri_val_str = (" ", "M", "*")[sc.tri_value] if len(sc.assignable) == 1: # Pinned to a single value return "-{}-".format(tri_val_str) if sc.type == BOOL: return "[{}]".format(tri_val_str) if sc.type == TRISTATE: if sc.assignable == (1, 2): # m and y available return "{" + tri_val_str + "}" # Gets a bit confusing with .format() return "<{}>".format(tri_val_str) def node_str(node): """ Returns the complete menu entry text for a menu node, or "" for invisible menu nodes. Invisible menu nodes are those that lack a prompt or that do not have a satisfied prompt condition. Example return value: "[*] Bool symbol (BOOL)" The symbol name is printed in parentheses to the right of the prompt. This is so that symbols can easily be referred to in the configuration interface. """ if not node.prompt: return "" # Even for menu nodes for symbols and choices, it's wrong to check # Symbol.visibility / Choice.visibility here. The reason is that a symbol # (and a choice, in theory) can be defined in multiple locations, giving it # multiple menu nodes, which do not necessarily all have the same prompt # visibility. Symbol.visibility / Choice.visibility is calculated as the OR # of the visibility of all the prompts. prompt, prompt_cond = node.prompt if not expr_value(prompt_cond): return "" if node.item == MENU: return " " + prompt if node.item == COMMENT: return " *** {} ***".format(prompt) # Symbol or Choice sc = node.item if sc.type == UNKNOWN: # Skip symbols defined without a type (these are obscure and generate # a warning) return "" # {:3} sets the field width to three. Gives nice alignment for empty string # values. res = "{:3} {}".format(value_str(sc), prompt) # Don't print the name for unnamed choices (the normal kind) if sc.name is not None: res += " ({})".format(sc.name) return res def print_menuconfig_nodes(node, indent): """ Prints a tree with all the menu entries rooted at 'node'. Child menu entries are indented. """ while node: string = node_str(node) if string: indent_print(string, indent) if node.list: print_menuconfig_nodes(node.list, indent + 8) node = node.next def print_menuconfig(kconf): """ Prints all menu entries for the configuration. """ # Print the expanded mainmenu text at the top. This is the same as # kconf.top_node.prompt[0], but with variable references expanded. print("\n======== {} ========\n".format(kconf.mainmenu_text)) print_menuconfig_nodes(kconf.top_node.list, 0) print("") def get_value_from_user(sc): """ Prompts the user for a value for the symbol or choice 'sc'. For bool/tristate symbols and choices, provides a list of all the assignable values. """ if not sc.visibility: print(sc.name + " is not currently visible") return False prompt = "Value for {}".format(sc.name) if sc.type in (BOOL, TRISTATE): prompt += " (available: {})" \ .format(", ".join(TRI_TO_STR[val] for val in sc.assignable)) prompt += ": " val = input(prompt) # Automatically add a "0x" prefix for hex symbols, like the menuconfig # interface does. This isn't done when loading .config files, hence why # set_value() doesn't do it automatically. if sc.type == HEX and not val.startswith(("0x", "0X")): val = "0x" + val # Let Kconfiglib itself print a warning here if the value is invalid. We # could also disable warnings temporarily with 'kconf.warn = False' and # print our own warning. return sc.set_value(val) if __name__ == "__main__": if len(sys.argv) != 2: sys.exit("usage: menuconfig.py ") # Load Kconfig configuration files kconf = Kconfig(sys.argv[1]) # Print the initial configuration tree print_menuconfig(kconf) while True: try: cmd = input('Enter a symbol/choice name, "load_config", or ' '"write_config" (or press CTRL+D to exit): ').strip() except EOFError: print("") break if cmd == "load_config": config_filename = input(".config file to load: ") try: # Returns a message telling which file got loaded print(kconf.load_config(config_filename)) except EnvironmentError as e: print(e, file=sys.stderr) print_menuconfig(kconf) continue if cmd == "write_config": config_filename = input("To this file: ") try: # Returns a message telling which file got saved print(kconf.write_config(config_filename)) except EnvironmentError as e: print(e, file=sys.stderr) continue # Assume 'cmd' is the name of a symbol or choice if it isn't one of the # commands above, prompt the user for a value for it, and print the new # configuration tree if cmd in kconf.syms: if get_value_from_user(kconf.syms[cmd]): print_menuconfig(kconf) continue if cmd in kconf.named_choices: if get_value_from_user(kconf.named_choices[cmd]): print_menuconfig(kconf) continue print("No symbol/choice named '{}' in the configuration".format(cmd), file=sys.stderr) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/merge_config.py000077500000000000000000000070631432224323300273530ustar00rootroot00000000000000#!/usr/bin/env python3 # This script functions similarly to scripts/kconfig/merge_config.sh from the # kernel tree, merging multiple configurations fragments to produce a complete # .config, with unspecified values filled in as for alldefconfig. # # The generated .config respects symbol dependencies, and a warning is printed # if any symbol gets a different value from the assigned value. # # For a real-world merging example based on this script, see # https://github.com/zephyrproject-rtos/zephyr/blob/master/scripts/kconfig/kconfig.py. # # Here's a demo: # # Kconfig contents: # # config FOO # bool "FOO" # # config BAR # bool "BAR" # # config BAZ # string "BAZ" # # config QAZ # bool "QAZ" if n # # # conf1 contents: # # CONFIG_FOO=y # # # conf2 contents: # # CONFIG_BAR=y # # # conf3 contents: # # # Assigned twice (would generate warning if 'warn_assign_override' was # # True) # # CONFIG_FOO is not set # # # Ops... this symbol doesn't exist # CONFIG_OPS=y # # CONFIG_BAZ="baz string" # # # conf4 contents: # # CONFIG_QAZ=y # # # Running: # # $ python(3) merge_config.py Kconfig merged conf1 conf2 conf3 conf4 # Merged configuration 'conf1' # Merged configuration 'conf2' # conf3:5: warning: attempt to assign the value 'y' to the undefined symbol OPS # Merged configuration 'conf3' # Merged configuration 'conf4' # Configuration saved to 'merged' # warning: QAZ (defined at Kconfig:10) was assigned the value 'y' but got the value 'n' -- check dependencies # $ cat merged # Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib) # # CONFIG_FOO is not set # CONFIG_BAR=y # CONFIG_BAZ="baz string" from __future__ import print_function import sys from kconfiglib import Kconfig, BOOL, TRISTATE, TRI_TO_STR if len(sys.argv) < 4: sys.exit("usage: merge_config.py Kconfig merged_config config1 [config2 ...]") kconf = Kconfig(sys.argv[1], suppress_traceback=True) # Enable warnings for assignments to undefined symbols kconf.warn_assign_undef = True # (This script uses alldefconfig as the base. Other starting states could be # set up here as well. The approach in examples/allnoconfig_simpler.py could # provide an allnoconfig starting state for example.) # Disable warnings generated for multiple assignments to the same symbol within # a (set of) configuration files. Assigning a symbol multiple times might be # done intentionally when merging configuration files. kconf.warn_assign_override = False kconf.warn_assign_redun = False # Create a merged configuration by loading the fragments with replace=False. # load_config() and write_config() returns a message to print. for config in sys.argv[3:]: print(kconf.load_config(config, replace=False)) # Write the merged configuration print(kconf.write_config(sys.argv[2])) # Print warnings for symbols whose actual value doesn't match the assigned # value for sym in kconf.defined_syms: # Was the symbol assigned to? if sym.user_value is not None: # Tristate values are represented as 0, 1, 2. Having them as # "n", "m", "y" is more convenient here, so convert. if sym.type in (BOOL, TRISTATE): user_value = TRI_TO_STR[sym.user_value] else: user_value = sym.user_value if user_value != sym.str_value: print("warning: {} was assigned the value '{}' but got the " "value '{}' -- check dependencies".format( sym.name_and_loc, user_value, sym.str_value), file=sys.stderr) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/print_config_tree.py000066400000000000000000000157711432224323300304310ustar00rootroot00000000000000# Prints menu entries as a tree with its value in the .config file. This can be # handy e.g. for diffing between different .config files or versions of Kconfig files. # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=print_config_tree.py [SCRIPT_ARG=<.config>] # # If the variable WITH_HELP_DESC is modified to 'True', the help is added # to the symbols. # # Here's a notation guide. The notation matches the one used by menuconfig # (scripts/kconfig/mconf): # # [ ] prompt - Bool # < > prompt - Tristate # {M} prompt - Tristate selected to m. Can only be set to m or y. # -*- prompt - Bool/tristate selected to y, pinning it # -M- prompt - Tristate selected to m that also has m visibility, # pinning it to m # (foo) prompt - String/int/hex symbol with value "foo" # --> prompt - The selected symbol in a choice in y mode. This # syntax is unique to this example. # # When modules are disabled, the .type attribute of TRISTATE symbols and # choices automatically changes to BOOL. This trick is used by the C # implementation as well, and gives the expected behavior without having to do # anything extra here. The original type is available in .orig_type if needed. # # Example output: # # $ make scriptconfig SCRIPT=Kconfiglib/examples/print_config_tree.py [SCRIPT_ARG=<.config file>] # # ======== Linux/x86 4.9.82 Kernel Configuration ======== # # [*] 64-bit kernel (64BIT) # General setup # () Cross-compiler tool prefix (CROSS_COMPILE) # [ ] Compile also drivers which will not load (COMPILE_TEST) # () Local version - append to kernel release (LOCALVERSION) # [*] Automatically append version information to the version string (LOCALVERSION_AUTO) # -*- Kernel compression mode # ... # # With the variable WITH_HELP_DESC modified to 'True': # # ======== Linux/x86 4.9.82 Kernel Configuration ======== # # [*] 64-bit kernel - Say yes to build a 64-bit kernel - formerly known as x86_64 Say no to build a 32-bit kernel - formerly known as i386 (64BIT) # General setup # () Cross-compiler tool prefix - Same as running 'make CROSS_COMPILE=prefix-' but stored for default make runs in this kernel build directory. You don't need to set this unless you want the configured kernel build directory to select the cross-compiler automatically. (CROSS_COMPILE) # [ ] Compile also drivers which will not load - Some drivers can be compiled on a different platform than they are intended to be run on. Despite they cannot be loaded there (or even when they load they cannot be used due to missing HW support), developers still, opposing to distributors, might want to build such drivers to compile-test them. If you are a developer and want to build everything available, say Y here. If you are a user/distributor, say N here to exclude useless drivers to be distributed. (COMPILE_TEST) # ... import sys from kconfiglib import Kconfig, \ Symbol, MENU, COMMENT, \ BOOL, TRISTATE, STRING, INT, HEX, UNKNOWN, \ expr_value # Add help description to output WITH_HELP_DESC = False def indent_print(s, indent): print(indent*" " + s) def value_str(sc): """ Returns the value part ("[*]", "", "(foo)" etc.) of a menu entry. sc: Symbol or Choice. """ if sc.type in (STRING, INT, HEX): return "({})".format(sc.str_value) # BOOL or TRISTATE # The choice mode is an upper bound on the visibility of choice symbols, so # we can check the choice symbols' own visibility to see if the choice is # in y mode if isinstance(sc, Symbol) and sc.choice and sc.visibility == 2: # For choices in y mode, print '-->' next to the selected symbol return "-->" if sc.choice.selection is sc else " " tri_val_str = (" ", "M", "*")[sc.tri_value] if len(sc.assignable) == 1: # Pinned to a single value return "-{}-".format(tri_val_str) if sc.type == BOOL: return "[{}]".format(tri_val_str) if sc.type == TRISTATE: if sc.assignable == (1, 2): # m and y available return "{" + tri_val_str + "}" # Gets a bit confusing with .format() return "<{}>".format(tri_val_str) def node_str(node): """ Returns the complete menu entry text for a menu node, or "" for invisible menu nodes. Invisible menu nodes are those that lack a prompt or that do not have a satisfied prompt condition. Example return value: "[*] Bool symbol (BOOL)" The symbol name is printed in parentheses to the right of the prompt. """ if not node.prompt: return "" # Even for menu nodes for symbols and choices, it's wrong to check # Symbol.visibility / Choice.visibility here. The reason is that a symbol # (and a choice, in theory) can be defined in multiple locations, giving it # multiple menu nodes, which do not necessarily all have the same prompt # visibility. Symbol.visibility / Choice.visibility is calculated as the OR # of the visibility of all the prompts. prompt, prompt_cond = node.prompt if not expr_value(prompt_cond): return "" if node.item == MENU: return " " + prompt if node.item == COMMENT: return " *** {} ***".format(prompt) # Symbol or Choice sc = node.item if sc.type == UNKNOWN: # Skip symbols defined without a type (these are obscure and generate # a warning) return "" # Add help text if WITH_HELP_DESC: prompt += ' - ' + str(node.help).replace('\n', ' ').replace('\r', '') # {:3} sets the field width to three. Gives nice alignment for empty string # values. res = "{:3} {}".format(value_str(sc), prompt) # Don't print the name for unnamed choices (the normal kind) if sc.name is not None: res += " ({})".format(sc.name) return res def print_menuconfig_nodes(node, indent): """ Prints a tree with all the menu entries rooted at 'node'. Child menu entries are indented. """ while node: string = node_str(node) if string: indent_print(string, indent) if node.list: print_menuconfig_nodes(node.list, indent + 8) node = node.next def print_menuconfig(kconf): """ Prints all menu entries for the configuration. """ # Print the expanded mainmenu text at the top. This is the same as # kconf.top_node.prompt[0], but with variable references expanded. print("\n======== {} ========\n".format(kconf.mainmenu_text)) print_menuconfig_nodes(kconf.top_node.list, 0) print("") if __name__ == "__main__": # Load Kconfig configuration files kconf = Kconfig(sys.argv[1]) # Set default .config file or load it from argv if len(sys.argv) == 2: config_filename = '.config' else: config_filename = sys.argv[2] kconf.load_config(config_filename) # Print the configuration tree print_menuconfig(kconf) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/print_sym_info.py000066400000000000000000000032201432224323300277520ustar00rootroot00000000000000# Loads a Kconfig and a .config and prints a symbol. # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/print_sym_info.py SCRIPT_ARG= # # Example output for SCRIPT_ARG=MODULES: # # menuconfig MODULES # bool # prompt "Enable loadable module support" # option modules # help # Kernel modules are small pieces of compiled code which can # be inserted in the running kernel, rather than being # permanently built into the kernel. You use the "modprobe" # tool to add (and sometimes remove) them. If you say Y here, # many parts of the kernel can be built as modules (by # answering M instead of Y where indicated): this is most # useful for infrequently used options which are not required # for booting. For more information, see the man pages for # modprobe, lsmod, modinfo, insmod and rmmod. # # If you say Y here, you will need to run "make # modules_install" to put the modules under /lib/modules/ # where modprobe can find them (you may need to be root to do # this). # # If unsure, say Y. # # value = n # visibility = y # currently assignable values: n, y # defined at init/Kconfig:1674 import sys from kconfiglib import Kconfig, TRI_TO_STR if len(sys.argv) < 3: sys.exit('Pass symbol name (without "CONFIG_" prefix) with SCRIPT_ARG=') kconf = Kconfig(sys.argv[1]) sym = kconf.syms[sys.argv[2]] print(sym) print("value = " + sym.str_value) print("visibility = " + TRI_TO_STR[sym.visibility]) print("currently assignable values: " + ", ".join([TRI_TO_STR[v] for v in sym.assignable])) for node in sym.nodes: print("defined at {}:{}".format(node.filename, node.linenr)) hart-software-services-2022.10/thirdparty/Kconfiglib/examples/print_tree.py000066400000000000000000000034641432224323300271000ustar00rootroot00000000000000# Prints the menu tree of the configuration. Dependencies between symbols can # sometimes implicitly alter the menu structure (see kconfig-language.txt), and # that's implemented too. # # Note: See the Kconfig.node_iter() function as well, which provides a simpler # interface for walking the menu tree. # # Usage: # # $ make [ARCH=] scriptconfig SCRIPT=Kconfiglib/examples/print_tree.py # # Example output: # # ... # config HAVE_KERNEL_LZO # config HAVE_KERNEL_LZ4 # choice # config KERNEL_GZIP # config KERNEL_BZIP2 # config KERNEL_LZMA # config KERNEL_XZ # config KERNEL_LZO # config KERNEL_LZ4 # config DEFAULT_HOSTNAME # config SWAP # config SYSVIPC # config SYSVIPC_SYSCTL # config POSIX_MQUEUE # config POSIX_MQUEUE_SYSCTL # config CROSS_MEMORY_ATTACH # config FHANDLE # config USELIB # config AUDIT # config HAVE_ARCH_AUDITSYSCALL # config AUDITSYSCALL # config AUDIT_WATCH # config AUDIT_TREE # menu "IRQ subsystem" # config MAY_HAVE_SPARSE_IRQ # config GENERIC_IRQ_LEGACY # config GENERIC_IRQ_PROBE # ... import sys from kconfiglib import Kconfig, Symbol, Choice, MENU, COMMENT def indent_print(s, indent): print(indent*" " + s) def print_items(node, indent): while node: if isinstance(node.item, Symbol): indent_print("config " + node.item.name, indent) elif isinstance(node.item, Choice): indent_print("choice", indent) elif node.item == MENU: indent_print('menu "{}"'.format(node.prompt[0]), indent) elif node.item == COMMENT: indent_print('comment "{}"'.format(node.prompt[0]), indent) if node.list: print_items(node.list, indent + 2) node = node.next kconf = Kconfig(sys.argv[1]) print_items(kconf.top_node, 0) hart-software-services-2022.10/thirdparty/Kconfiglib/genconfig.py000077500000000000000000000131741432224323300250500ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2018-2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Generates a header file with #defines from the configuration, matching the format of include/generated/autoconf.h in the Linux kernel. Optionally, also writes the configuration output as a .config file. See --config-out. The --sync-deps, --file-list, and --env-list options generate information that can be used to avoid needless rebuilds/reconfigurations. Before writing a header or configuration file, Kconfiglib compares the old contents of the file against the new contents. If there's no change, the write is skipped. This avoids updating file metadata like the modification time, and might save work depending on your build setup. By default, the configuration is generated from '.config'. A different configuration file can be passed in the KCONFIG_CONFIG environment variable. A custom header string can be inserted at the beginning of generated configuration and header files by setting the KCONFIG_CONFIG_HEADER and KCONFIG_AUTOHEADER_HEADER environment variables, respectively (this also works for other scripts). The string is not automatically made a comment (this is by design, to allow anything to be added), and no trailing newline is added, so add '/* */', '#', and newlines as appropriate. See https://www.gnu.org/software/make/manual/make.html#Multi_002dLine for a handy way to define multi-line variables in makefiles, for use with custom headers. Remember to export the variable to the environment. """ import argparse import os import sys # The version of embedded Python that is bundled with SoftConsole # does not understand %PYTHONPATH% and so we need to update the # PATH here directly with the environment variable if sys.platform.startswith('win'): path = os.path.join(os.getcwd(), 'thirdparty\\Kconfiglib') print("INFO: SoftConsole on Windows detected, adding ", path, "to Python sys.path") sys.path.append(path) # End of SoftConsole modification import kconfiglib DEFAULT_SYNC_DEPS_PATH = "deps/" def main(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__) parser.add_argument( "--header-path", metavar="HEADER_FILE", help=""" Path to write the generated header file to. If not specified, the path in the environment variable KCONFIG_AUTOHEADER is used if it is set, and 'config.h' otherwise. """) parser.add_argument( "--config-out", metavar="CONFIG_FILE", help=""" Write the configuration to CONFIG_FILE. This is useful if you include .config files in Makefiles, as the generated configuration file will be a full .config file even if .config is outdated. The generated configuration matches what olddefconfig would produce. If you use sync-deps, you can include deps/auto.conf instead. --config-out is meant for cases where incremental build information isn't needed. """) parser.add_argument( "--sync-deps", metavar="OUTPUT_DIR", nargs="?", const=DEFAULT_SYNC_DEPS_PATH, help=""" Enable generation of symbol dependency information for incremental builds, optionally specifying the output directory (default: {}). See the docstring of Kconfig.sync_deps() in Kconfiglib for more information. """.format(DEFAULT_SYNC_DEPS_PATH)) parser.add_argument( "--file-list", metavar="OUTPUT_FILE", help=""" Write a list of all Kconfig files to OUTPUT_FILE, with one file per line. The paths are relative to $srctree (or to the current directory if $srctree is unset). Files appear in the order they're 'source'd. """) parser.add_argument( "--env-list", metavar="OUTPUT_FILE", help=""" Write a list of all environment variables referenced in Kconfig files to OUTPUT_FILE, with one variable per line. Each line has the format NAME=VALUE. Only environment variables referenced with the preprocessor $(VAR) syntax are included, and not variables referenced with the older $VAR syntax (which is only supported for backwards compatibility). """) parser.add_argument( "kconfig", metavar="KCONFIG", nargs="?", default="Kconfig", help="Top-level Kconfig file (default: Kconfig)") args = parser.parse_args() kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True) kconf.load_config() if args.header_path is None: if "KCONFIG_AUTOHEADER" in os.environ: kconf.write_autoconf() else: # Kconfiglib defaults to include/generated/autoconf.h to be # compatible with the C tools. 'config.h' is used here instead for # backwards compatibility. It's probably a saner default for tools # as well. kconf.write_autoconf("config.h") else: kconf.write_autoconf(args.header_path) if args.config_out is not None: kconf.write_config(args.config_out, save_old=False) if args.sync_deps is not None: kconf.sync_deps(args.sync_deps) if args.file_list is not None: with _open_write(args.file_list) as f: for path in kconf.kconfig_filenames: f.write(path + "\n") if args.env_list is not None: with _open_write(args.env_list) as f: for env_var in kconf.env_vars: f.write("{}={}\n".format(env_var, os.environ[env_var])) def _open_write(path): # Python 2/3 compatibility. io.open() is available on both, but makes # write() expect 'unicode' strings on Python 2. if sys.version_info[0] < 3: return open(path, "w") return open(path, "w", encoding="utf-8") if __name__ == "__main__": main() hart-software-services-2022.10/thirdparty/Kconfiglib/guiconfig.py000077500000000000000000002176441432224323300250730ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Overview ======== A Tkinter-based menuconfig implementation, based around a treeview control and a help display. The interface should feel familiar to people used to qconf ('make xconfig'). Compatible with both Python 2 and Python 3. The display can be toggled between showing the full tree and showing just a single menu (like menuconfig.py). Only single-menu mode distinguishes between symbols defined with 'config' and symbols defined with 'menuconfig'. A show-all mode is available that shows invisible items in red. Supports both mouse and keyboard controls. The following keyboard shortcuts are available: Ctrl-S : Save configuration Ctrl-O : Open configuration Ctrl-A : Toggle show-all mode Ctrl-N : Toggle show-name mode Ctrl-M : Toggle single-menu mode Ctrl-F, /: Open jump-to dialog ESC : Close Running ======= guiconfig.py can be run either as a standalone executable or by calling the menuconfig() function with an existing Kconfig instance. The second option is a bit inflexible in that it will still load and save .config, etc. When run in standalone mode, the top-level Kconfig file to load can be passed as a command-line argument. With no argument, it defaults to "Kconfig". The KCONFIG_CONFIG environment variable specifies the .config file to load (if it exists) and save. If KCONFIG_CONFIG is unset, ".config" is used. When overwriting a configuration file, the old version is saved to .old (e.g. .config.old). $srctree is supported through Kconfiglib. """ # Note: There's some code duplication with menuconfig.py below, especially for # the help text. Maybe some of it could be moved into kconfiglib.py or a shared # helper script, but OTOH it's pretty nice to have things standalone and # customizable. import errno import os import sys _PY2 = sys.version_info[0] < 3 if _PY2: # Python 2 from Tkinter import * import ttk import tkFont as font import tkFileDialog as filedialog import tkMessageBox as messagebox else: # Python 3 from tkinter import * import tkinter.ttk as ttk import tkinter.font as font from tkinter import filedialog, messagebox from kconfiglib import Symbol, Choice, MENU, COMMENT, MenuNode, \ BOOL, TRISTATE, STRING, INT, HEX, \ AND, OR, \ expr_str, expr_value, split_expr, \ standard_sc_expr_str, \ TRI_TO_STR, TYPE_TO_STR, \ standard_kconfig, standard_config_filename # If True, use GIF image data embedded in this file instead of separate GIF # files. See _load_images(). _USE_EMBEDDED_IMAGES = True # Help text for the jump-to dialog _JUMP_TO_HELP = """\ Type one or more strings/regexes and press Enter to list items that match all of them. Python's regex flavor is used (see the 're' module). Double-clicking an item will jump to it. Item values can be toggled directly within the dialog.\ """ def _main(): menuconfig(standard_kconfig(__doc__)) # Global variables used below: # # _root: # The Toplevel instance for the main window # # _tree: # The Treeview in the main window # # _jump_to_tree: # The Treeview in the jump-to dialog. None if the jump-to dialog isn't # open. Doubles as a flag. # # _jump_to_matches: # List of Nodes shown in the jump-to dialog # # _menupath: # The Label that shows the menu path of the selected item # # _backbutton: # The button shown in single-menu mode for jumping to the parent menu # # _status_label: # Label with status text shown at the bottom of the main window # ("Modified", "Saved to ...", etc.) # # _id_to_node: # We can't use Node objects directly as Treeview item IDs, so we use their # id()s instead. This dictionary maps Node id()s back to Nodes. (The keys # are actually str(id(node)), just to simplify lookups.) # # _cur_menu: # The current menu. Ignored outside single-menu mode. # # _show_all_var/_show_name_var/_single_menu_var: # Tkinter Variable instances bound to the corresponding checkboxes # # _show_all/_single_menu: # Plain Python bools that track _show_all_var and _single_menu_var, to # speed up and simplify things a bit # # _conf_filename: # File to save the configuration to # # _minconf_filename: # File to save minimal configurations to # # _conf_changed: # True if the configuration has been changed. If False, we don't bother # showing the save-and-quit dialog. # # We reset this to False whenever the configuration is saved. # # _*_img: # PhotoImage instances for images def menuconfig(kconf): """ Launches the configuration interface, returning after the user exits. kconf: Kconfig instance to be configured """ global _kconf global _conf_filename global _minconf_filename global _jump_to_tree global _cur_menu _kconf = kconf _jump_to_tree = None _create_id_to_node() _create_ui() # Filename to save configuration to _conf_filename = standard_config_filename() # Load existing configuration and check if it's outdated _set_conf_changed(_load_config()) # Filename to save minimal configuration to _minconf_filename = "defconfig" # Current menu in single-menu mode _cur_menu = _kconf.top_node # Any visible items in the top menu? if not _shown_menu_nodes(kconf.top_node): # Nothing visible. Start in show-all mode and try again. _show_all_var.set(True) if not _shown_menu_nodes(kconf.top_node): # Give up and show an error. It's nice to be able to assume that # the tree is non-empty in the rest of the code. _root.wait_visibility() messagebox.showerror( "Error", "Empty configuration -- nothing to configure.\n\n" "Check that environment variables are set properly.") _root.destroy() return # Build the initial tree _update_tree() # Select the first item and focus the Treeview, so that keyboard controls # work immediately _select(_tree, _tree.get_children()[0]) _tree.focus_set() # Make geometry information available for centering the window. This # indirectly creates the window, so hide it so that it's never shown at the # old location. _root.withdraw() _root.update_idletasks() # Center the window _root.geometry("+{}+{}".format( (_root.winfo_screenwidth() - _root.winfo_reqwidth())//2, (_root.winfo_screenheight() - _root.winfo_reqheight())//2)) # Show it _root.deiconify() # Prevent the window from being automatically resized. Otherwise, it # changes size when scrollbars appear/disappear before the user has # manually resized it. _root.geometry(_root.geometry()) _root.mainloop() def _load_config(): # Loads any existing .config file. See the Kconfig.load_config() docstring. # # Returns True if .config is missing or outdated. We always prompt for # saving the configuration in that case. print(_kconf.load_config()) if not os.path.exists(_conf_filename): # No .config return True return _needs_save() def _needs_save(): # Returns True if a just-loaded .config file is outdated (would get # modified when saving) if _kconf.missing_syms: # Assignments to undefined symbols in the .config return True for sym in _kconf.unique_defined_syms: if sym.user_value is None: if sym.config_string: # Unwritten symbol return True elif sym.orig_type in (BOOL, TRISTATE): if sym.tri_value != sym.user_value: # Written bool/tristate symbol, new value return True elif sym.str_value != sym.user_value: # Written string/int/hex symbol, new value return True # No need to prompt for save return False def _create_id_to_node(): global _id_to_node _id_to_node = {str(id(node)): node for node in _kconf.node_iter()} def _create_ui(): # Creates the main window UI global _root global _tree # Create the root window. This initializes Tkinter and makes e.g. # PhotoImage available, so do it early. _root = Tk() _load_images() _init_misc_ui() _fix_treeview_issues() _create_top_widgets() # Create the pane with the Kconfig tree and description text panedwindow, _tree = _create_kconfig_tree_and_desc(_root) panedwindow.grid(column=0, row=1, sticky="nsew") _create_status_bar() _root.columnconfigure(0, weight=1) # Only the pane with the Kconfig tree and description grows vertically _root.rowconfigure(1, weight=1) # Start with show-name disabled _do_showname() _tree.bind("", _tree_left_key) _tree.bind("", _tree_right_key) # Note: Binding this for the jump-to tree as well would cause issues due to # the Tk bug mentioned in _tree_open() _tree.bind("<>", _tree_open) # add=True to avoid overriding the description text update _tree.bind("<>", _update_menu_path, add=True) _root.bind("", _save) _root.bind("", _open) _root.bind("", _toggle_showall) _root.bind("", _toggle_showname) _root.bind("", _toggle_tree_mode) _root.bind("", _jump_to_dialog) _root.bind("/", _jump_to_dialog) _root.bind("", _on_quit) def _load_images(): # Loads GIF images, creating the global _*_img PhotoImage variables. # Base64-encoded images embedded in this script are used if # _USE_EMBEDDED_IMAGES is True, and separate image files in the same # directory as the script otherwise. # # Using a global variable indirectly prevents the image from being # garbage-collected. Passing an image to a Tkinter function isn't enough to # keep it alive. def load_image(name, data): var_name = "_{}_img".format(name) if _USE_EMBEDDED_IMAGES: globals()[var_name] = PhotoImage(data=data, format="gif") else: globals()[var_name] = PhotoImage( file=os.path.join(os.path.dirname(__file__), name + ".gif"), format="gif") # Note: Base64 data can be put on the clipboard with # $ base64 -w0 foo.gif | xclip load_image("icon", "R0lGODlhMAAwAPEDAAAAAADQAO7u7v///yH5BAUKAAMALAAAAAAwADAAAAL/nI+gy+2Pokyv2jazuZxryQjiSJZmyXxHeLbumH6sEATvW8OLNtf5bfLZRLFITzgEipDJ4mYxYv6A0ubuqYhWk66tVTE4enHer7jcKvt0LLUw6P45lvEprT6c0+v7OBuqhYdHohcoqIbSAHc4ljhDwrh1UlgSydRCWWlp5wiYZvmSuSh4IzrqV6p4cwhkCsmY+nhK6uJ6t1mrOhuJqfu6+WYiCiwl7HtLjNSZZZis/MeM7NY3TaRKS40ooDeoiVqIultsrav92bi9c3a5KkkOsOJZpSS99m4k/0zPng4Gks9JSbB+8DIcoQfnjwpZCHv5W+ip4aQrKrB0uOikYhiMCBw1/uPoQUMBADs=") load_image("n_bool", "R0lGODdhEAAQAPAAAAgICP///ywAAAAAEAAQAAACIISPacHtvp5kcb5qG85hZ2+BkyiRF8BBaEqtrKkqslEAADs=") load_image("y_bool", "R0lGODdhEAAQAPEAAAgICADQAP///wAAACwAAAAAEAAQAAACMoSPacLtvlh4YrIYsst2cV19AvaVF9CUXBNJJoum7ymrsKuCnhiupIWjSSjAFuWhSCIKADs=") load_image("n_tri", "R0lGODlhEAAQAPD/AAEBAf///yH5BAUKAAIALAAAAAAQABAAAAInlI+pBrAKQnCPSUlXvFhznlkfeGwjKZhnJ65h6nrfi6h0st2QXikFADs=") load_image("m_tri", "R0lGODlhEAAQAPEDAAEBAeQMuv///wAAACH5BAUKAAMALAAAAAAQABAAAAI5nI+pBrAWAhPCjYhiAJQCnWmdoElHGVBoiK5M21ofXFpXRIrgiecqxkuNciZIhNOZFRNI24PhfEoLADs=") load_image("y_tri", "R0lGODlhEAAQAPEDAAICAgDQAP///wAAACH5BAUKAAMALAAAAAAQABAAAAI0nI+pBrAYBhDCRRUypfmergmgZ4xjMpmaw2zmxk7cCB+pWiVqp4MzDwn9FhGZ5WFjIZeGAgA7") load_image("m_my", "R0lGODlhEAAQAPEDAAAAAOQMuv///wAAACH5BAUKAAMALAAAAAAQABAAAAI5nIGpxiAPI2ghxFinq/ZygQhc94zgZopmOLYf67anGr+oZdp02emfV5n9MEHN5QhqICETxkABbQ4KADs=") load_image("y_my", "R0lGODlhEAAQAPH/AAAAAADQAAPRA////yH5BAUKAAQALAAAAAAQABAAAAM+SArcrhCMSSuIM9Q8rxxBWIXawIBkmWonupLd565Um9G1PIs59fKmzw8WnAlusBYR2SEIN6DmAmqBLBxYSAIAOw==") load_image("n_locked", "R0lGODlhEAAQAPABAAAAAP///yH5BAUKAAEALAAAAAAQABAAAAIgjB8AyKwN04pu0vMutpqqz4Hih4ydlnUpyl2r23pxUAAAOw==") load_image("m_locked", "R0lGODlhEAAQAPD/AAAAAOQMuiH5BAUKAAIALAAAAAAQABAAAAIylC8AyKwN04ohnGcqqlZmfXDWI26iInZoyiore05walolV39ftxsYHgL9QBBMBGFEFAAAOw==") load_image("y_locked", "R0lGODlhEAAQAPD/AAAAAADQACH5BAUKAAIALAAAAAAQABAAAAIylC8AyKzNgnlCtoDTwvZwrHydIYpQmR3KWq4uK74IOnp0HQPmnD3cOVlUIAgKsShkFAAAOw==") load_image("not_selected", "R0lGODlhEAAQAPD/AAAAAP///yH5BAUKAAIALAAAAAAQABAAAAIrlA2px6IBw2IpWglOvTYhzmUbGD3kNZ5QqrKn2YrqigCxZoMelU6No9gdCgA7") load_image("selected", "R0lGODlhEAAQAPD/AAAAAP///yH5BAUKAAIALAAAAAAQABAAAAIzlA2px6IBw2IpWglOvTah/kTZhimASJomiqonlLov1qptHTsgKSEzh9H8QI0QzNPwmRoFADs=") load_image("edit", "R0lGODlhEAAQAPIFAAAAAKOLAMuuEPvXCvrxvgAAAAAAAAAAACH5BAUKAAUALAAAAAAQABAAAANCWLqw/gqMBp8cszJxcwVC2FEOEIAi5kVBi3IqWZhuCGMyfdpj2e4pnK+WAshmvxeAcETWlsxPkkBtsqBMa8TIBSQAADs=") def _fix_treeview_issues(): # Fixes some Treeview issues global _treeview_rowheight style = ttk.Style() # The treeview rowheight isn't adjusted automatically on high-DPI displays, # so do it ourselves. The font will probably always be TkDefaultFont, but # play it safe and look it up. _treeview_rowheight = font.Font(font=style.lookup("Treeview", "font")) \ .metrics("linespace") + 2 style.configure("Treeview", rowheight=_treeview_rowheight) # Work around regression in https://core.tcl.tk/tk/tktview?name=509cafafae, # which breaks tag background colors for option in "foreground", "background": # Filter out any styles starting with ("!disabled", "!selected", ...). # style.map() returns an empty list for missing options, so this should # be future-safe. style.map( "Treeview", **{option: [elm for elm in style.map("Treeview", query_opt=option) if elm[:2] != ("!disabled", "!selected")]}) def _init_misc_ui(): # Does misc. UI initialization, like setting the title, icon, and theme _root.title(_kconf.mainmenu_text) # iconphoto() isn't available in Python 2's Tkinter _root.tk.call("wm", "iconphoto", _root._w, "-default", _icon_img) # Reducing the width of the window to 1 pixel makes it move around, at # least on GNOME. Prevent weird stuff like that. _root.minsize(128, 128) _root.protocol("WM_DELETE_WINDOW", _on_quit) # Use the 'clam' theme on *nix if it's available. It looks nicer than the # 'default' theme. if _root.tk.call("tk", "windowingsystem") == "x11": style = ttk.Style() if "clam" in style.theme_names(): style.theme_use("clam") def _create_top_widgets(): # Creates the controls above the Kconfig tree in the main window global _show_all_var global _show_name_var global _single_menu_var global _menupath global _backbutton topframe = ttk.Frame(_root) topframe.grid(column=0, row=0, sticky="ew") ttk.Button(topframe, text="Save", command=_save) \ .grid(column=0, row=0, sticky="ew", padx=".05c", pady=".05c") ttk.Button(topframe, text="Save as...", command=_save_as) \ .grid(column=1, row=0, sticky="ew") ttk.Button(topframe, text="Save minimal (advanced)...", command=_save_minimal) \ .grid(column=2, row=0, sticky="ew", padx=".05c") ttk.Button(topframe, text="Open...", command=_open) \ .grid(column=3, row=0) ttk.Button(topframe, text="Jump to...", command=_jump_to_dialog) \ .grid(column=4, row=0, padx=".05c") _show_name_var = BooleanVar() ttk.Checkbutton(topframe, text="Show name", command=_do_showname, variable=_show_name_var) \ .grid(column=0, row=1, sticky="nsew", padx=".05c", pady="0 .05c", ipady=".2c") _show_all_var = BooleanVar() ttk.Checkbutton(topframe, text="Show all", command=_do_showall, variable=_show_all_var) \ .grid(column=1, row=1, sticky="nsew", pady="0 .05c") # Allow the show-all and single-menu status to be queried via plain global # Python variables, which is faster and simpler def show_all_updated(*_): global _show_all _show_all = _show_all_var.get() _trace_write(_show_all_var, show_all_updated) _show_all_var.set(False) _single_menu_var = BooleanVar() ttk.Checkbutton(topframe, text="Single-menu mode", command=_do_tree_mode, variable=_single_menu_var) \ .grid(column=2, row=1, sticky="nsew", padx=".05c", pady="0 .05c") _backbutton = ttk.Button(topframe, text="<--", command=_leave_menu, state="disabled") _backbutton.grid(column=0, row=4, sticky="nsew", padx=".05c", pady="0 .05c") def tree_mode_updated(*_): global _single_menu _single_menu = _single_menu_var.get() if _single_menu: _backbutton.grid() else: _backbutton.grid_remove() _trace_write(_single_menu_var, tree_mode_updated) _single_menu_var.set(False) # Column to the right of the buttons that the menu path extends into, so # that it can grow wider than the buttons topframe.columnconfigure(5, weight=1) _menupath = ttk.Label(topframe) _menupath.grid(column=0, row=3, columnspan=6, sticky="w", padx="0.05c", pady="0 .05c") def _create_kconfig_tree_and_desc(parent): # Creates a Panedwindow with a Treeview that shows Kconfig nodes and a Text # that shows a description of the selected node. Returns a tuple with the # Panedwindow and the Treeview. This code is shared between the main window # and the jump-to dialog. panedwindow = ttk.Panedwindow(parent, orient=VERTICAL) tree_frame, tree = _create_kconfig_tree(panedwindow) desc_frame, desc = _create_kconfig_desc(panedwindow) panedwindow.add(tree_frame, weight=1) panedwindow.add(desc_frame) def tree_select(_): # The Text widget does not allow editing the text in its disabled # state. We need to temporarily enable it. desc["state"] = "normal" sel = tree.selection() if not sel: desc.delete("1.0", "end") desc["state"] = "disabled" return # Text.replace() is not available in Python 2's Tkinter desc.delete("1.0", "end") desc.insert("end", _info_str(_id_to_node[sel[0]])) desc["state"] = "disabled" tree.bind("<>", tree_select) tree.bind("<1>", _tree_click) tree.bind("", _tree_double_click) tree.bind("", _tree_enter) tree.bind("", _tree_enter) tree.bind("", _tree_toggle) tree.bind("n", _tree_set_val(0)) tree.bind("m", _tree_set_val(1)) tree.bind("y", _tree_set_val(2)) return panedwindow, tree def _create_kconfig_tree(parent): # Creates a Treeview for showing Kconfig nodes frame = ttk.Frame(parent) tree = ttk.Treeview(frame, selectmode="browse", height=20, columns=("name",)) tree.heading("#0", text="Option", anchor="w") tree.heading("name", text="Name", anchor="w") tree.tag_configure("n-bool", image=_n_bool_img) tree.tag_configure("y-bool", image=_y_bool_img) tree.tag_configure("m-tri", image=_m_tri_img) tree.tag_configure("n-tri", image=_n_tri_img) tree.tag_configure("m-tri", image=_m_tri_img) tree.tag_configure("y-tri", image=_y_tri_img) tree.tag_configure("m-my", image=_m_my_img) tree.tag_configure("y-my", image=_y_my_img) tree.tag_configure("n-locked", image=_n_locked_img) tree.tag_configure("m-locked", image=_m_locked_img) tree.tag_configure("y-locked", image=_y_locked_img) tree.tag_configure("not-selected", image=_not_selected_img) tree.tag_configure("selected", image=_selected_img) tree.tag_configure("edit", image=_edit_img) tree.tag_configure("invisible", foreground="red") tree.grid(column=0, row=0, sticky="nsew") _add_vscrollbar(frame, tree) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) # Create items for all menu nodes. These can be detached/moved later. # Micro-optimize this a bit. insert = tree.insert id_ = id Symbol_ = Symbol for node in _kconf.node_iter(): item = node.item insert("", "end", iid=id_(node), values=item.name if item.__class__ is Symbol_ else "") return frame, tree def _create_kconfig_desc(parent): # Creates a Text for showing the description of the selected Kconfig node frame = ttk.Frame(parent) desc = Text(frame, height=12, wrap="none", borderwidth=0, state="disabled") desc.grid(column=0, row=0, sticky="nsew") # Work around not being to Ctrl-C/V text from a disabled Text widget, with a # tip found in https://stackoverflow.com/questions/3842155/is-there-a-way-to-make-the-tkinter-text-widget-read-only desc.bind("<1>", lambda _: desc.focus_set()) _add_vscrollbar(frame, desc) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) return frame, desc def _add_vscrollbar(parent, widget): # Adds a vertical scrollbar to 'widget' that's only shown as needed vscrollbar = ttk.Scrollbar(parent, orient="vertical", command=widget.yview) vscrollbar.grid(column=1, row=0, sticky="ns") def yscrollcommand(first, last): # Only show the scrollbar when needed. 'first' and 'last' are # strings. if float(first) <= 0.0 and float(last) >= 1.0: vscrollbar.grid_remove() else: vscrollbar.grid() vscrollbar.set(first, last) widget["yscrollcommand"] = yscrollcommand def _create_status_bar(): # Creates the status bar at the bottom of the main window global _status_label _status_label = ttk.Label(_root, anchor="e", padding="0 0 0.4c 0") _status_label.grid(column=0, row=3, sticky="ew") def _set_status(s): # Sets the text in the status bar to 's' _status_label["text"] = s def _set_conf_changed(changed): # Updates the status re. whether there are unsaved changes global _conf_changed _conf_changed = changed if changed: _set_status("Modified") def _update_tree(): # Updates the Kconfig tree in the main window by first detaching all nodes # and then updating and reattaching them. The tree structure might have # changed. # If a selected/focused item is detached and later reattached, it stays # selected/focused. That can give multiple selections even though # selectmode=browse. Save and later restore the selection and focus as a # workaround. old_selection = _tree.selection() old_focus = _tree.focus() # Detach all tree items before re-stringing them. This is relatively fast, # luckily. _tree.detach(*_id_to_node.keys()) if _single_menu: _build_menu_tree() else: _build_full_tree(_kconf.top_node) _tree.selection_set(old_selection) _tree.focus(old_focus) def _build_full_tree(menu): # Updates the tree starting from menu.list, in full-tree mode. To speed # things up, only open menus are updated. The menu-at-a-time logic here is # to deal with invisible items that can show up outside show-all mode (see # _shown_full_nodes()). for node in _shown_full_nodes(menu): _add_to_tree(node, _kconf.top_node) # _shown_full_nodes() includes nodes from menus rooted at symbols, so # we only need to check "real" menus/choices here if node.list and not isinstance(node.item, Symbol): if _tree.item(id(node), "open"): _build_full_tree(node) else: # We're just probing here, so _shown_menu_nodes() will work # fine, and might be a bit faster shown = _shown_menu_nodes(node) if shown: # Dummy element to make the open/closed toggle appear _tree.move(id(shown[0]), id(shown[0].parent), "end") def _shown_full_nodes(menu): # Returns the list of menu nodes shown in 'menu' (a menu node for a menu) # for full-tree mode. A tricky detail is that invisible items need to be # shown if they have visible children. def rec(node): res = [] while node: if _visible(node) or _show_all: res.append(node) if node.list and isinstance(node.item, Symbol): # Nodes from menu created from dependencies res += rec(node.list) elif node.list and isinstance(node.item, Symbol): # Show invisible symbols (defined with either 'config' and # 'menuconfig') if they have visible children. This can happen # for an m/y-valued symbol with an optional prompt # ('prompt "foo" is COND') that is currently disabled. shown_children = rec(node.list) if shown_children: res.append(node) res += shown_children node = node.next return res return rec(menu.list) def _build_menu_tree(): # Updates the tree in single-menu mode. See _build_full_tree() as well. for node in _shown_menu_nodes(_cur_menu): _add_to_tree(node, _cur_menu) def _shown_menu_nodes(menu): # Used for single-menu mode. Similar to _shown_full_nodes(), but doesn't # include children of symbols defined with 'menuconfig'. def rec(node): res = [] while node: if _visible(node) or _show_all: res.append(node) if node.list and not node.is_menuconfig: res += rec(node.list) elif node.list and isinstance(node.item, Symbol): shown_children = rec(node.list) if shown_children: # Invisible item with visible children res.append(node) if not node.is_menuconfig: res += shown_children node = node.next return res return rec(menu.list) def _visible(node): # Returns True if the node should appear in the menu (outside show-all # mode) return node.prompt and expr_value(node.prompt[1]) and not \ (node.item == MENU and not expr_value(node.visibility)) def _add_to_tree(node, top): # Adds 'node' to the tree, at the end of its menu. We rely on going through # the nodes linearly to get the correct order. 'top' holds the menu that # corresponds to the top-level menu, and can vary in single-menu mode. parent = node.parent _tree.move(id(node), "" if parent is top else id(parent), "end") _tree.item( id(node), text=_node_str(node), # The _show_all test avoids showing invisible items in red outside # show-all mode, which could look confusing/broken. Invisible symbols # are shown outside show-all mode if an invisible symbol has visible # children in an implicit menu. tags=_img_tag(node) if _visible(node) or not _show_all else _img_tag(node) + " invisible") def _node_str(node): # Returns the string shown to the right of the image (if any) for the node if node.prompt: if node.item == COMMENT: s = "*** {} ***".format(node.prompt[0]) else: s = node.prompt[0] if isinstance(node.item, Symbol): sym = node.item # Print "(NEW)" next to symbols without a user value (from e.g. a # .config), but skip it for choice symbols in choices in y mode, # and for symbols of UNKNOWN type (which generate a warning though) if sym.user_value is None and sym.type and not \ (sym.choice and sym.choice.tri_value == 2): s += " (NEW)" elif isinstance(node.item, Symbol): # Symbol without prompt (can show up in show-all) s = "<{}>".format(node.item.name) else: # Choice without prompt. Use standard_sc_expr_str() so that it shows up # as ''. s = standard_sc_expr_str(node.item) if isinstance(node.item, Symbol): sym = node.item if sym.orig_type == STRING: s += ": " + sym.str_value elif sym.orig_type in (INT, HEX): s = "({}) {}".format(sym.str_value, s) elif isinstance(node.item, Choice) and node.item.tri_value == 2: # Print the prompt of the selected symbol after the choice for # choices in y mode sym = node.item.selection if sym: for sym_node in sym.nodes: # Use the prompt used at this choice location, in case the # choice symbol is defined in multiple locations if sym_node.parent is node and sym_node.prompt: s += " ({})".format(sym_node.prompt[0]) break else: # If the symbol isn't defined at this choice location, then # just use whatever prompt we can find for it for sym_node in sym.nodes: if sym_node.prompt: s += " ({})".format(sym_node.prompt[0]) break # In single-menu mode, print "--->" next to nodes that have menus that can # potentially be entered. Print "----" if the menu is empty. We don't allow # those to be entered. if _single_menu and node.is_menuconfig: s += " --->" if _shown_menu_nodes(node) else " ----" return s def _img_tag(node): # Returns the tag for the image that should be shown next to 'node', or the # empty string if it shouldn't have an image item = node.item if item in (MENU, COMMENT) or not item.orig_type: return "" if item.orig_type in (STRING, INT, HEX): return "edit" # BOOL or TRISTATE if _is_y_mode_choice_sym(item): # Choice symbol in y-mode choice return "selected" if item.choice.selection is item else "not-selected" if len(item.assignable) <= 1: # Pinned to a single value return "" if isinstance(item, Choice) else item.str_value + "-locked" if item.type == BOOL: return item.str_value + "-bool" # item.type == TRISTATE if item.assignable == (1, 2): return item.str_value + "-my" return item.str_value + "-tri" def _is_y_mode_choice_sym(item): # The choice mode is an upper bound on the visibility of choice symbols, so # we can check the choice symbols' own visibility to see if the choice is # in y mode return isinstance(item, Symbol) and item.choice and item.visibility == 2 def _tree_click(event): # Click on the Kconfig Treeview tree = event.widget if tree.identify_element(event.x, event.y) == "image": item = tree.identify_row(event.y) # Select the item before possibly popping up a dialog for # string/int/hex items, so that its help is visible _select(tree, item) _change_node(_id_to_node[item], tree.winfo_toplevel()) return "break" def _tree_double_click(event): # Double-click on the Kconfig treeview # Do an extra check to avoid weirdness when double-clicking in the tree # heading area if not _in_heading(event): return _tree_enter(event) def _in_heading(event): # Returns True if 'event' took place in the tree heading tree = event.widget return hasattr(tree, "identify_region") and \ tree.identify_region(event.x, event.y) in ("heading", "separator") def _tree_enter(event): # Enter press or double-click within the Kconfig treeview. Prefer to # open/close/enter menus, but toggle the value if that's not possible. tree = event.widget sel = tree.focus() if sel: node = _id_to_node[sel] if tree.get_children(sel): _tree_toggle_open(sel) elif _single_menu_mode_menu(node, tree): _enter_menu_and_select_first(node) else: _change_node(node, tree.winfo_toplevel()) return "break" def _tree_toggle(event): # Space press within the Kconfig treeview. Prefer to toggle the value, but # open/close/enter the menu if that's not possible. tree = event.widget sel = tree.focus() if sel: node = _id_to_node[sel] if _changeable(node): _change_node(node, tree.winfo_toplevel()) elif _single_menu_mode_menu(node, tree): _enter_menu_and_select_first(node) elif tree.get_children(sel): _tree_toggle_open(sel) return "break" def _tree_left_key(_): # Left arrow key press within the Kconfig treeview if _single_menu: # Leave the current menu in single-menu mode _leave_menu() return "break" # Otherwise, default action def _tree_right_key(_): # Right arrow key press within the Kconfig treeview sel = _tree.focus() if sel: node = _id_to_node[sel] # If the node can be entered in single-menu mode, do it if _single_menu_mode_menu(node, _tree): _enter_menu_and_select_first(node) return "break" # Otherwise, default action def _single_menu_mode_menu(node, tree): # Returns True if single-menu mode is on and 'node' is an (interface) # menu that can be entered return _single_menu and tree is _tree and node.is_menuconfig and \ _shown_menu_nodes(node) def _changeable(node): # Returns True if 'node' is a Symbol/Choice whose value can be changed sc = node.item if not isinstance(sc, (Symbol, Choice)): return False # This will hit for invisible symbols, which appear in show-all mode and # when an invisible symbol has visible children (which can happen e.g. for # symbols with optional prompts) if not (node.prompt and expr_value(node.prompt[1])): return False return sc.orig_type in (STRING, INT, HEX) or len(sc.assignable) > 1 \ or _is_y_mode_choice_sym(sc) def _tree_toggle_open(item): # Opens/closes the Treeview item 'item' if _tree.item(item, "open"): _tree.item(item, open=False) else: node = _id_to_node[item] if not isinstance(node.item, Symbol): # Can only get here in full-tree mode _build_full_tree(node) _tree.item(item, open=True) def _tree_set_val(tri_val): def tree_set_val(event): # n/m/y press within the Kconfig treeview # Sets the value of the currently selected item to 'tri_val', if that # value can be assigned sel = event.widget.focus() if sel: sc = _id_to_node[sel].item if isinstance(sc, (Symbol, Choice)) and tri_val in sc.assignable: _set_val(sc, tri_val) return tree_set_val def _tree_open(_): # Lazily populates the Kconfig tree when menus are opened in full-tree mode if _single_menu: # Work around https://core.tcl.tk/tk/tktview?name=368fa4561e # ("ttk::treeview open/closed indicators can be toggled while hidden"). # Clicking on the hidden indicator will call _build_full_tree() in # single-menu mode otherwise. return node = _id_to_node[_tree.focus()] # _shown_full_nodes() includes nodes from menus rooted at symbols, so we # only need to check "real" menus and choices here if not isinstance(node.item, Symbol): _build_full_tree(node) def _update_menu_path(_): # Updates the displayed menu path when nodes are selected in the Kconfig # treeview sel = _tree.selection() _menupath["text"] = _menu_path_info(_id_to_node[sel[0]]) if sel else "" def _item_row(item): # Returns the row number 'item' appears on within the Kconfig treeview, # starting from the top of the tree. Used to preserve scrolling. # # ttkTreeview.c in the Tk sources defines a RowNumber() function that does # the same thing, but it's not exposed. row = 0 while True: prev = _tree.prev(item) if prev: item = prev row += _n_rows(item) else: item = _tree.parent(item) if not item: return row row += 1 def _n_rows(item): # _item_row() helper. Returns the number of rows occupied by 'item' and # # its children. rows = 1 if _tree.item(item, "open"): for child in _tree.get_children(item): rows += _n_rows(child) return rows def _attached(item): # Heuristic for checking if a Treeview item is attached. Doesn't seem to be # good APIs for this. Might fail for super-obscure cases with tiny trees, # but you'd just get a small scroll mess-up. return bool(_tree.next(item) or _tree.prev(item) or _tree.parent(item)) def _change_node(node, parent): # Toggles/changes the value of 'node'. 'parent' is the parent window # (either the main window or the jump-to dialog), in case we need to pop up # a dialog. if not _changeable(node): return # sc = symbol/choice sc = node.item if sc.type in (INT, HEX, STRING): s = _set_val_dialog(node, parent) # Tkinter can return 'unicode' strings on Python 2, which Kconfiglib # can't deal with. UTF-8-encode the string to work around it. if _PY2 and isinstance(s, unicode): s = s.encode("utf-8", "ignore") if s is not None: _set_val(sc, s) elif len(sc.assignable) == 1: # Handles choice symbols for choices in y mode, which are a special # case: .assignable can be (2,) while .tri_value is 0. _set_val(sc, sc.assignable[0]) else: # Set the symbol to the value after the current value in # sc.assignable, with wrapping val_index = sc.assignable.index(sc.tri_value) _set_val(sc, sc.assignable[(val_index + 1) % len(sc.assignable)]) def _set_val(sc, val): # Wrapper around Symbol/Choice.set_value() for updating the menu state and # _conf_changed # Use the string representation of tristate values. This makes the format # consistent for all symbol types. if val in TRI_TO_STR: val = TRI_TO_STR[val] if val != sc.str_value: sc.set_value(val) _set_conf_changed(True) # Update the tree and try to preserve the scroll. Do a cheaper variant # than in the show-all case, that might mess up the scroll slightly in # rare cases, but is fast and flicker-free. stayput = _loc_ref_item() # Item to preserve scroll for old_row = _item_row(stayput) _update_tree() # If the reference item disappeared (can happen if the change was done # from the jump-to dialog), then avoid messing with the scroll and hope # for the best if _attached(stayput): _tree.yview_scroll(_item_row(stayput) - old_row, "units") if _jump_to_tree: _update_jump_to_display() def _set_val_dialog(node, parent): # Pops up a dialog for setting the value of the string/int/hex # symbol at node 'node'. 'parent' is the parent window. def ok(_=None): # No 'nonlocal' in Python 2 global _entry_res s = entry.get() if sym.type == HEX and not s.startswith(("0x", "0X")): s = "0x" + s if _check_valid(dialog, entry, sym, s): _entry_res = s dialog.destroy() def cancel(_=None): global _entry_res _entry_res = None dialog.destroy() sym = node.item dialog = Toplevel(parent) dialog.title("Enter {} value".format(TYPE_TO_STR[sym.type])) dialog.resizable(False, False) dialog.transient(parent) dialog.protocol("WM_DELETE_WINDOW", cancel) ttk.Label(dialog, text=node.prompt[0] + ":") \ .grid(column=0, row=0, columnspan=2, sticky="w", padx=".3c", pady=".2c .05c") entry = ttk.Entry(dialog, width=30) # Start with the previous value in the editbox, selected entry.insert(0, sym.str_value) entry.selection_range(0, "end") entry.grid(column=0, row=1, columnspan=2, sticky="ew", padx=".3c") entry.focus_set() range_info = _range_info(sym) if range_info: ttk.Label(dialog, text=range_info) \ .grid(column=0, row=2, columnspan=2, sticky="w", padx=".3c", pady=".2c 0") ttk.Button(dialog, text="OK", command=ok) \ .grid(column=0, row=4 if range_info else 3, sticky="e", padx=".3c", pady=".4c") ttk.Button(dialog, text="Cancel", command=cancel) \ .grid(column=1, row=4 if range_info else 3, padx="0 .3c") # Give all horizontal space to the grid cell with the OK button, so that # Cancel moves to the right dialog.columnconfigure(0, weight=1) _center_on_root(dialog) # Hack to scroll the entry so that the end of the text is shown, from # https://stackoverflow.com/questions/29334544/why-does-tkinters-entry-xview-moveto-fail. # Related Tk ticket: https://core.tcl.tk/tk/info/2513186fff def scroll_entry(_): _root.update_idletasks() entry.unbind("") entry.xview_moveto(1) entry.bind("", scroll_entry) # The dialog must be visible before we can grab the input dialog.wait_visibility() dialog.grab_set() dialog.bind("", ok) dialog.bind("", ok) dialog.bind("", cancel) # Wait for the user to be done with the dialog parent.wait_window(dialog) # Regrab the input in the parent parent.grab_set() return _entry_res def _center_on_root(dialog): # Centers 'dialog' on the root window. It often ends up at some bad place # like the top-left corner of the screen otherwise. See the menuconfig() # function, which has similar logic. dialog.withdraw() _root.update_idletasks() dialog_width = dialog.winfo_reqwidth() dialog_height = dialog.winfo_reqheight() screen_width = _root.winfo_screenwidth() screen_height = _root.winfo_screenheight() x = _root.winfo_rootx() + (_root.winfo_width() - dialog_width)//2 y = _root.winfo_rooty() + (_root.winfo_height() - dialog_height)//2 # Clamp so that no part of the dialog is outside the screen if x + dialog_width > screen_width: x = screen_width - dialog_width elif x < 0: x = 0 if y + dialog_height > screen_height: y = screen_height - dialog_height elif y < 0: y = 0 dialog.geometry("+{}+{}".format(x, y)) dialog.deiconify() def _check_valid(dialog, entry, sym, s): # Returns True if the string 's' is a well-formed value for 'sym'. # Otherwise, pops up an error and returns False. if sym.type not in (INT, HEX): # Anything goes for non-int/hex symbols return True base = 10 if sym.type == INT else 16 try: int(s, base) except ValueError: messagebox.showerror( "Bad value", "'{}' is a malformed {} value".format( s, TYPE_TO_STR[sym.type]), parent=dialog) entry.focus_set() return False for low_sym, high_sym, cond in sym.ranges: if expr_value(cond): low_s = low_sym.str_value high_s = high_sym.str_value if not int(low_s, base) <= int(s, base) <= int(high_s, base): messagebox.showerror( "Value out of range", "{} is outside the range {}-{}".format(s, low_s, high_s), parent=dialog) entry.focus_set() return False break return True def _range_info(sym): # Returns a string with information about the valid range for the symbol # 'sym', or None if 'sym' doesn't have a range if sym.type in (INT, HEX): for low, high, cond in sym.ranges: if expr_value(cond): return "Range: {}-{}".format(low.str_value, high.str_value) return None def _save(_=None): # Tries to save the configuration if _try_save(_kconf.write_config, _conf_filename, "configuration"): _set_conf_changed(False) _tree.focus_set() def _save_as(): # Pops up a dialog for saving the configuration to a specific location global _conf_filename filename = _conf_filename while True: filename = filedialog.asksaveasfilename( title="Save configuration as", initialdir=os.path.dirname(filename), initialfile=os.path.basename(filename), parent=_root) if not filename: break if _try_save(_kconf.write_config, filename, "configuration"): _conf_filename = filename break _tree.focus_set() def _save_minimal(): # Pops up a dialog for saving a minimal configuration (defconfig) to a # specific location global _minconf_filename filename = _minconf_filename while True: filename = filedialog.asksaveasfilename( title="Save minimal configuration as", initialdir=os.path.dirname(filename), initialfile=os.path.basename(filename), parent=_root) if not filename: break if _try_save(_kconf.write_min_config, filename, "minimal configuration"): _minconf_filename = filename break _tree.focus_set() def _open(_=None): # Pops up a dialog for loading a configuration global _conf_filename if _conf_changed and \ not messagebox.askokcancel( "Unsaved changes", "You have unsaved changes. Load new configuration anyway?"): return filename = _conf_filename while True: filename = filedialog.askopenfilename( title="Open configuration", initialdir=os.path.dirname(filename), initialfile=os.path.basename(filename), parent=_root) if not filename: break if _try_load(filename): # Maybe something fancier could be done here later to try to # preserve the scroll _conf_filename = filename _set_conf_changed(_needs_save()) if _single_menu and not _shown_menu_nodes(_cur_menu): # Turn on show-all if we're in single-menu mode and would end # up with an empty menu _show_all_var.set(True) _update_tree() break _tree.focus_set() def _toggle_showname(_): # Toggles show-name mode on/off _show_name_var.set(not _show_name_var.get()) _do_showname() def _do_showname(): # Updates the UI for the current show-name setting # Columns do not automatically shrink/expand, so we have to update # column widths ourselves tree_width = _tree.winfo_width() if _show_name_var.get(): _tree["displaycolumns"] = ("name",) _tree["show"] = "tree headings" name_width = tree_width//3 _tree.column("#0", width=max(tree_width - name_width, 1)) _tree.column("name", width=name_width) else: _tree["displaycolumns"] = () _tree["show"] = "tree" _tree.column("#0", width=tree_width) _tree.focus_set() def _toggle_showall(_): # Toggles show-all mode on/off _show_all_var.set(not _show_all) _do_showall() def _do_showall(): # Updates the UI for the current show-all setting # Don't allow turning off show-all if we'd end up with no visible nodes if _nothing_shown(): _show_all_var.set(True) return # Save scroll information. old_scroll can end up negative here, if the # reference item isn't shown (only invisible items on the screen, and # show-all being turned off). stayput = _vis_loc_ref_item() # Probe the middle of the first row, to play it safe. identify_row(0) seems # to return the row before the top row. old_scroll = _item_row(stayput) - \ _item_row(_tree.identify_row(_treeview_rowheight//2)) _update_tree() if _show_all: # Deep magic: Unless we call update_idletasks(), the scroll adjustment # below is restricted to the height of the old tree, instead of the # height of the new tree. Since the tree with show-all on is guaranteed # to be taller, and we want the maximum range, we only call it when # turning show-all on. # # Strictly speaking, something similar ought to be done when changing # symbol values, but it causes annoying flicker, and in 99% of cases # things work anyway there (with usually minor scroll mess-ups in the # 1% case). _root.update_idletasks() # Restore scroll _tree.yview(_item_row(stayput) - old_scroll) _tree.focus_set() def _nothing_shown(): # _do_showall() helper. Returns True if no nodes would get # shown with the current show-all setting. Also handles the # (obscure) case when there are no visible nodes in the entire # tree, meaning guiconfig was automatically started in # show-all mode, which mustn't be turned off. return not _shown_menu_nodes( _cur_menu if _single_menu else _kconf.top_node) def _toggle_tree_mode(_): # Toggles single-menu mode on/off _single_menu_var.set(not _single_menu) _do_tree_mode() def _do_tree_mode(): # Updates the UI for the current tree mode (full-tree or single-menu) loc_ref_node = _id_to_node[_loc_ref_item()] if not _single_menu: # _jump_to() -> _enter_menu() already updates the tree, but # _jump_to() -> load_parents() doesn't, because it isn't always needed. # We always need to update the tree here, e.g. to add/remove "--->". _update_tree() _jump_to(loc_ref_node) _tree.focus_set() def _enter_menu_and_select_first(menu): # Enters the menu 'menu' and selects the first item. Used in single-menu # mode. _enter_menu(menu) _select(_tree, _tree.get_children()[0]) def _enter_menu(menu): # Enters the menu 'menu'. Used in single-menu mode. global _cur_menu _cur_menu = menu _update_tree() _backbutton["state"] = "disabled" if menu is _kconf.top_node else "normal" def _leave_menu(): # Leaves the current menu. Used in single-menu mode. global _cur_menu if _cur_menu is not _kconf.top_node: old_menu = _cur_menu _cur_menu = _parent_menu(_cur_menu) _update_tree() _select(_tree, id(old_menu)) if _cur_menu is _kconf.top_node: _backbutton["state"] = "disabled" _tree.focus_set() def _select(tree, item): # Selects, focuses, and see()s 'item' in 'tree' tree.selection_set(item) tree.focus(item) tree.see(item) def _loc_ref_item(): # Returns a Treeview item that can serve as a reference for the current # scroll location. We try to make this item stay on the same row on the # screen when updating the tree. # If the selected item is visible, use that sel = _tree.selection() if sel and _tree.bbox(sel[0]): return sel[0] # Otherwise, use the middle item on the screen. If it doesn't exist, the # tree is probably really small, so use the first item in the entire tree. return _tree.identify_row(_tree.winfo_height()//2) or \ _tree.get_children()[0] def _vis_loc_ref_item(): # Like _loc_ref_item(), but finds a visible item around the reference item. # Used when changing show-all mode, where non-visible (red) items will # disappear. item = _loc_ref_item() vis_before = _vis_before(item) if vis_before and _tree.bbox(vis_before): return vis_before vis_after = _vis_after(item) if vis_after and _tree.bbox(vis_after): return vis_after return vis_before or vis_after def _vis_before(item): # _vis_loc_ref_item() helper. Returns the first visible (not red) item, # searching backwards from 'item'. while item: if not _tree.tag_has("invisible", item): return item prev = _tree.prev(item) item = prev if prev else _tree.parent(item) return None def _vis_after(item): # _vis_loc_ref_item() helper. Returns the first visible (not red) item, # searching forwards from 'item'. while item: if not _tree.tag_has("invisible", item): return item next = _tree.next(item) if next: item = next else: item = _tree.parent(item) if not item: break item = _tree.next(item) return None def _on_quit(_=None): # Called when the user wants to exit if not _conf_changed: _quit("No changes to save (for '{}')".format(_conf_filename)) return while True: ync = messagebox.askyesnocancel("Quit", "Save changes?") if ync is None: return if not ync: _quit("Configuration ({}) was not saved".format(_conf_filename)) return if _try_save(_kconf.write_config, _conf_filename, "configuration"): # _try_save() already prints the "Configuration saved to ..." # message _quit() return def _quit(msg=None): # Quits the application # Do not call sys.exit() here, in case we're being run from a script _root.destroy() if msg: print(msg) def _try_save(save_fn, filename, description): # Tries to save a configuration file. Pops up an error and returns False on # failure. # # save_fn: # Function to call with 'filename' to save the file # # description: # String describing the thing being saved try: # save_fn() returns a message to print msg = save_fn(filename) _set_status(msg) print(msg) return True except EnvironmentError as e: messagebox.showerror( "Error saving " + description, "Error saving {} to '{}': {} (errno: {})" .format(description, e.filename, e.strerror, errno.errorcode[e.errno])) return False def _try_load(filename): # Tries to load a configuration file. Pops up an error and returns False on # failure. # # filename: # Configuration file to load try: msg = _kconf.load_config(filename) _set_status(msg) print(msg) return True except EnvironmentError as e: messagebox.showerror( "Error loading configuration", "Error loading '{}': {} (errno: {})" .format(filename, e.strerror, errno.errorcode[e.errno])) return False def _jump_to_dialog(_=None): # Pops up a dialog for jumping directly to a particular node. Symbol values # can also be changed within the dialog. # # Note: There's nothing preventing this from doing an incremental search # like menuconfig.py does, but currently it's a bit jerky for large Kconfig # trees, at least when inputting the beginning of the search string. We'd # need to somehow only update the tree items that are shown in the Treeview # to fix it. global _jump_to_tree def search(_=None): _update_jump_to_matches(msglabel, entry.get()) def jump_to_selected(event=None): # Jumps to the selected node and closes the dialog # Ignore double clicks on the image and in the heading area if event and (tree.identify_element(event.x, event.y) == "image" or _in_heading(event)): return sel = tree.selection() if not sel: return node = _id_to_node[sel[0]] if node not in _shown_menu_nodes(_parent_menu(node)): _show_all_var.set(True) if not _single_menu: # See comment in _do_tree_mode() _update_tree() _jump_to(node) dialog.destroy() def tree_select(_): jumpto_button["state"] = "normal" if tree.selection() else "disabled" dialog = Toplevel(_root) dialog.geometry("+{}+{}".format( _root.winfo_rootx() + 50, _root.winfo_rooty() + 50)) dialog.title("Jump to symbol/choice/menu/comment") dialog.minsize(128, 128) # See _create_ui() dialog.transient(_root) ttk.Label(dialog, text=_JUMP_TO_HELP) \ .grid(column=0, row=0, columnspan=2, sticky="w", padx=".1c", pady=".1c") entry = ttk.Entry(dialog) entry.grid(column=0, row=1, sticky="ew", padx=".1c", pady=".1c") entry.focus_set() entry.bind("", search) entry.bind("", search) ttk.Button(dialog, text="Search", command=search) \ .grid(column=1, row=1, padx="0 .1c", pady="0 .1c") msglabel = ttk.Label(dialog) msglabel.grid(column=0, row=2, sticky="w", pady="0 .1c") panedwindow, tree = _create_kconfig_tree_and_desc(dialog) panedwindow.grid(column=0, row=3, columnspan=2, sticky="nsew") # Clear tree tree.set_children("") _jump_to_tree = tree jumpto_button = ttk.Button(dialog, text="Jump to selected item", state="disabled", command=jump_to_selected) jumpto_button.grid(column=0, row=4, columnspan=2, sticky="ns", pady=".1c") dialog.columnconfigure(0, weight=1) # Only the pane with the Kconfig tree and description grows vertically dialog.rowconfigure(3, weight=1) # See the menuconfig() function _root.update_idletasks() dialog.geometry(dialog.geometry()) # The dialog must be visible before we can grab the input dialog.wait_visibility() dialog.grab_set() tree.bind("", jump_to_selected) tree.bind("", jump_to_selected) tree.bind("", jump_to_selected) # add=True to avoid overriding the description text update tree.bind("<>", tree_select, add=True) dialog.bind("", lambda _: dialog.destroy()) # Wait for the user to be done with the dialog _root.wait_window(dialog) _jump_to_tree = None _tree.focus_set() def _update_jump_to_matches(msglabel, search_string): # Searches for nodes matching the search string and updates # _jump_to_matches. Puts a message in 'msglabel' if there are no matches, # or regex errors. global _jump_to_matches _jump_to_tree.selection_set(()) try: # We could use re.IGNORECASE here instead of lower(), but this is # faster for regexes like '.*debug$' (though the '.*' is redundant # there). Those probably have bad interactions with re.search(), which # matches anywhere in the string. regex_searches = [re.compile(regex).search for regex in search_string.lower().split()] except re.error as e: msg = "Bad regular expression" # re.error.msg was added in Python 3.5 if hasattr(e, "msg"): msg += ": " + e.msg msglabel["text"] = msg # Clear tree _jump_to_tree.set_children("") return _jump_to_matches = [] add_match = _jump_to_matches.append for node in _sorted_sc_nodes(): # Symbol/choice sc = node.item for search in regex_searches: # Both the name and the prompt might be missing, since # we're searching both symbols and choices # Does the regex match either the symbol name or the # prompt (if any)? if not (sc.name and search(sc.name.lower()) or node.prompt and search(node.prompt[0].lower())): # Give up on the first regex that doesn't match, to # speed things up a bit when multiple regexes are # entered break else: add_match(node) # Search menus and comments for node in _sorted_menu_comment_nodes(): for search in regex_searches: if not search(node.prompt[0].lower()): break else: add_match(node) msglabel["text"] = "" if _jump_to_matches else "No matches" _update_jump_to_display() if _jump_to_matches: item = id(_jump_to_matches[0]) _jump_to_tree.selection_set(item) _jump_to_tree.focus(item) def _update_jump_to_display(): # Updates the images and text for the items in _jump_to_matches, and sets # them as the items of _jump_to_tree # Micro-optimize a bit item = _jump_to_tree.item id_ = id node_str = _node_str img_tag = _img_tag visible = _visible for node in _jump_to_matches: item(id_(node), text=node_str(node), tags=img_tag(node) if visible(node) else img_tag(node) + " invisible") _jump_to_tree.set_children("", *map(id, _jump_to_matches)) def _jump_to(node): # Jumps directly to 'node' and selects it if _single_menu: _enter_menu(_parent_menu(node)) else: _load_parents(node) _select(_tree, id(node)) # Obscure Python: We never pass a value for cached_nodes, and it keeps pointing # to the same list. This avoids a global. def _sorted_sc_nodes(cached_nodes=[]): # Returns a sorted list of symbol and choice nodes to search. The symbol # nodes appear first, sorted by name, and then the choice nodes, sorted by # prompt and (secondarily) name. if not cached_nodes: # Add symbol nodes for sym in sorted(_kconf.unique_defined_syms, key=lambda sym: sym.name): # += is in-place for lists cached_nodes += sym.nodes # Add choice nodes choices = sorted(_kconf.unique_choices, key=lambda choice: choice.name or "") cached_nodes += sorted( [node for choice in choices for node in choice.nodes], key=lambda node: node.prompt[0] if node.prompt else "") return cached_nodes def _sorted_menu_comment_nodes(cached_nodes=[]): # Returns a list of menu and comment nodes to search, sorted by prompt, # with the menus first if not cached_nodes: def prompt_text(mc): return mc.prompt[0] cached_nodes += sorted(_kconf.menus, key=prompt_text) cached_nodes += sorted(_kconf.comments, key=prompt_text) return cached_nodes def _load_parents(node): # Menus are lazily populated as they're opened in full-tree mode, but # jumping to an item needs its parent menus to be populated. This function # populates 'node's parents. # Get all parents leading up to 'node', sorted with the root first parents = [] cur = node.parent while cur is not _kconf.top_node: parents.append(cur) cur = cur.parent parents.reverse() for i, parent in enumerate(parents): if not _tree.item(id(parent), "open"): # Found a closed menu. Populate it and all the remaining menus # leading up to 'node'. for parent in parents[i:]: # We only need to populate "real" menus/choices. Implicit menus # are populated when their parents menus are entered. if not isinstance(parent.item, Symbol): _build_full_tree(parent) return def _parent_menu(node): # Returns the menu node of the menu that contains 'node'. In addition to # proper 'menu's, this might also be a 'menuconfig' symbol or a 'choice'. # "Menu" here means a menu in the interface. menu = node.parent while not menu.is_menuconfig: menu = menu.parent return menu def _trace_write(var, fn): # Makes fn() be called whenever the Tkinter Variable 'var' changes value # trace_variable() is deprecated according to the docstring, # which recommends trace_add() if hasattr(var, "trace_add"): var.trace_add("write", fn) else: var.trace_variable("w", fn) def _info_str(node): # Returns information about the menu node 'node' as a string. # # The helper functions are responsible for adding newlines. This allows # them to return "" if they don't want to add any output. if isinstance(node.item, Symbol): sym = node.item return ( _name_info(sym) + _help_info(sym) + _direct_dep_info(sym) + _defaults_info(sym) + _select_imply_info(sym) + _kconfig_def_info(sym) ) if isinstance(node.item, Choice): choice = node.item return ( _name_info(choice) + _help_info(choice) + 'Mode: {}\n\n'.format(choice.str_value) + _choice_syms_info(choice) + _direct_dep_info(choice) + _defaults_info(choice) + _kconfig_def_info(choice) ) # node.item in (MENU, COMMENT) return _kconfig_def_info(node) def _name_info(sc): # Returns a string with the name of the symbol/choice. Choices are shown as # . return (sc.name if sc.name else standard_sc_expr_str(sc)) + "\n\n" def _value_info(sym): # Returns a string showing 'sym's value # Only put quotes around the value for string symbols return "Value: {}\n".format( '"{}"'.format(sym.str_value) if sym.orig_type == STRING else sym.str_value) def _choice_syms_info(choice): # Returns a string listing the choice symbols in 'choice'. Adds # "(selected)" next to the selected one. s = "Choice symbols:\n" for sym in choice.syms: s += " - " + sym.name if sym is choice.selection: s += " (selected)" s += "\n" return s + "\n" def _help_info(sc): # Returns a string with the help text(s) of 'sc' (Symbol or Choice). # Symbols and choices defined in multiple locations can have multiple help # texts. s = "" for node in sc.nodes: if node.help is not None: s += node.help + "\n\n" return s def _direct_dep_info(sc): # Returns a string describing the direct dependencies of 'sc' (Symbol or # Choice). The direct dependencies are the OR of the dependencies from each # definition location. The dependencies at each definition location come # from 'depends on' and dependencies inherited from parent items. return "" if sc.direct_dep is _kconf.y else \ 'Direct dependencies (={}):\n{}\n' \ .format(TRI_TO_STR[expr_value(sc.direct_dep)], _split_expr_info(sc.direct_dep, 2)) def _defaults_info(sc): # Returns a string describing the defaults of 'sc' (Symbol or Choice) if not sc.defaults: return "" s = "Default" if len(sc.defaults) > 1: s += "s" s += ":\n" for val, cond in sc.orig_defaults: s += " - " if isinstance(sc, Symbol): s += _expr_str(val) # Skip the tristate value hint if the expression is just a single # symbol. _expr_str() already shows its value as a string. # # This also avoids showing the tristate value for string/int/hex # defaults, which wouldn't make any sense. if isinstance(val, tuple): s += ' (={})'.format(TRI_TO_STR[expr_value(val)]) else: # Don't print the value next to the symbol name for choice # defaults, as it looks a bit confusing s += val.name s += "\n" if cond is not _kconf.y: s += " Condition (={}):\n{}" \ .format(TRI_TO_STR[expr_value(cond)], _split_expr_info(cond, 4)) return s + "\n" def _split_expr_info(expr, indent): # Returns a string with 'expr' split into its top-level && or || operands, # with one operand per line, together with the operand's value. This is # usually enough to get something readable for long expressions. A fancier # recursive thingy would be possible too. # # indent: # Number of leading spaces to add before the split expression. if len(split_expr(expr, AND)) > 1: split_op = AND op_str = "&&" else: split_op = OR op_str = "||" s = "" for i, term in enumerate(split_expr(expr, split_op)): s += "{}{} {}".format(indent*" ", " " if i == 0 else op_str, _expr_str(term)) # Don't bother showing the value hint if the expression is just a # single symbol. _expr_str() already shows its value. if isinstance(term, tuple): s += " (={})".format(TRI_TO_STR[expr_value(term)]) s += "\n" return s def _select_imply_info(sym): # Returns a string with information about which symbols 'select' or 'imply' # 'sym'. The selecting/implying symbols are grouped according to which # value they select/imply 'sym' to (n/m/y). def sis(expr, val, title): # sis = selects/implies sis = [si for si in split_expr(expr, OR) if expr_value(si) == val] if not sis: return "" res = title for si in sis: res += " - {}\n".format(split_expr(si, AND)[0].name) return res + "\n" s = "" if sym.rev_dep is not _kconf.n: s += sis(sym.rev_dep, 2, "Symbols currently y-selecting this symbol:\n") s += sis(sym.rev_dep, 1, "Symbols currently m-selecting this symbol:\n") s += sis(sym.rev_dep, 0, "Symbols currently n-selecting this symbol (no effect):\n") if sym.weak_rev_dep is not _kconf.n: s += sis(sym.weak_rev_dep, 2, "Symbols currently y-implying this symbol:\n") s += sis(sym.weak_rev_dep, 1, "Symbols currently m-implying this symbol:\n") s += sis(sym.weak_rev_dep, 0, "Symbols currently n-implying this symbol (no effect):\n") return s def _kconfig_def_info(item): # Returns a string with the definition of 'item' in Kconfig syntax, # together with the definition location(s) and their include and menu paths nodes = [item] if isinstance(item, MenuNode) else item.nodes s = "Kconfig definition{}, with parent deps. propagated to 'depends on'\n" \ .format("s" if len(nodes) > 1 else "") s += (len(s) - 1)*"=" for node in nodes: s += "\n\n" \ "At {}:{}\n" \ "{}" \ "Menu path: {}\n\n" \ "{}" \ .format(node.filename, node.linenr, _include_path_info(node), _menu_path_info(node), node.custom_str(_name_and_val_str)) return s def _include_path_info(node): if not node.include_path: # In the top-level Kconfig file return "" return "Included via {}\n".format( " -> ".join("{}:{}".format(filename, linenr) for filename, linenr in node.include_path)) def _menu_path_info(node): # Returns a string describing the menu path leading up to 'node' path = "" while node.parent is not _kconf.top_node: node = node.parent # Promptless choices might appear among the parents. Use # standard_sc_expr_str() for them, so that they show up as # ''. path = " -> " + (node.prompt[0] if node.prompt else standard_sc_expr_str(node.item)) + path return "(Top)" + path def _name_and_val_str(sc): # Custom symbol/choice printer that shows symbol values after symbols # Show the values of non-constant (non-quoted) symbols that don't look like # numbers. Things like 123 are actually symbol references, and only work as # expected due to undefined symbols getting their name as their value. # Showing the symbol value for those isn't helpful though. if isinstance(sc, Symbol) and not sc.is_constant and not _is_num(sc.name): if not sc.nodes: # Undefined symbol reference return "{}(undefined/n)".format(sc.name) return '{}(={})'.format(sc.name, sc.str_value) # For other items, use the standard format return standard_sc_expr_str(sc) def _expr_str(expr): # Custom expression printer that shows symbol values return expr_str(expr, _name_and_val_str) def _is_num(name): # Heuristic to see if a symbol name looks like a number, for nicer output # when printing expressions. Things like 16 are actually symbol names, only # they get their name as their value when the symbol is undefined. try: int(name) except ValueError: if not name.startswith(("0x", "0X")): return False try: int(name, 16) except ValueError: return False return True if __name__ == "__main__": _main() hart-software-services-2022.10/thirdparty/Kconfiglib/kconfiglib.py000066400000000000000000007732441432224323300252300ustar00rootroot00000000000000# Copyright (c) 2011-2019, Ulf Magnusson # SPDX-License-Identifier: ISC """ Overview ======== Kconfiglib is a Python 2/3 library for scripting and extracting information from Kconfig (https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt) configuration systems. See the homepage at https://github.com/ulfalizer/Kconfiglib for a longer overview. Since Kconfiglib 12.0.0, the library version is available in kconfiglib.VERSION, which is a (, , ) tuple, e.g. (12, 0, 0). Using Kconfiglib on the Linux kernel with the Makefile targets ============================================================== For the Linux kernel, a handy interface is provided by the scripts/kconfig/Makefile patch, which can be applied with either 'git am' or the 'patch' utility: $ wget -qO- https://raw.githubusercontent.com/ulfalizer/Kconfiglib/master/makefile.patch | git am $ wget -qO- https://raw.githubusercontent.com/ulfalizer/Kconfiglib/master/makefile.patch | patch -p1 Warning: Not passing -p1 to patch will cause the wrong file to be patched. Please tell me if the patch does not apply. It should be trivial to apply manually, as it's just a block of text that needs to be inserted near the other *conf: targets in scripts/kconfig/Makefile. Look further down for a motivation for the Makefile patch and for instructions on how you can use Kconfiglib without it. If you do not wish to install Kconfiglib via pip, the Makefile patch is set up so that you can also just clone Kconfiglib into the kernel root: $ git clone git://github.com/ulfalizer/Kconfiglib.git $ git am Kconfiglib/makefile.patch (or 'patch -p1 < Kconfiglib/makefile.patch') Warning: The directory name Kconfiglib/ is significant in this case, because it's added to PYTHONPATH by the new targets in makefile.patch. The targets added by the Makefile patch are described in the following sections. make kmenuconfig ---------------- This target runs the curses menuconfig interface with Python 3. As of Kconfiglib 12.2.0, both Python 2 and Python 3 are supported (previously, only Python 3 was supported, so this was a backport). make guiconfig -------------- This target runs the Tkinter menuconfig interface. Both Python 2 and Python 3 are supported. To change the Python interpreter used, pass PYTHONCMD= to 'make'. The default is 'python'. make [ARCH=] iscriptconfig -------------------------------- This target gives an interactive Python prompt where a Kconfig instance has been preloaded and is available in 'kconf'. To change the Python interpreter used, pass PYTHONCMD= to 'make'. The default is 'python'. To get a feel for the API, try evaluating and printing the symbols in kconf.defined_syms, and explore the MenuNode menu tree starting at kconf.top_node by following 'next' and 'list' pointers. The item contained in a menu node is found in MenuNode.item (note that this can be one of the constants kconfiglib.MENU and kconfiglib.COMMENT), and all symbols and choices have a 'nodes' attribute containing their menu nodes (usually only one). Printing a menu node will print its item, in Kconfig format. If you want to look up a symbol by name, use the kconf.syms dictionary. make scriptconfig SCRIPT=