pax_global_header 0000666 0000000 0000000 00000000064 14322243233 0014510 g ustar 00root root 0000000 0000000 52 comment=94e86d109a4eaa1a093efc66059b74648ebf6dc5
hart-software-services-2022.10/ 0000775 0000000 0000000 00000000000 14322243233 0016265 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/.cproject 0000664 0000000 0000000 00000102042 14322243233 0020076 0 ustar 00root root 0000000 0000000
hart-software-services-2022.10/.github/ 0000775 0000000 0000000 00000000000 14322243233 0017625 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/.github/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006210 14322243233 0022423 0 ustar 00root root 0000000 0000000 # 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.md 0000664 0000000 0000000 00000006110 14322243233 0022054 0 ustar 00root root 0000000 0000000 # 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.md 0000664 0000000 0000000 00000003177 14322243233 0023202 0 ustar 00root root 0000000 0000000 # 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.md 0000664 0000000 0000000 00000002155 14322243233 0024571 0 ustar 00root root 0000000 0000000 # 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/ 0000775 0000000 0000000 00000000000 14322243233 0021662 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/.github/workflows/build-hss.yaml 0000664 0000000 0000000 00000000530 14322243233 0024436 0 ustar 00root root 0000000 0000000 on: [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/.gitignore 0000664 0000000 0000000 00000000134 14322243233 0020253 0 ustar 00root root 0000000 0000000 *.d
*.o
*.bin
*.elf
*.hex
*.map
*.sym
.config
.config.old
config.h
include/tool_versions.h
hart-software-services-2022.10/.project 0000664 0000000 0000000 00000001467 14322243233 0017744 0 ustar 00root root 0000000 0000000
hart-software-servicesorg.eclipse.cdt.managedbuilder.core.genmakebuilderclean,full,incremental,org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilderfull,incremental,org.eclipse.cdt.core.cnatureorg.eclipse.cdt.core.ccnatureorg.eclipse.cdt.managedbuilder.core.managedBuildNatureorg.eclipse.cdt.managedbuilder.core.ScannerConfigNature
hart-software-services-2022.10/CHANGELOG.md 0000664 0000000 0000000 00000005424 14322243233 0020103 0 ustar 00root root 0000000 0000000 # 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/ 0000775 0000000 0000000 00000000000 14322243233 0017651 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/Default/README.md 0000664 0000000 0000000 00000000155 14322243233 0021131 0 ustar 00root root 0000000 0000000 This directory is used by SoftConsole programming.
It will contain the hexfile output from the HSS build.
hart-software-services-2022.10/Kconfig 0000664 0000000 0000000 00000000312 14322243233 0017564 0 ustar 00root root 0000000 0000000 mainmenu "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.md 0000664 0000000 0000000 00000010165 14322243233 0017674 0 ustar 00root root 0000000 0000000 # 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/Makefile 0000664 0000000 0000000 00000010131 14322243233 0017721 0 ustar 00root root 0000000 0000000 #
# 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.md 0000664 0000000 0000000 00000020136 14322243233 0017546 0 ustar 00root root 0000000 0000000 # 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/ 0000775 0000000 0000000 00000000000 14322243233 0020570 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/application/Kconfig.build 0000664 0000000 0000000 00000005734 14322243233 0023202 0 ustar 00root root 0000000 0000000 mainmenu "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.general 0000664 0000000 0000000 00000005711 14322243233 0023513 0 ustar 00root root 0000000 0000000 menu "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/Makefile 0000664 0000000 0000000 00000003705 14322243233 0022235 0 ustar 00root root 0000000 0000000 #
# 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.S 0000664 0000000 0000000 00000027702 14322243233 0021514 0 ustar 00root root 0000000 0000000 /*
* 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/ 0000775 0000000 0000000 00000000000 14322243233 0021606 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/application/hart0/hss_clock.c 0000664 0000000 0000000 00000002273 14322243233 0023726 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000017677 14322243233 0023614 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000004362 14322243233 0023560 0 ustar 00root root 0000000 0000000 /******************************************************************************************
*
* 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.c 0000664 0000000 0000000 00000021605 14322243233 0024503 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000021771 14322243233 0025443 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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/ 0000775 0000000 0000000 00000000000 14322243233 0021750 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/application/hart1-4/u54_handle_ipi.c 0000664 0000000 0000000 00000010152 14322243233 0024704 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000006607 14322243233 0023742 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.mk 0000775 0000000 0000000 00000003343 14322243233 0021550 0 ustar 00root root 0000000 0000000 #
# 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.mk 0000664 0000000 0000000 00000014431 14322243233 0022256 0 ustar 00root root 0000000 0000000 #
# 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.mk 0000664 0000000 0000000 00000016227 14322243233 0022602 0 ustar 00root root 0000000 0000000 #
# 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/ 0000775 0000000 0000000 00000000000 14322243233 0020221 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/Makefile 0000664 0000000 0000000 00000017366 14322243233 0021676 0 ustar 00root root 0000000 0000000 #
# 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.md 0000664 0000000 0000000 00000001222 14322243233 0021475 0 ustar 00root root 0000000 0000000 # 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/ 0000775 0000000 0000000 00000000000 14322243233 0021677 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/fpga_ip/ 0000775 0000000 0000000 00000000000 14322243233 0023304 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/ 0000775 0000000 0000000 00000000000 14322243233 0024722 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/fpga_ip/miv_ihc/miv_ihc.c 0000664 0000000 0000000 00000056356 14322243233 0026523 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000101312 14322243233 0026507 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000010546 14322243233 0033060 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000005422 14322243233 0030211 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000040700 14322243233 0027532 0 ustar 00root root 0000000 0000000 /******************************************************************************
* 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.h 0000664 0000000 0000000 00000004300 14322243233 0030253 0 ustar 00root root 0000000 0000000 #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/ 0000775 0000000 0000000 00000000000 14322243233 0024216 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/micron_mt25q/micron_mt25q.c 0000664 0000000 0000000 00000062361 14322243233 0026711 0 ustar 00root root 0000000 0000000 /***************************************************************************//**
* 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.h 0000664 0000000 0000000 00000016103 14322243233 0026707 0 ustar 00root root 0000000 0000000 /***************************************************************************//**
* 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/ 0000775 0000000 0000000 00000000000 14322243233 0022501 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/ 0000775 0000000 0000000 00000000000 14322243233 0024154 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/mss/mss_usb/mss_usb_common_cif.c 0000664 0000000 0000000 00000065421 14322243233 0030174 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000037160 14322243233 0030200 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000073240 14322243233 0030702 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000005515 14322243233 0027333 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000045704 14322243233 0030042 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000212252 14322243233 0027316 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000142412 14322243233 0027323 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000024641 14322243233 0030142 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000012425 14322243233 0030144 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.c 0000664 0000000 0000000 00000175436 14322243233 0030175 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000043073 14322243233 0030171 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000003744 14322243233 0030653 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000000750 14322243233 0027022 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000021716 14322243233 0027477 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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/ 0000775 0000000 0000000 00000000000 14322243233 0025163 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/mss/mss_watchdog/mss_watchdog.c 0000664 0000000 0000000 00000006244 14322243233 0030017 0 ustar 00root root 0000000 0000000 /***************************************************************************//**
* 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.h 0000664 0000000 0000000 00000075774 14322243233 0030042 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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/ 0000775 0000000 0000000 00000000000 14322243233 0024710 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/drivers/winbond_w25n01gv/winbond_w25n01gv.c 0000664 0000000 0000000 00000047744 14322243233 0030105 0 ustar 00root root 0000000 0000000 /***************************************************************************//**
* 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.h 0000664 0000000 0000000 00000023353 14322243233 0030100 0 ustar 00root root 0000000 0000000 /***************************************************************************//**
* 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/ 0000775 0000000 0000000 00000000000 14322243233 0026437 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/readme.md 0000664 0000000 0000000 00000006561 14322243233 0030226 0 ustar 00root root 0000000 0000000 # 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/ 0000775 0000000 0000000 00000000000 14322243233 0027226 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/ 0000775 0000000 0000000 00000000000 14322243233 0031052 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/ 0000775 0000000 0000000 00000000000 14322243233 0032530 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss/ 0000775 0000000 0000000 00000000000 14322243233 0033332 5 ustar 00root root 0000000 0000000 mss_can/ 0000775 0000000 0000000 00000000000 14322243233 0034676 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_can.c 0000664 0000000 0000000 00000067574 14322243233 0036510 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000251077 14322243233 0036506 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0036573 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_ethernet_mac.c 0000664 0000000 0000000 00000461214 14322243233 0042267 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000354054 14322243233 0042277 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000143520 14322243233 0043311 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000112024 14322243233 0043510 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000014362 14322243233 0044655 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000074315 14322243233 0043545 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000005602 14322243233 0040574 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000041202 14322243233 0037543 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000044145 14322243233 0041346 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000024266 14322243233 0040746 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000076164 14322243233 0040761 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000037246 14322243233 0041673 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0035073 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_gpio.c 0000664 0000000 0000000 00000032444 14322243233 0037066 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000116042 14322243233 0037070 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034612 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_i2c.c 0000664 0000000 0000000 00000141115 14322243233 0036320 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000256747 14322243233 0036347 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000004516 14322243233 0037350 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034711 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_mmc.c 0000664 0000000 0000000 00000366312 14322243233 0036526 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000132356 14322243233 0036532 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000027554 14322243233 0037206 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000011635 14322243233 0037204 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000050467 14322243233 0041261 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000147410 14322243233 0037547 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000025527 14322243233 0037757 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0035442 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_uart.c 0000664 0000000 0000000 00000140452 14322243233 0037451 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000376100 14322243233 0037457 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000017020 14322243233 0040470 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0035056 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_pdma.c 0000664 0000000 0000000 00000027734 14322243233 0037042 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000054174 14322243233 0037045 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0035111 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_qspi.c 0000664 0000000 0000000 00000023653 14322243233 0037124 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000071647 14322243233 0037137 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000014237 14322243233 0040147 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034725 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_rtc.c 0000664 0000000 0000000 00000050520 14322243233 0036545 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000101721 14322243233 0036552 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000004626 14322243233 0037600 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034730 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_spi.c 0000664 0000000 0000000 00000134714 14322243233 0036563 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000154154 14322243233 0036570 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0036656 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_sys_services.c 0000664 0000000 0000000 00000166163 14322243233 0042442 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000471213 14322243233 0042442 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000004031 14322243233 0043450 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0035255 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_timer.h 0000664 0000000 0000000 00000072544 14322243233 0037444 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000003707 14322243233 0040457 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034726 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers/mss mss_usb_common_cif.c 0000664 0000000 0000000 00000065446 14322243233 0040755 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000037227 14322243233 0040756 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000073315 14322243233 0041457 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000005567 14322243233 0040114 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000045756 14322243233 0040623 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000214042 14322243233 0037605 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000226324 14322243233 0037620 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000026627 14322243233 0040440 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000031354 14322243233 0040436 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000051072 14322243233 0040433 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000035754 14322243233 0040451 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000127161 14322243233 0040454 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000110472 14322243233 0040456 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000052475 14322243233 0041150 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000001022 14322243233 0037565 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000021776 14322243233 0040257 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034056 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/drivers pf_pcie.c 0000664 0000000 0000000 00000144316 14322243233 0035640 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000106701 14322243233 0035641 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000132302 14322243233 0036655 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000027021 14322243233 0037062 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0031616 5 ustar 00root root 0000000 0000000 cpu_types.h 0000664 0000000 0000000 00000001610 14322243233 0033721 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000025704 14322243233 0032543 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000003041 14322243233 0034033 0 ustar 00root root 0000000 0000000 hart-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.c0000664 0000000 0000000 00000002223 14322243233 0033400 0 ustar 00root root 0000000 0000000 /*******************************************************************************
* 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.h 0000664 0000000 0000000 00000010242 14322243233 0033671 0 ustar 00root root 0000000 0000000 hart-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.S 0000664 0000000 0000000 00000013027 14322243233 0034462 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000016762 14322243233 0034520 0 ustar 00root root 0000000 0000000 hart-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.md0000664 0000000 0000000 00000003047 14322243233 0033401 0 ustar 00root root 0000000 0000000 ===============================================================================
# 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/ 0000775 0000000 0000000 00000000000 14322243233 0032643 5 ustar 00root root 0000000 0000000 Jenkinsfile 0000664 0000000 0000000 00000000142 14322243233 0034745 0 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal @Library('automated-testing-library') _
pipelineBareMetalDriverSrc(examplesRepoBranch: 'develop')
common/ 0000775 0000000 0000000 00000000000 14322243233 0034054 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal atomic.h 0000664 0000000 0000000 00000004542 14322243233 0035506 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000005102 14322243233 0035164 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000152525 14322243233 0036025 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000001577 14322243233 0036422 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000021705 14322243233 0037112 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000013714 14322243233 0037120 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000007017 14322243233 0036220 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000005671 14322243233 0036231 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000044735 14322243233 0035576 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000005370 14322243233 0035573 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000035636 14322243233 0037117 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000064012 14322243233 0040615 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000026317 14322243233 0036553 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000070030 14322243233 0036547 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000130011 14322243233 0040044 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000022204 14322243233 0035703 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000012141 14322243233 0035707 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000047156 14322243233 0036242 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000006262 14322243233 0036240 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000017734 14322243233 0037434 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000012006 14322243233 0037424 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000001265 14322243233 0036035 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000111513 14322243233 0036040 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000022166 14322243233 0035705 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000006132 14322243233 0035705 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000003437 14322243233 0035674 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000673630 14322243233 0036442 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000013474 14322243233 0036070 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000004454 14322243233 0036073 0 ustar 00root root 0000000 0000000 hart-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/ 0000775 0000000 0000000 00000000000 14322243233 0034643 5 ustar 00root root 0000000 0000000 hart-software-services-2022.10/baremetal/polarfire-soc-bare-metal-library/src/platform/mpfs_hal/common mss_cfm.c 0000664 0000000 0000000 00000010027 14322243233 0036436 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000017126 14322243233 0036452 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000766721 14322243233 0036465 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000127143 14322243233 0036457 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000067262 14322243233 0037625 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000012734 14322243233 0037624 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000004246 14322243233 0037456 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000714741 14322243233 0041536 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00001050425 14322243233 0040666 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000022743 14322243233 0041246 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000051463 14322243233 0036311 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000043313 14322243233 0037636 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000034061 14322243233 0037507 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000016745 14322243233 0037525 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000061672 14322243233 0036474 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000032061 14322243233 0036467 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000012011 14322243233 0040327 0 ustar 00root root 0000000 0000000 hart-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.c 0000664 0000000 0000000 00000054000 14322243233 0037000 0 ustar 00root root 0000000 0000000 hart-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.h 0000664 0000000 0000000 00000022347 14322243233 0037016 0 ustar 00root root 0000000 0000000 hart-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<