mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-19 21:11:57 -04:00
Update RISCC-V-RV32-SiFive_HiFive1_FreedomStudio project to latest tools and metal library versions.
This commit is contained in:
parent
cfa83672ef
commit
4b943b35e0
|
@ -1,88 +1,174 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" moduleId="org.eclipse.cdt.core.settings" name="Debug">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug">
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480." name="/" resourcePath="">
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1023181676" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.1119183919" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
|
||||
<builder buildPath="${workspace_loc:/RTOSDemo}/Debug" id="cdt.managedbuild.builder.gnu.cross.1388532167" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/>
|
||||
<tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
|
||||
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.440219377" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||
<option id="gnu.c.compiler.option.debugging.level.1721555429" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.max" valueType="enumerated"/>
|
||||
<option id="gnu.c.compiler.option.dialect.std.1648189865" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/>
|
||||
<option id="gnu.c.compiler.option.include.paths.1720192082" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/full_demo/Common_Demo_Tasks/include}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/freedom-metal}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/bsp/install/include}""/>
|
||||
</option>
|
||||
<option id="gnu.c.compiler.option.misc.other.257964774" name="Other flags" superClass="gnu.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -fmessage-length=0 -march=rv32imac -mabi=ilp32 -mcmodel=medlow -ffunction-sections -fdata-sections --specs=nano.specs" valueType="string"/>
|
||||
<option id="gnu.c.compiler.option.warnings.extrawarn.1802410957" name="Extra warnings (-Wextra)" superClass="gnu.c.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1079251302" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.420742449" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
|
||||
<option id="gnu.cpp.compiler.option.optimization.level.1056760450" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
|
||||
<option id="gnu.cpp.compiler.option.debugging.level.52506316" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
|
||||
</tool>
|
||||
<tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.linker.558060359" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">
|
||||
<option id="gnu.c.link.option.ldflags.46965227" name="Linker flags" superClass="gnu.c.link.option.ldflags" useByScannerDiscovery="false" value="-Xlinker --gc-sections -Wl,-Map,RTOSDemo.map -T../bsp/metal.default.lds -march=rv32imac -mabi=ilp32 -mcmodel=medlow -Wl,--start-group -lc -lgcc -Wl,--end-group --specs=nano.specs" valueType="string"/>
|
||||
<option id="gnu.c.link.option.nostart.1038463237" name="Do not use standard start files (-nostartfiles)" superClass="gnu.c.link.option.nostart" useByScannerDiscovery="false" value="true" valueType="boolean"/>
|
||||
<option id="gnu.c.link.option.nostdlibs.934043026" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
|
||||
<option id="gnu.c.link.option.nodeflibs.1095611620" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.549526426" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2105463183" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.424513814" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
|
||||
<tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.assembler.825438707" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
|
||||
<option id="gnu.both.asm.option.flags.1946908814" name="Assembler flags" superClass="gnu.both.asm.option.flags" useByScannerDiscovery="false" value="-march=rv32imac -mabi=ilp32 -mcmodel=medlow -c -DportasmHANDLE_INTERRUPT=handle_trap -g3" valueType="string"/>
|
||||
<option id="gnu.both.asm.option.include.paths.1448234506" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions/RV32I_CLINT_no_extensions}""/>
|
||||
</option>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1723023894" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="RTOSDemo.cdt.managedbuild.target.gnu.cross.exe.1669036252" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.206163480;cdt.managedbuild.config.gnu.cross.exe.debug.206163480.;cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065;cdt.managedbuild.tool.gnu.c.compiler.input.1079251302">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
<configuration configurationName="Debug">
|
||||
<resource resourceType="PROJECT" workspacePath="/RTOSDemo"/>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
|
||||
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480">
|
||||
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" moduleId="org.eclipse.cdt.core.settings" name="Debug">
|
||||
|
||||
<externalSettings/>
|
||||
|
||||
<extensions>
|
||||
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
|
||||
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug">
|
||||
|
||||
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480." name="/" resourcePath="">
|
||||
|
||||
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1023181676" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
|
||||
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.1119183919" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
|
||||
|
||||
<builder buildPath="${workspace_loc:/RTOSDemo}/Debug" id="cdt.managedbuild.builder.gnu.cross.1388532167" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/>
|
||||
|
||||
<tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
|
||||
|
||||
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.440219377" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
|
||||
|
||||
<option id="gnu.c.compiler.option.debugging.level.1721555429" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.max" valueType="enumerated"/>
|
||||
|
||||
<option id="gnu.c.compiler.option.dialect.std.1648189865" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/>
|
||||
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.c.compiler.option.include.paths.1720192082" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/full_demo/Common_Demo_Tasks/include}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/include}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/freedom-metal}""/>
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/bsp/install/include}""/>
|
||||
|
||||
</option>
|
||||
|
||||
<option id="gnu.c.compiler.option.misc.other.257964774" name="Other flags" superClass="gnu.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -fmessage-length=0 -march=rv32imac -mabi=ilp32 -mcmodel=medlow -ffunction-sections -fdata-sections --specs=nano.specs -Wno-unused-parameter" valueType="string"/>
|
||||
|
||||
<option id="gnu.c.compiler.option.warnings.extrawarn.1802410957" name="Extra warnings (-Wextra)" superClass="gnu.c.compiler.option.warnings.extrawarn" useByScannerDiscovery="false" value="true" valueType="boolean"/>
|
||||
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1079251302" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.420742449" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
|
||||
|
||||
<option id="gnu.cpp.compiler.option.optimization.level.1056760450" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
|
||||
|
||||
<option id="gnu.cpp.compiler.option.debugging.level.52506316" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.c.linker.558060359" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker">
|
||||
|
||||
<option id="gnu.c.link.option.ldflags.46965227" name="Linker flags" superClass="gnu.c.link.option.ldflags" useByScannerDiscovery="false" value="-Xlinker --gc-sections -Wl,-Map,RTOSDemo.map -T../bsp/metal.default.lds -march=rv32imac -mabi=ilp32 -mcmodel=medlow -Wl,--start-group -lc -lgcc -Wl,--end-group --specs=nano.specs" valueType="string"/>
|
||||
|
||||
<option id="gnu.c.link.option.nostart.1038463237" name="Do not use standard start files (-nostartfiles)" superClass="gnu.c.link.option.nostart" useByScannerDiscovery="false" value="true" valueType="boolean"/>
|
||||
|
||||
<option id="gnu.c.link.option.nostdlibs.934043026" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
|
||||
|
||||
<option id="gnu.c.link.option.nodeflibs.1095611620" name="Do not use default libraries (-nodefaultlibs)" superClass="gnu.c.link.option.nodeflibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
|
||||
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.549526426" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
|
||||
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
|
||||
</inputType>
|
||||
|
||||
</tool>
|
||||
|
||||
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.2105463183" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker"/>
|
||||
|
||||
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.424513814" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
|
||||
|
||||
<tool command="riscv64-unknown-elf-gcc.exe" id="cdt.managedbuild.tool.gnu.cross.assembler.825438707" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
|
||||
|
||||
<option id="gnu.both.asm.option.flags.1946908814" name="Assembler flags" superClass="gnu.both.asm.option.flags" useByScannerDiscovery="false" value="-march=rv32imac -mabi=ilp32 -mcmodel=medlow -c -DportasmHANDLE_INTERRUPT=handle_trap -g3" valueType="string"/>
|
||||
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="gnu.both.asm.option.include.paths.1448234506" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
|
||||
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/FreeRTOS_Source/portable/GCC/RISC-V/chip_specific_extensions/RV32I_CLINT_no_extensions}""/>
|
||||
|
||||
</option>
|
||||
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1723023894" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
|
||||
</tool>
|
||||
|
||||
</toolChain>
|
||||
|
||||
</folderInfo>
|
||||
|
||||
<sourceEntries>
|
||||
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
|
||||
</sourceEntries>
|
||||
|
||||
</configuration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
|
||||
</cconfiguration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
|
||||
<project id="RTOSDemo.cdt.managedbuild.target.gnu.cross.exe.1669036252" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
|
||||
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.206163480;cdt.managedbuild.config.gnu.cross.exe.debug.206163480.;cdt.managedbuild.tool.gnu.cross.c.compiler.1469975065;cdt.managedbuild.tool.gnu.c.compiler.input.1079251302">
|
||||
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
|
||||
</scannerConfigBuildInfo>
|
||||
|
||||
</storageModule>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
|
||||
<configuration configurationName="Debug">
|
||||
|
||||
<resource resourceType="PROJECT" workspacePath="/RTOSDemo"/>
|
||||
|
||||
</configuration>
|
||||
|
||||
</storageModule>
|
||||
|
||||
</cproject>
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project>
|
||||
<configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="166385301954473" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
</extension>
|
||||
</configuration>
|
||||
|
||||
<configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.206163480" name="Debug">
|
||||
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
|
||||
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-316647897902857" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
|
||||
</provider>
|
||||
|
||||
</extension>
|
||||
|
||||
</configuration>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -80,11 +80,19 @@ _start:
|
|||
bge t1, t2, 2f
|
||||
|
||||
1:
|
||||
#if __riscv_xlen == 32
|
||||
lw a0, 0(t0)
|
||||
addi t0, t0, 4
|
||||
sw a0, 0(t1)
|
||||
addi t1, t1, 4
|
||||
blt t1, t2, 1b
|
||||
#else
|
||||
ld a0, 0(t0)
|
||||
addi t0, t0, 8
|
||||
sd a0, 0(t1)
|
||||
addi t1, t1, 8
|
||||
blt t1, t2, 1b
|
||||
#endif
|
||||
2:
|
||||
|
||||
/* Copy the ITIM section */
|
||||
|
@ -96,13 +104,25 @@ _start:
|
|||
bge t1, t2, 2f
|
||||
|
||||
1:
|
||||
#if __riscv_xlen == 32
|
||||
lw a0, 0(t0)
|
||||
addi t0, t0, 4
|
||||
sw a0, 0(t1)
|
||||
addi t1, t1, 4
|
||||
blt t1, t2, 1b
|
||||
#else
|
||||
ld a0, 0(t0)
|
||||
addi t0, t0, 8
|
||||
sd a0, 0(t1)
|
||||
addi t1, t1, 8
|
||||
blt t1, t2, 1b
|
||||
#endif
|
||||
2:
|
||||
|
||||
/* Fence all subsequent instruction fetches until after the ITIM writes
|
||||
complete */
|
||||
fence.i
|
||||
|
||||
/* Zero the BSS segment. */
|
||||
la t1, metal_segment_bss_target_start
|
||||
la t2, metal_segment_bss_target_end
|
||||
|
@ -110,9 +130,15 @@ _start:
|
|||
bge t1, t2, 2f
|
||||
|
||||
1:
|
||||
#if __riscv_xlen == 32
|
||||
sw x0, 0(t1)
|
||||
addi t1, t1, 4
|
||||
blt t1, t2, 1b
|
||||
#else
|
||||
sd x0, 0(t1)
|
||||
addi t1, t1, 8
|
||||
blt t1, t2, 1b
|
||||
#endif
|
||||
2:
|
||||
|
||||
/* At this point we're in an environment that can execute C code. The first
|
||||
|
@ -131,7 +157,7 @@ _skip_init:
|
|||
|
||||
/* Synchronize harts so that secondary harts wait until hart 0 finishes
|
||||
initializing */
|
||||
call _synchronize_harts
|
||||
call __metal_synchronize_harts
|
||||
|
||||
/* Check RISC-V isa and enable FS bits if Floating Point architecture. */
|
||||
csrr a5, misa
|
||||
|
|
|
@ -7,10 +7,12 @@ _gettimeofday(struct timeval *tp, void *tzp)
|
|||
{
|
||||
int rv;
|
||||
unsigned long long mcc, timebase;
|
||||
if (rv = metal_timer_get_cyclecount(0, &mcc)) {
|
||||
rv = metal_timer_get_cyclecount(0, &mcc);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (rv = metal_timer_get_timebase_frequency(0, &timebase)) {
|
||||
rv = metal_timer_get_timebase_frequency(0, &timebase);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
tp->tv_sec = mcc / timebase;
|
||||
|
|
|
@ -24,7 +24,7 @@ _sbrk(ptrdiff_t incr)
|
|||
|
||||
/* If __heap_size == 0, we can't allocate memory on the heap */
|
||||
if(&metal_segment_heap_target_start == &metal_segment_heap_target_end) {
|
||||
return NULL;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
/* Don't move the break past the end of the heap */
|
||||
|
@ -32,6 +32,7 @@ _sbrk(ptrdiff_t incr)
|
|||
brk += incr;
|
||||
} else {
|
||||
brk = &metal_segment_heap_target_end;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
return old;
|
||||
|
|
|
@ -30,7 +30,8 @@ _times(struct tms *buf)
|
|||
_gettimeofday (&t, 0);
|
||||
|
||||
unsigned long long timebase;
|
||||
if (rv = metal_timer_get_timebase_frequency(0, &timebase)) {
|
||||
rv = metal_timer_get_timebase_frequency(0, &timebase);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ struct metal_button* metal_button_get(char *label);
|
|||
* @return A pointer to the interrupt controller responsible for handling
|
||||
* button interrupts.
|
||||
*/
|
||||
inline struct metal_interrupt*
|
||||
__inline__ struct metal_interrupt*
|
||||
metal_button_interrupt_controller(struct metal_button *button) { return button->vtable->interrupt_controller(button); }
|
||||
|
||||
/*!
|
||||
|
@ -54,6 +54,6 @@ inline struct metal_interrupt*
|
|||
* @param button The handle for the button
|
||||
* @return The interrupt id corresponding to a button.
|
||||
*/
|
||||
inline int metal_button_get_interrupt_id(struct metal_button *button) { return button->vtable->get_interrupt_id(button); }
|
||||
__inline__ int metal_button_get_interrupt_id(struct metal_button *button) { return button->vtable->get_interrupt_id(button); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*
|
||||
* @brief API for configuring caches
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
struct metal_cache;
|
||||
|
||||
|
@ -32,8 +33,8 @@ struct metal_cache {
|
|||
*
|
||||
* Initializes a cache with the requested number of ways enabled.
|
||||
*/
|
||||
inline void metal_cache_init(struct metal_cache *cache, int ways) {
|
||||
return cache->vtable->init(cache, ways);
|
||||
__inline__ void metal_cache_init(struct metal_cache *cache, int ways) {
|
||||
cache->vtable->init(cache, ways);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -41,7 +42,7 @@ inline void metal_cache_init(struct metal_cache *cache, int ways) {
|
|||
* @param cache The handle for the cache
|
||||
* @return The current number of enabled cache ways
|
||||
*/
|
||||
inline int metal_cache_get_enabled_ways(struct metal_cache *cache) {
|
||||
__inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) {
|
||||
return cache->vtable->get_enabled_ways(cache);
|
||||
}
|
||||
|
||||
|
@ -51,8 +52,45 @@ inline int metal_cache_get_enabled_ways(struct metal_cache *cache) {
|
|||
* @param ways The number of ways to enabled
|
||||
* @return 0 if the ways are successfully enabled
|
||||
*/
|
||||
inline int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
|
||||
__inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) {
|
||||
return cache->vtable->set_enabled_ways(cache, ways);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check if dcache is supported on the core
|
||||
* @param hartid The core to check
|
||||
* @return 1 if dcache is present
|
||||
*/
|
||||
int metal_dcache_l1_available(int hartid);
|
||||
|
||||
/*!
|
||||
* @brief Flush dcache for L1 on the requested core with write back
|
||||
* @param hartid The core to flush
|
||||
* @param address The virtual address of cacheline to invalidate
|
||||
* @return None
|
||||
*/
|
||||
void metal_dcache_l1_flush(int hartid, uintptr_t address);
|
||||
|
||||
/*!
|
||||
* @brief Discard dcache for L1 on the requested core with no write back
|
||||
* @param hartid The core to discard
|
||||
* @param address The virtual address of cacheline to invalidate
|
||||
* @return None
|
||||
*/
|
||||
void metal_dcache_l1_discard(int hartid, uintptr_t address);
|
||||
|
||||
/*!
|
||||
* @brief Check if icache is supported on the core
|
||||
* @param hartid The core to check
|
||||
* @return 1 if icache is present
|
||||
*/
|
||||
int metal_icache_l1_available(int hartid);
|
||||
|
||||
/*!
|
||||
* @brief Flush icache for L1 on the requested core
|
||||
* @param hartid The core to flush
|
||||
* @return None
|
||||
*/
|
||||
void metal_icache_l1_flush(int hartid);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,14 +22,57 @@ struct __metal_clock_vtable {
|
|||
};
|
||||
|
||||
/*!
|
||||
* @brief Function signature of clock pre-rate change callbacks
|
||||
* @brief Function signature of clock rate change callbacks
|
||||
*/
|
||||
typedef void (*metal_clock_pre_rate_change_callback)(void *priv);
|
||||
typedef void (*metal_clock_rate_change_callback)(void *priv);
|
||||
|
||||
struct _metal_clock_callback_t;
|
||||
struct _metal_clock_callback_t {
|
||||
/* The callback function */
|
||||
metal_clock_rate_change_callback callback;
|
||||
|
||||
/* Private data for the callback function */
|
||||
void *priv;
|
||||
|
||||
struct _metal_clock_callback_t *_next;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Function signature of clock post-rate change callbacks
|
||||
* @brief Type for the linked list of callbacks for clock rate changes
|
||||
*/
|
||||
typedef void (*metal_clock_post_rate_change_callback)(void *priv);
|
||||
typedef struct _metal_clock_callback_t metal_clock_callback;
|
||||
|
||||
/*!
|
||||
* @brief Call all callbacks in the linked list, if any are registered
|
||||
*/
|
||||
__inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list) {
|
||||
const metal_clock_callback *current = list;
|
||||
while (current) {
|
||||
current->callback(current->priv);
|
||||
current = current->_next;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Append a callback to the linked list and return the head of the list
|
||||
*/
|
||||
__inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb) {
|
||||
cb->_next = NULL;
|
||||
|
||||
if (!list) {
|
||||
return cb;
|
||||
}
|
||||
|
||||
metal_clock_callback *current = list;
|
||||
|
||||
while ((current->_next) != NULL) {
|
||||
current = current->_next;
|
||||
}
|
||||
|
||||
current->_next = cb;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @struct metal_clock
|
||||
|
@ -46,13 +89,11 @@ typedef void (*metal_clock_post_rate_change_callback)(void *priv);
|
|||
struct metal_clock {
|
||||
const struct __metal_clock_vtable *vtable;
|
||||
|
||||
/* Pre-rate change callback */
|
||||
metal_clock_pre_rate_change_callback _pre_rate_change_callback;
|
||||
void *_pre_rate_change_callback_priv;
|
||||
/* Pre-rate change callback linked list */
|
||||
metal_clock_callback *_pre_rate_change_callback;
|
||||
|
||||
/* Post-rate change callback */
|
||||
metal_clock_post_rate_change_callback _post_rate_change_callback;
|
||||
void *_post_rate_change_callback_priv;
|
||||
/* Post-rate change callback linked list */
|
||||
metal_clock_callback *_post_rate_change_callback;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -61,7 +102,7 @@ struct metal_clock {
|
|||
* @param clk The handle for the clock
|
||||
* @return The current rate of the clock in Hz
|
||||
*/
|
||||
inline long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); }
|
||||
__inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); }
|
||||
|
||||
/*!
|
||||
* @brief Set the current rate of a clock
|
||||
|
@ -77,15 +118,13 @@ inline long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk-
|
|||
* Prior to and after the rate change of the clock, this will call the registered
|
||||
* pre- and post-rate change callbacks.
|
||||
*/
|
||||
inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
|
||||
__inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
|
||||
{
|
||||
if(clk->_pre_rate_change_callback != NULL)
|
||||
clk->_pre_rate_change_callback(clk->_pre_rate_change_callback_priv);
|
||||
_metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
|
||||
|
||||
long out = clk->vtable->set_rate_hz(clk, hz);
|
||||
|
||||
if (clk->_post_rate_change_callback != NULL)
|
||||
clk->_post_rate_change_callback(clk->_post_rate_change_callback_priv);
|
||||
_metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
@ -95,12 +134,10 @@ inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
|
|||
*
|
||||
* @param clk The handle for the clock
|
||||
* @param cb The callback to be registered
|
||||
* @param priv Private data for the callback handler
|
||||
*/
|
||||
inline void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_pre_rate_change_callback cb, void *priv)
|
||||
__inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
|
||||
{
|
||||
clk->_pre_rate_change_callback = cb;
|
||||
clk->_pre_rate_change_callback_priv = priv;
|
||||
clk->_pre_rate_change_callback = _metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -108,12 +145,10 @@ inline void metal_clock_register_pre_rate_change_callback(struct metal_clock *cl
|
|||
*
|
||||
* @param clk The handle for the clock
|
||||
* @param cb The callback to be registered
|
||||
* @param priv Private data for the callback handler
|
||||
*/
|
||||
inline void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_post_rate_change_callback cb, void *priv)
|
||||
__inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
|
||||
{
|
||||
clk->_post_rate_change_callback = cb;
|
||||
clk->_post_rate_change_callback_priv = priv;
|
||||
clk->_post_rate_change_callback = _metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@ struct metal_cpu;
|
|||
typedef void (*metal_exception_handler_t) (struct metal_cpu *cpu, int ecode);
|
||||
|
||||
struct metal_cpu_vtable {
|
||||
unsigned long long (*timer_get)(struct metal_cpu *cpu);
|
||||
unsigned long long (*mcycle_get)(struct metal_cpu *cpu);
|
||||
unsigned long long (*timebase_get)(struct metal_cpu *cpu);
|
||||
unsigned long long (*mtime_get)(struct metal_cpu *cpu);
|
||||
int (*mtimecmp_set)(struct metal_cpu *cpu, unsigned long long time);
|
||||
|
@ -49,17 +49,17 @@ struct metal_cpu {
|
|||
* @param hartid The ID of the desired CPU hart
|
||||
* @return A pointer to the CPU device handle
|
||||
*/
|
||||
struct metal_cpu* metal_cpu_get(int hartid);
|
||||
struct metal_cpu* metal_cpu_get(unsigned int hartid);
|
||||
|
||||
/*! @brief Get the hartid of the CPU hart executing this function
|
||||
*
|
||||
* @return The hartid of the current CPU hart */
|
||||
int metal_cpu_get_current_hartid();
|
||||
int metal_cpu_get_current_hartid(void);
|
||||
|
||||
/*! @brief Get the number of CPU harts
|
||||
*
|
||||
* @return The number of CPU harts */
|
||||
int metal_cpu_get_num_harts();
|
||||
int metal_cpu_get_num_harts(void);
|
||||
|
||||
/*! @brief Get the CPU cycle count timer value
|
||||
*
|
||||
|
@ -68,8 +68,8 @@ int metal_cpu_get_num_harts();
|
|||
* @param cpu The CPU device handle
|
||||
* @return The value of the CPU cycle count timer
|
||||
*/
|
||||
inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->timer_get(cpu); }
|
||||
__inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->mcycle_get(cpu); }
|
||||
|
||||
/*! @brief Get the timebase of the CPU
|
||||
*
|
||||
|
@ -78,7 +78,7 @@ inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu)
|
|||
* @param cpu The CPU device handle
|
||||
* @return The value of the cycle count timer timebase
|
||||
*/
|
||||
inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
|
||||
__inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->timebase_get(cpu); }
|
||||
|
||||
/*! @brief Get the value of the mtime RTC
|
||||
|
@ -90,7 +90,7 @@ inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu)
|
|||
* @param cpu The CPU device handle
|
||||
* @return The value of mtime, or 0 if failure
|
||||
*/
|
||||
inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
|
||||
__inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->mtime_get(cpu); }
|
||||
|
||||
/*! @brief Set the value of the RTC mtimecmp RTC
|
||||
|
@ -103,7 +103,7 @@ inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu)
|
|||
* @param time The value to set the compare register to
|
||||
* @return The value of mtimecmp or -1 if error
|
||||
*/
|
||||
inline int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
|
||||
__inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time)
|
||||
{ return cpu->vtable->mtimecmp_set(cpu, time); }
|
||||
|
||||
/*! @brief Get a reference to RTC timer interrupt controller
|
||||
|
@ -115,7 +115,7 @@ inline int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time
|
|||
* @param cpu The CPU device handle
|
||||
* @return A pointer to the timer interrupt handle
|
||||
*/
|
||||
inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
|
||||
__inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->tmr_controller_interrupt(cpu); }
|
||||
|
||||
/*! @brief Get the RTC timer interrupt id
|
||||
|
@ -125,7 +125,7 @@ inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal
|
|||
* @param cpu The CPU device handle
|
||||
* @return The timer interrupt ID
|
||||
*/
|
||||
inline int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
|
||||
__inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->get_tmr_interrupt_id(cpu); }
|
||||
|
||||
/*! @brief Get a reference to the software interrupt controller
|
||||
|
@ -137,7 +137,7 @@ inline int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu)
|
|||
* @param cpu The CPU device handle
|
||||
* @return A pointer to the software interrupt handle
|
||||
*/
|
||||
inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
|
||||
__inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->sw_controller_interrupt(cpu); }
|
||||
|
||||
/*! @brief Get the software interrupt id
|
||||
|
@ -147,7 +147,7 @@ inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct me
|
|||
* @param cpu The CPU device handle
|
||||
* @return the software interrupt ID
|
||||
*/
|
||||
inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
|
||||
__inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->get_sw_interrupt_id(cpu); }
|
||||
|
||||
/*!
|
||||
|
@ -161,7 +161,7 @@ inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu)
|
|||
* @param hartid The CPU hart ID to be interrupted
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
|
||||
__inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
|
||||
{ return cpu->vtable->set_sw_ipi(cpu, hartid); }
|
||||
|
||||
/*!
|
||||
|
@ -175,7 +175,7 @@ inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid)
|
|||
* @param hartid The CPU hart ID to clear
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
|
||||
__inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
|
||||
{ return cpu->vtable->clear_sw_ipi(cpu, hartid); }
|
||||
|
||||
/*!
|
||||
|
@ -190,7 +190,7 @@ inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid)
|
|||
* @param hartid The CPU hart to read
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
|
||||
__inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
|
||||
{ return cpu->vtable->get_msip(cpu, hartid); }
|
||||
|
||||
/*!
|
||||
|
@ -204,7 +204,7 @@ inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid)
|
|||
* @param cpu The CPU device handle
|
||||
* @return The handle for the CPU interrupt controller
|
||||
*/
|
||||
inline struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
|
||||
__inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->controller_interrupt(cpu); }
|
||||
|
||||
/*!
|
||||
|
@ -218,7 +218,7 @@ inline struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *
|
|||
* @param handler Callback function for the exception handler
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
|
||||
__inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler)
|
||||
{ return cpu->vtable->exception_register(cpu, ecode, handler); }
|
||||
|
||||
/*!
|
||||
|
@ -237,7 +237,7 @@ inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_
|
|||
* @param epc The address of the instruction to measure
|
||||
* @return the length of the instruction in bytes
|
||||
*/
|
||||
inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
|
||||
__inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
|
||||
{ return cpu->vtable->get_ilen(cpu, epc); }
|
||||
|
||||
/*!
|
||||
|
@ -249,7 +249,7 @@ inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc
|
|||
* @param cpu The CPU device handle
|
||||
* @return The value of the program counter at the time of the exception
|
||||
*/
|
||||
inline uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
|
||||
__inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
|
||||
{ return cpu->vtable->get_epc(cpu); }
|
||||
|
||||
/*!
|
||||
|
@ -265,7 +265,7 @@ inline uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu)
|
|||
* @param epc The address to set the exception program counter to
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
|
||||
__inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc)
|
||||
{ return cpu->vtable->set_epc(cpu, epc); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -86,6 +86,9 @@
|
|||
#define METAL_LOCAL_INTERRUPT(X) (0x10000 << X) /* Bit16+ Start of Custom Local Interrupt */
|
||||
#define METAL_MIE_INTERRUPT METAL_MSTATUS_MIE
|
||||
|
||||
#define METAL_INSN_LENGTH_MASK 3
|
||||
#define METAL_INSN_NOT_COMPRESSED 3
|
||||
|
||||
typedef enum {
|
||||
METAL_MACHINE_PRIVILEGE_MODE,
|
||||
METAL_SUPERVISOR_PRIVILEGE_MODE,
|
||||
|
@ -97,6 +100,7 @@ typedef enum {
|
|||
METAL_INTERRUPT_ID_SW = (METAL_INTERRUPT_ID_BASE + 3),
|
||||
METAL_INTERRUPT_ID_TMR = (METAL_INTERRUPT_ID_BASE + 7),
|
||||
METAL_INTERRUPT_ID_EXT = (METAL_INTERRUPT_ID_BASE + 11),
|
||||
METAL_INTERRUPT_ID_CSW = (METAL_INTERRUPT_ID_BASE + 12),
|
||||
METAL_INTERRUPT_ID_LC0 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(0)),
|
||||
METAL_INTERRUPT_ID_LC1 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(1)),
|
||||
METAL_INTERRUPT_ID_LC2 = (METAL_INTERRUPT_ID_BASE + METAL_LOCAL_INTR(2)),
|
||||
|
@ -154,15 +158,6 @@ typedef struct __metal_interrupt_data {
|
|||
|
||||
uintptr_t __metal_myhart_id(void);
|
||||
|
||||
struct __metal_driver_interrupt_controller_vtable {
|
||||
void (*interrupt_init)(struct metal_interrupt *controller);
|
||||
int (*interrupt_register)(struct metal_interrupt *controller,
|
||||
int id, metal_interrupt_handler_t isr, void *priv_data);
|
||||
int (*interrupt_enable)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_disable)(struct metal_interrupt *controller, int id);
|
||||
int (*command_request)(struct metal_interrupt *intr, int cmd, void *data);
|
||||
};
|
||||
|
||||
struct __metal_driver_vtable_riscv_cpu_intc {
|
||||
struct metal_interrupt_vtable controller_vtable;
|
||||
};
|
||||
|
@ -170,14 +165,8 @@ struct __metal_driver_vtable_riscv_cpu_intc {
|
|||
|
||||
void __metal_interrupt_global_enable(void);
|
||||
void __metal_interrupt_global_disable(void);
|
||||
metal_vector_mode __metal_controller_interrupt_vector_mode(void);
|
||||
void __metal_controller_interrupt_vector(metal_vector_mode mode, void *vec_table);
|
||||
inline int __metal_controller_interrupt_is_selective_vectored (void)
|
||||
{
|
||||
uintptr_t val;
|
||||
|
||||
asm volatile ("csrr %0, mtvec" : "=r"(val));
|
||||
return ((val & METAL_MTVEC_CLIC_VECTORED) == METAL_MTVEC_CLIC);
|
||||
}
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_riscv_cpu_intc)
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__DRIVERS__SIFIVE_CCACHE0_H
|
||||
#define METAL__DRIVERS__SIFIVE_CCACHE0_H
|
||||
|
||||
#include <metal/cache.h>
|
||||
#include <metal/compiler.h>
|
||||
|
||||
struct __metal_driver_vtable_sifive_ccache0 {
|
||||
struct __metal_cache_vtable cache;
|
||||
};
|
||||
|
||||
struct __metal_driver_sifive_ccache0;
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_ccache0)
|
||||
|
||||
struct __metal_driver_sifive_ccache0 {
|
||||
struct metal_cache cache;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -34,7 +34,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_clic0)
|
|||
struct __metal_driver_sifive_clic0 {
|
||||
struct metal_interrupt controller;
|
||||
int init_done;
|
||||
metal_interrupt_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
|
||||
int pad[14];
|
||||
metal_interrupt_vector_handler_t metal_mtvt_table[__METAL_CLIC_SUBINTERRUPTS];
|
||||
__metal_interrupt_data metal_exint_table[__METAL_CLIC_SUBINTERRUPTS];
|
||||
};
|
||||
#undef __METAL_MACHINE_MACROS
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__DRIVERS__SIFIVE_FE310_G000_LFROSC_H
|
||||
#define METAL__DRIVERS__SIFIVE_FE310_G000_LFROSC_H
|
||||
|
||||
#include <metal/compiler.h>
|
||||
#include <metal/clock.h>
|
||||
#include <metal/io.h>
|
||||
|
||||
struct __metal_driver_vtable_sifive_fe310_g000_lfrosc {
|
||||
struct __metal_clock_vtable clock;
|
||||
};
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc)
|
||||
|
||||
struct __metal_driver_sifive_fe310_g000_lfrosc {
|
||||
struct metal_clock clock;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -17,6 +17,7 @@ struct __metal_driver_vtable_sifive_fe310_g000_prci {
|
|||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci)
|
||||
|
||||
struct __metal_driver_sifive_fe310_g000_prci {
|
||||
const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
#ifndef METAL__DRIVERS__SIFIVE_FU540_C000_L2_H
|
||||
#define METAL__DRIVERS__SIFIVE_FU540_C000_L2_H
|
||||
|
||||
struct __metal_driver_sifive_fu540_c000_l2;
|
||||
|
||||
#include <stdint.h>
|
||||
#include <metal/cache.h>
|
||||
#include <metal/compiler.h>
|
||||
|
||||
struct __metal_driver_vtable_sifive_fu540_c000_l2 {
|
||||
struct __metal_cache_vtable cache;
|
||||
};
|
||||
|
||||
//_RB___METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2)
|
||||
struct __metal_driver_sifive_fu540_c000_l2;
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2)
|
||||
|
||||
struct __metal_driver_sifive_fu540_c000_l2 {
|
||||
struct metal_cache cache;
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__DRIVERS__SIFIVE_RTC0_H
|
||||
#define METAL__DRIVERS__SIFIVE_RTC0_H
|
||||
|
||||
#include <metal/io.h>
|
||||
#include <metal/compiler.h>
|
||||
|
||||
#include <metal/clock.h>
|
||||
#include <metal/interrupt.h>
|
||||
#include <metal/rtc.h>
|
||||
|
||||
struct __metal_driver_vtable_sifive_rtc0 {
|
||||
const struct metal_rtc_vtable rtc;
|
||||
};
|
||||
|
||||
struct __metal_driver_sifive_rtc0;
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_rtc0)
|
||||
|
||||
struct __metal_driver_sifive_rtc0 {
|
||||
const struct metal_rtc rtc;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -19,6 +19,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_spi0)
|
|||
struct __metal_driver_sifive_spi0 {
|
||||
struct metal_spi spi;
|
||||
unsigned long baud_rate;
|
||||
metal_clock_callback pre_rate_change_callback;
|
||||
metal_clock_callback post_rate_change_callback;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__DRIVERS__SIFIVE_TRACE_H
|
||||
#define METAL__DRIVERS__SIFIVE_TRACE_H
|
||||
|
||||
#include <metal/compiler.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/uart.h>
|
||||
|
||||
struct __metal_driver_vtable_sifive_trace {
|
||||
const struct metal_uart_vtable uart;
|
||||
};
|
||||
|
||||
struct __metal_driver_sifive_trace;
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_trace)
|
||||
|
||||
struct __metal_driver_sifive_trace {
|
||||
struct metal_uart uart;
|
||||
};
|
||||
|
||||
#endif /* METAL__DRIVERS__SIFIVE_TRACE_H */
|
|
@ -22,6 +22,8 @@ __METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_uart0)
|
|||
struct __metal_driver_sifive_uart0 {
|
||||
struct metal_uart uart;
|
||||
unsigned long baud_rate;
|
||||
metal_clock_callback pre_rate_change_callback;
|
||||
metal_clock_callback post_rate_change_callback;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* Copyright 2018 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__DRIVERS__SIFIVE_WDOG0_H
|
||||
#define METAL__DRIVERS__SIFIVE_WDOG0_H
|
||||
|
||||
#include <metal/io.h>
|
||||
#include <metal/compiler.h>
|
||||
|
||||
#include <metal/watchdog.h>
|
||||
#include <metal/clock.h>
|
||||
#include <metal/interrupt.h>
|
||||
|
||||
struct __metal_driver_vtable_sifive_wdog0 {
|
||||
const struct metal_watchdog_vtable watchdog;
|
||||
};
|
||||
|
||||
struct __metal_driver_sifive_wdog0;
|
||||
|
||||
__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_wdog0)
|
||||
|
||||
struct __metal_driver_sifive_wdog0 {
|
||||
const struct metal_watchdog watchdog;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -5,6 +5,7 @@
|
|||
#define METAL__GPIO_H
|
||||
|
||||
#include <metal/compiler.h>
|
||||
#include <metal/interrupt.h>
|
||||
|
||||
/*!
|
||||
* @file gpio.h
|
||||
|
@ -15,14 +16,31 @@ struct metal_gpio;
|
|||
|
||||
struct __metal_gpio_vtable {
|
||||
int (*disable_input)(struct metal_gpio *, long pins);
|
||||
int (*enable_input)(struct metal_gpio *, long pins);
|
||||
long (*input)(struct metal_gpio *);
|
||||
long (*output)(struct metal_gpio *);
|
||||
int (*disable_output)(struct metal_gpio *, long pins);
|
||||
int (*enable_output)(struct metal_gpio *, long pins);
|
||||
int (*output_set)(struct metal_gpio *, long value);
|
||||
int (*output_clear)(struct metal_gpio *, long value);
|
||||
int (*output_toggle)(struct metal_gpio *, long value);
|
||||
int (*enable_io)(struct metal_gpio *, long pins, long dest);
|
||||
int (*disable_io)(struct metal_gpio *, long pins);
|
||||
int (*config_int)(struct metal_gpio *, long pins, int intr_type);
|
||||
int (*clear_int)(struct metal_gpio *, long pins, int intr_type);
|
||||
struct metal_interrupt* (*interrupt_controller)(struct metal_gpio *gpio);
|
||||
int (*get_interrupt_id)(struct metal_gpio *gpio, int pin);
|
||||
};
|
||||
|
||||
#define METAL_GPIO_INT_DISABLE 0
|
||||
#define METAL_GPIO_INT_RISING 1
|
||||
#define METAL_GPIO_INT_FALLING 2
|
||||
#define METAL_GPIO_INT_BOTH_EDGE 3
|
||||
#define METAL_GPIO_INT_LOW 4
|
||||
#define METAL_GPIO_INT_HIGH 5
|
||||
#define METAL_GPIO_INT_BOTH_LEVEL 6
|
||||
#define METAL_GPIO_INT_MAX 7
|
||||
|
||||
/*!
|
||||
* @struct metal_gpio
|
||||
* @brief The handle for a GPIO interface
|
||||
|
@ -36,7 +54,21 @@ struct metal_gpio {
|
|||
* @param device_num The GPIO device index
|
||||
* @return The GPIO device handle, or NULL if there is no device at that index
|
||||
*/
|
||||
struct metal_gpio *metal_gpio_get_device(int device_num);
|
||||
struct metal_gpio *metal_gpio_get_device(unsigned int device_num);
|
||||
|
||||
/*!
|
||||
* @brief enable input on a pin
|
||||
* @param gpio The handle for the GPIO interface
|
||||
* @param pin The pin number indexed from 0
|
||||
* @return 0 if the input is successfully enabled
|
||||
*/
|
||||
__inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return gpio->vtable->enable_input(gpio, (1 << pin));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Disable input on a pin
|
||||
|
@ -44,7 +76,7 @@ struct metal_gpio *metal_gpio_get_device(int device_num);
|
|||
* @param pin The pin number indexed from 0
|
||||
* @return 0 if the input is successfully disabled
|
||||
*/
|
||||
inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
|
||||
__inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -58,7 +90,7 @@ inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin) {
|
|||
* @param pin The pin number indexed from 0
|
||||
* @return 0 if the output is successfully enabled
|
||||
*/
|
||||
inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
|
||||
__inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -66,6 +98,20 @@ inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
|
|||
return gpio->vtable->enable_output(gpio, (1 << pin));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Disable output on a pin
|
||||
* @param gpio The handle for the GPIO interface
|
||||
* @param pin The pin number indexed from 0
|
||||
* @return 0 if the output is successfully disabled
|
||||
*/
|
||||
__inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return gpio->vtable->disable_output(gpio, (1 << pin));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the output value of a GPIO pin
|
||||
* @param gpio The handle for the GPIO interface
|
||||
|
@ -73,7 +119,7 @@ inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin) {
|
|||
* @param value The value to set the pin to
|
||||
* @return 0 if the output is successfully set
|
||||
*/
|
||||
inline int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
|
||||
__inline__ int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -91,7 +137,27 @@ inline int metal_gpio_set_pin(struct metal_gpio *gpio, int pin, int value) {
|
|||
* @param pin The pin number indexed from 0
|
||||
* @return The value of the GPIO pin
|
||||
*/
|
||||
inline int metal_gpio_get_pin(struct metal_gpio *gpio, int pin) {
|
||||
__inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long value = gpio->vtable->input(gpio);
|
||||
|
||||
if(value & (1 << pin)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the value of the GPIO pin
|
||||
* @param gpio The handle for the GPIO interface
|
||||
* @param pin The pin number indexed from 0
|
||||
* @return The value of the GPIO pin
|
||||
*/
|
||||
__inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -111,7 +177,7 @@ inline int metal_gpio_get_pin(struct metal_gpio *gpio, int pin) {
|
|||
* @param pin The pin number indexed from 0
|
||||
* @return 0 if the pin is successfully cleared
|
||||
*/
|
||||
inline int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
|
||||
__inline__ int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -125,7 +191,7 @@ inline int metal_gpio_clear_pin(struct metal_gpio *gpio, int pin) {
|
|||
* @param pin The pin number indexed from 0
|
||||
* @return 0 if the pin is successfully toggled
|
||||
*/
|
||||
inline int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
|
||||
__inline__ int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -140,7 +206,7 @@ inline int metal_gpio_toggle_pin(struct metal_gpio *gpio, int pin) {
|
|||
* @param io_function The IO function to set
|
||||
* @return 0 if the pinmux is successfully set
|
||||
*/
|
||||
inline int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
|
||||
__inline__ int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_function) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -148,4 +214,71 @@ inline int metal_gpio_enable_pinmux(struct metal_gpio *gpio, int pin, int io_fun
|
|||
return gpio->vtable->enable_io(gpio, (1 << pin), (io_function << pin));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Disables the pinmux for a GPIO pin
|
||||
* @param gpio The handle for the GPIO interface
|
||||
* @param pin The bitmask for the pin to disable pinmux on
|
||||
* @return 0 if the pinmux is successfully set
|
||||
*/
|
||||
__inline__ int metal_gpio_disable_pinmux(struct metal_gpio *gpio, int pin) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return gpio->vtable->disable_io(gpio, (1 << pin));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Config gpio interrupt type
|
||||
* @param gpio The handle for the GPIO interface
|
||||
* @param pin The bitmask for the pin to enable gpio interrupt
|
||||
* @param intr_type The interrupt type
|
||||
* @return 0 if the interrupt mode is setup properly
|
||||
*/
|
||||
__inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin, int intr_type) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return gpio->vtable->config_int(gpio, (1 << pin), intr_type);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Clear gpio interrupt status
|
||||
* @param gpio The handle for the GPIO interface
|
||||
* @param pin The bitmask for the pin to clear gpio interrupt
|
||||
* @param intr_type The interrupt type to be clear
|
||||
* @return 0 if the interrupt is cleared
|
||||
*/
|
||||
__inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin, int intr_type) {
|
||||
if(!gpio) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return gpio->vtable->clear_int(gpio, (1 << pin), intr_type);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt controller for a gpio
|
||||
*
|
||||
* @param gpio The handle for the gpio
|
||||
* @return A pointer to the interrupt controller responsible for handling
|
||||
* gpio interrupts.
|
||||
*/
|
||||
__inline__ struct metal_interrupt*
|
||||
metal_gpio_interrupt_controller(struct metal_gpio *gpio) {
|
||||
return gpio->vtable->interrupt_controller(gpio);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt id for a gpio
|
||||
*
|
||||
* @param gpio The handle for the gpio
|
||||
* @param pin The bitmask for the pin to get gpio interrupt id
|
||||
* @return The interrupt id corresponding to a gpio.
|
||||
*/
|
||||
__inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin) {
|
||||
return gpio->vtable->get_interrupt_id(gpio, pin);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,32 +10,64 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
/*!
|
||||
* @brief Possible interrupt controllers
|
||||
*/
|
||||
typedef enum metal_interrupt_controller_ {
|
||||
METAL_CPU_CONTROLLER = 0,
|
||||
METAL_CLINT_CONTROLLER = 1,
|
||||
METAL_CLIC_CONTROLLER = 2,
|
||||
METAL_PLIC_CONTROLLER = 3
|
||||
} metal_intr_cntrl_type;
|
||||
|
||||
/*!
|
||||
* @brief Possible mode of interrupts to operate
|
||||
*/
|
||||
typedef enum metal_vector_mode_ {
|
||||
METAL_DIRECT_MODE = 0,
|
||||
METAL_VECTOR_MODE = 1,
|
||||
METAL_SELECTIVE_VECTOR_MODE = 2,
|
||||
METAL_HARDWARE_VECTOR_MODE = 3
|
||||
METAL_SELECTIVE_NONVECTOR_MODE = 2,
|
||||
METAL_SELECTIVE_VECTOR_MODE = 3,
|
||||
METAL_HARDWARE_VECTOR_MODE = 4
|
||||
} metal_vector_mode;
|
||||
|
||||
/*!
|
||||
* @brief Possible mode of privilege interrupts to operate
|
||||
*/
|
||||
typedef enum metal_intr_priv_mode_ {
|
||||
METAL_INTR_PRIV_M_MODE = 0,
|
||||
METAL_INTR_PRIV_MU_MODE = 1,
|
||||
METAL_INTR_PRIV_MSU_MODE = 2
|
||||
} metal_intr_priv_mode;
|
||||
|
||||
/*!
|
||||
* @brief Function signature for interrupt callback handlers
|
||||
*/
|
||||
typedef void (*metal_interrupt_handler_t) (int, void *);
|
||||
typedef void (*metal_interrupt_vector_handler_t) (void);
|
||||
|
||||
struct metal_interrupt;
|
||||
|
||||
struct metal_interrupt_vtable {
|
||||
void (*interrupt_init)(struct metal_interrupt *controller);
|
||||
int (*interrupt_set_vector_mode)(struct metal_interrupt *controller, metal_vector_mode mode);
|
||||
metal_vector_mode (*interrupt_get_vector_mode)(struct metal_interrupt *controller);
|
||||
int (*interrupt_set_privilege)(struct metal_interrupt *controller, metal_intr_priv_mode priv);
|
||||
metal_intr_priv_mode (*interrupt_get_privilege)(struct metal_interrupt *controller);
|
||||
int (*interrupt_clear)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_set)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_register)(struct metal_interrupt *controller, int id,
|
||||
metal_interrupt_handler_t isr, void *priv_data);
|
||||
int (*interrupt_vector_register)(struct metal_interrupt *controller, int id,
|
||||
metal_interrupt_vector_handler_t isr, void *priv_data);
|
||||
int (*interrupt_enable)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_disable)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_vector_enable)(struct metal_interrupt *controller,
|
||||
int id, metal_vector_mode mode);
|
||||
int (*interrupt_vector_enable)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_vector_disable)(struct metal_interrupt *controller, int id);
|
||||
unsigned int (*interrupt_get_threshold)(struct metal_interrupt *controller);
|
||||
int (*interrupt_set_threshold)(struct metal_interrupt *controller, unsigned int threshold);
|
||||
unsigned int (*interrupt_get_priority)(struct metal_interrupt *controller, int id);
|
||||
int (*interrupt_set_priority)(struct metal_interrupt *controller, int id, unsigned int priority);
|
||||
int (*command_request)(struct metal_interrupt *controller, int cmd, void *data);
|
||||
int (*mtimecmp_set)(struct metal_interrupt *controller, int hartid, unsigned long long time);
|
||||
};
|
||||
|
@ -56,11 +88,107 @@ struct metal_interrupt {
|
|||
*
|
||||
* @param controller The handle for the interrupt controller
|
||||
*/
|
||||
inline void metal_interrupt_init(struct metal_interrupt *controller)
|
||||
__inline__ void metal_interrupt_init(struct metal_interrupt *controller)
|
||||
{
|
||||
return controller->vtable->interrupt_init(controller);
|
||||
controller->vtable->interrupt_init(controller);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the handle for an given interrupt controller type
|
||||
* @param cntrl The type ofinterrupt controller
|
||||
* @param id The instance of the interrupt controller
|
||||
* @return A handle to the interrupt controller (CLINT, CLIC, PLIC), or
|
||||
* NULL if none is found for the requested label
|
||||
*/
|
||||
struct metal_interrupt* metal_interrupt_get_controller(metal_intr_cntrl_type cntrl,
|
||||
int id);
|
||||
|
||||
/*!
|
||||
* @brief Configure vector mode for an interrupt controller
|
||||
*
|
||||
* Configure vector mode for an interrupt controller.
|
||||
* This function must be called after initialization and before
|
||||
* configuring individual interrupts, registering ISR.
|
||||
*
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param mode The vector mode of the interrupt controller.
|
||||
* @return 0 upon success
|
||||
*/
|
||||
__inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
|
||||
metal_vector_mode mode)
|
||||
{
|
||||
return controller->vtable->interrupt_set_vector_mode(controller, mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get vector mode of a given an interrupt controller
|
||||
*
|
||||
* Configure vector mode for an interrupt controller.
|
||||
* This function must be called after initialization and before
|
||||
* configuring individual interrupts, registering ISR.
|
||||
*
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param mode The vector mode of the interrupt controller.
|
||||
* @return The interrupt vector mode
|
||||
*/
|
||||
__inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller)
|
||||
{
|
||||
return controller->vtable->interrupt_get_vector_mode(controller);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Configure privilege mode a of given interrupt controller
|
||||
*
|
||||
* Configure privilege mode for a given interrupt controller.
|
||||
* This function must be called after initialization and before
|
||||
* configuring individual interrupts, registering ISR.
|
||||
*
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param privilege The privilege mode of the interrupt controller.
|
||||
* @return 0 upon success
|
||||
*/
|
||||
__inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
|
||||
metal_intr_priv_mode privilege)
|
||||
{
|
||||
return controller->vtable->interrupt_set_privilege(controller, privilege);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get privilege mode a of given interrupt controller
|
||||
*
|
||||
* Get privilege mode for a given interrupt controller.
|
||||
* This function must be called after initialization and before
|
||||
* configuring individual interrupts, registering ISR.
|
||||
*
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @return The interrupt privilege mode
|
||||
*/
|
||||
__inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller)
|
||||
{
|
||||
return controller->vtable->interrupt_get_privilege(controller);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief clear an interrupt
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to trigger
|
||||
* @return 0 upon success
|
||||
*/
|
||||
__inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_clear(controller, id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set an interrupt
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to trigger
|
||||
* @return 0 upon success
|
||||
*/
|
||||
__inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_set(controller, id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Register an interrupt handler
|
||||
|
@ -70,7 +198,7 @@ inline void metal_interrupt_init(struct metal_interrupt *controller)
|
|||
* @param priv_data Private data for the interrupt handler
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_register_handler(struct metal_interrupt *controller,
|
||||
__inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
|
||||
int id,
|
||||
metal_interrupt_handler_t handler,
|
||||
void *priv_data)
|
||||
|
@ -78,13 +206,29 @@ inline int metal_interrupt_register_handler(struct metal_interrupt *controller,
|
|||
return controller->vtable->interrupt_register(controller, id, handler, priv_data);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Register an interrupt vector handler
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to register
|
||||
* @param handler The interrupt vector handler callback
|
||||
* @param priv_data Private data for the interrupt handler
|
||||
* @return 0 upon success
|
||||
*/
|
||||
__inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller,
|
||||
int id,
|
||||
metal_interrupt_vector_handler_t handler,
|
||||
void *priv_data)
|
||||
{
|
||||
return controller->vtable->interrupt_vector_register(controller, id, handler, priv_data);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Enable an interrupt
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to enable
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_enable(struct metal_interrupt *controller, int id)
|
||||
__inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_enable(controller, id);
|
||||
}
|
||||
|
@ -95,22 +239,65 @@ inline int metal_interrupt_enable(struct metal_interrupt *controller, int id)
|
|||
* @param id The interrupt ID to disable
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_disable(struct metal_interrupt *controller, int id)
|
||||
__inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_disable(controller, id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set interrupt threshold level
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param threshold The interrupt threshold level
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_set_threshold(struct metal_interrupt *controller, unsigned int level)
|
||||
{
|
||||
return controller->vtable->interrupt_set_threshold(controller, level);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get an interrupt threshold level
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @return The interrupt threshold level
|
||||
*/
|
||||
inline unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller)
|
||||
{
|
||||
return controller->vtable->interrupt_get_threshold(controller);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set an interrupt priority level
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to enable
|
||||
* @param priority The interrupt priority level
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_set_priority(struct metal_interrupt *controller,
|
||||
int id, unsigned int priority)
|
||||
{
|
||||
return controller->vtable->interrupt_set_priority(controller, id, priority);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get an interrupt priority level
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to enable
|
||||
* @return The interrupt priority level
|
||||
*/
|
||||
inline unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_get_priority(controller, id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Enable an interrupt vector
|
||||
* @param controller The handle for the interrupt controller
|
||||
* @param id The interrupt ID to enable
|
||||
* @param mode The interrupt mode type to enable
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_vector_enable(struct metal_interrupt *controller,
|
||||
int id, metal_vector_mode mode)
|
||||
__inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_vector_enable(controller, id, mode);
|
||||
return controller->vtable->interrupt_vector_enable(controller, id);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -119,13 +306,153 @@ inline int metal_interrupt_vector_enable(struct metal_interrupt *controller,
|
|||
* @param id The interrupt ID to disable
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id)
|
||||
__inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
return controller->vtable->interrupt_vector_disable(controller, id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Default interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Software interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Timer interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal External interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 0 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 1 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 2 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 3 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 4 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 5 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 6 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 7 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 8 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 9 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 10 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 11 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 12 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 13 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 14 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler(void);
|
||||
|
||||
/*!
|
||||
* @brief Metal Local 15 interrupt vector handler, that can be overriden by user
|
||||
* @param None
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler(void);
|
||||
|
||||
/* Utilities function to controll, manages devices via a given interrupt controller */
|
||||
inline int _metal_interrupt_command_request(struct metal_interrupt *controller,
|
||||
__inline__ int _metal_interrupt_command_request(struct metal_interrupt *controller,
|
||||
int cmd, void *data)
|
||||
{
|
||||
return controller->vtable->command_request(controller, cmd, data);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#define METAL__IO_H
|
||||
|
||||
/* This macro enforces that the compiler will not elide the given access. */
|
||||
#define __METAL_ACCESS_ONCE(x) (*(typeof(*x) volatile *)(x))
|
||||
#define __METAL_ACCESS_ONCE(x) (*(__typeof__(*x) volatile *)(x))
|
||||
|
||||
/* Allows users to specify arbitrary fences. */
|
||||
#define __METAL_IO_FENCE(pred, succ) __asm__ volatile ("fence " #pred "," #succ ::: "memory");
|
||||
|
|
|
@ -45,24 +45,24 @@ struct metal_led* metal_led_get_rgb(char *label, char *color);
|
|||
* @brief Enable an LED
|
||||
* @param led The handle for the LED
|
||||
*/
|
||||
inline void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
|
||||
__inline__ void metal_led_enable(struct metal_led *led) { led->vtable->led_enable(led); }
|
||||
|
||||
/*!
|
||||
* @brief Turn an LED on
|
||||
* @param led The handle for the LED
|
||||
*/
|
||||
inline void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
|
||||
__inline__ void metal_led_on(struct metal_led *led) { led->vtable->led_on(led); }
|
||||
|
||||
/*!
|
||||
* @brief Turn an LED off
|
||||
* @param led The handle for the LED
|
||||
*/
|
||||
inline void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
|
||||
__inline__ void metal_led_off(struct metal_led *led) { led->vtable->led_off(led); }
|
||||
|
||||
/*!
|
||||
* @brief Toggle the on/off state of an LED
|
||||
* @param led The handle for the LED
|
||||
*/
|
||||
inline void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
|
||||
__inline__ void metal_led_toggle(struct metal_led *led) { led->vtable->led_toggle(led); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#ifndef METAL__LOCK_H
|
||||
#define METAL__LOCK_H
|
||||
|
||||
#include <metal/machine.h>
|
||||
#include <metal/memory.h>
|
||||
#include <metal/compiler.h>
|
||||
|
||||
|
@ -15,6 +16,9 @@
|
|||
/* TODO: How can we make the exception code platform-independant? */
|
||||
#define _METAL_STORE_AMO_ACCESS_FAULT 7
|
||||
|
||||
#define METAL_LOCK_BACKOFF_CYCLES 32
|
||||
#define METAL_LOCK_BACKOFF_EXPONENT 2
|
||||
|
||||
/*!
|
||||
* @def METAL_LOCK_DECLARE
|
||||
* @brief Declare a lock
|
||||
|
@ -41,7 +45,7 @@ struct metal_lock {
|
|||
* If the lock cannot be initialized, attempts to take or give the lock
|
||||
* will result in a Store/AMO access fault.
|
||||
*/
|
||||
inline int metal_lock_init(struct metal_lock *lock) {
|
||||
__inline__ int metal_lock_init(struct metal_lock *lock) {
|
||||
#ifdef __riscv_atomic
|
||||
/* Get a handle for the memory which holds the lock state */
|
||||
struct metal_memory *lock_mem = metal_get_memory_from_address((uintptr_t) &(lock->_state));
|
||||
|
@ -70,16 +74,31 @@ inline int metal_lock_init(struct metal_lock *lock) {
|
|||
* If the lock initialization failed, attempts to take a lock will result in
|
||||
* a Store/AMO access fault.
|
||||
*/
|
||||
inline int metal_lock_take(struct metal_lock *lock) {
|
||||
__inline__ int metal_lock_take(struct metal_lock *lock) {
|
||||
#ifdef __riscv_atomic
|
||||
int old = 1;
|
||||
int new = 1;
|
||||
|
||||
while(old != 0) {
|
||||
int backoff = 1;
|
||||
const int max_backoff = METAL_LOCK_BACKOFF_CYCLES * METAL_MAX_CORES;
|
||||
|
||||
while(1) {
|
||||
__asm__ volatile("amoswap.w.aq %[old], %[new], (%[state])"
|
||||
: [old] "=r" (old)
|
||||
: [new] "r" (new), [state] "r" (&(lock->_state))
|
||||
: "memory");
|
||||
|
||||
if (old == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < backoff; i++) {
|
||||
__asm__ volatile("");
|
||||
}
|
||||
|
||||
if (backoff < max_backoff) {
|
||||
backoff *= METAL_LOCK_BACKOFF_EXPONENT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -104,7 +123,7 @@ inline int metal_lock_take(struct metal_lock *lock) {
|
|||
* If the lock initialization failed, attempts to give a lock will result in
|
||||
* a Store/AMO access fault.
|
||||
*/
|
||||
inline int metal_lock_give(struct metal_lock *lock) {
|
||||
__inline__ int metal_lock_give(struct metal_lock *lock) {
|
||||
#ifdef __riscv_atomic
|
||||
__asm__ volatile("amoswap.w.rl x0, x0, (%[state])"
|
||||
:: [state] "r" (&(lock->_state))
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
*/
|
||||
|
||||
struct _metal_memory_attributes {
|
||||
int R : 1;
|
||||
int W : 1;
|
||||
int X : 1;
|
||||
int C : 1;
|
||||
int A : 1;
|
||||
unsigned int R : 1;
|
||||
unsigned int W : 1;
|
||||
unsigned int X : 1;
|
||||
unsigned int C : 1;
|
||||
unsigned int A : 1;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -46,7 +46,7 @@ struct metal_memory *metal_get_memory_from_address(const uintptr_t address);
|
|||
* @param memory The handle for the memory block
|
||||
* @return The base address of the memory block
|
||||
*/
|
||||
inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
|
||||
__inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory) {
|
||||
return memory->_base_address;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory
|
|||
* @param memory The handle for the memory block
|
||||
* @return The size of the memory block
|
||||
*/
|
||||
inline size_t metal_memory_get_size(const struct metal_memory *memory) {
|
||||
__inline__ size_t metal_memory_get_size(const struct metal_memory *memory) {
|
||||
return memory->_size;
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ inline size_t metal_memory_get_size(const struct metal_memory *memory) {
|
|||
* @param memory The handle for the memory block
|
||||
* @return nonzero if the memory block supports atomic operations
|
||||
*/
|
||||
inline int metal_memory_supports_atomics(const struct metal_memory *memory) {
|
||||
__inline__ int metal_memory_supports_atomics(const struct metal_memory *memory) {
|
||||
return memory->_attrs.A;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ inline int metal_memory_supports_atomics(const struct metal_memory *memory) {
|
|||
* @param memory The handle for the memory block
|
||||
* @return nonzero if the memory block is cachable
|
||||
*/
|
||||
inline int metal_memory_is_cachable(const struct metal_memory *memory) {
|
||||
__inline__ int metal_memory_is_cachable(const struct metal_memory *memory) {
|
||||
return memory->_attrs.C;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,11 +42,11 @@ enum metal_pmp_address_mode {
|
|||
*/
|
||||
struct metal_pmp_config {
|
||||
/*! @brief Sets whether reads to the PMP region succeed */
|
||||
int R : 1;
|
||||
unsigned int R : 1;
|
||||
/*! @brief Sets whether writes to the PMP region succeed */
|
||||
int W : 1;
|
||||
unsigned int W : 1;
|
||||
/*! @brief Sets whether the PMP region is executable */
|
||||
int X : 1;
|
||||
unsigned int X : 1;
|
||||
|
||||
/*! @brief Sets the addressing mode of the PMP region */
|
||||
enum metal_pmp_address_mode A : 2;
|
||||
|
@ -73,6 +73,11 @@ struct metal_pmp {
|
|||
*/
|
||||
struct metal_pmp *metal_pmp_get_device(void);
|
||||
|
||||
/*!
|
||||
* @brief Get the number of pmp regions for the hartid
|
||||
*/
|
||||
int metal_pmp_num_regions(int hartid);
|
||||
|
||||
/*!
|
||||
* @brief Initialize the PMP
|
||||
* @param pmp The PMP device handle to be initialized
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
enum metal_privilege_mode {
|
||||
METAL_PRIVILEGE_USER = 0,
|
||||
METAL_PRIVILEGE_SUPERVISOR = 1,
|
||||
METAL_PRIVELEGE_MACHINE = 3,
|
||||
METAL_PRIVILEGE_MACHINE = 3,
|
||||
};
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
|
@ -113,7 +113,7 @@ struct metal_register_file {
|
|||
#endif /* __riscv_flen */
|
||||
};
|
||||
|
||||
typedef void (*metal_privilege_entry_point_t)();
|
||||
typedef void (*metal_privilege_entry_point_t)(void);
|
||||
|
||||
void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
|
||||
struct metal_register_file regfile,
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/* Copyright 2019 SiFive, Inc. */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__RTC_H
|
||||
#define METAL__RTC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*!
|
||||
* @file rtc.h
|
||||
* @brief API for Real-Time Clocks
|
||||
*/
|
||||
|
||||
struct metal_rtc;
|
||||
|
||||
/*!
|
||||
* @brief List of RTC run behaviors
|
||||
*/
|
||||
enum metal_rtc_run_option {
|
||||
METAL_RTC_STOP = 0,
|
||||
METAL_RTC_RUN,
|
||||
};
|
||||
|
||||
struct metal_rtc_vtable {
|
||||
uint64_t (*get_rate)(const struct metal_rtc *const rtc);
|
||||
uint64_t (*set_rate)(const struct metal_rtc *const rtc, const uint64_t rate);
|
||||
uint64_t (*get_compare)(const struct metal_rtc *const rtc);
|
||||
uint64_t (*set_compare)(const struct metal_rtc *const rtc, const uint64_t compare);
|
||||
uint64_t (*get_count)(const struct metal_rtc *const rtc);
|
||||
uint64_t (*set_count)(const struct metal_rtc *const rtc, const uint64_t count);
|
||||
int (*run)(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option);
|
||||
struct metal_interrupt *(*get_interrupt)(const struct metal_rtc *const rtc);
|
||||
int (*get_interrupt_id)(const struct metal_rtc *const rtc);
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Handle for a Real-Time Clock
|
||||
*/
|
||||
struct metal_rtc {
|
||||
const struct metal_rtc_vtable *vtable;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Get the rate of the RTC
|
||||
* @return The rate in Hz
|
||||
*/
|
||||
inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc) {
|
||||
return rtc->vtable->get_rate(rtc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set (if possible) the rate of the RTC
|
||||
* @return The new rate of the RTC (not guaranteed to be the same as requested)
|
||||
*/
|
||||
inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
|
||||
return rtc->vtable->set_rate(rtc, rate);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the compare value of the RTC
|
||||
* @return The compare value
|
||||
*/
|
||||
inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc) {
|
||||
return rtc->vtable->get_compare(rtc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the compare value of the RTC
|
||||
* @return The set compare value (not guaranteed to be exactly the requested value)
|
||||
*
|
||||
* The RTC device might impose limits on the maximum compare value or the granularity
|
||||
* of the compare value.
|
||||
*/
|
||||
inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
|
||||
return rtc->vtable->set_compare(rtc, compare);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the current count of the RTC
|
||||
* @return The count
|
||||
*/
|
||||
inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc) {
|
||||
return rtc->vtable->get_count(rtc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the current count of the RTC
|
||||
* @return The set value of the count (not guaranteed to be exactly the requested value)
|
||||
*
|
||||
* The RTC device might impose limits on the maximum value of the count
|
||||
*/
|
||||
inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
|
||||
return rtc->vtable->set_count(rtc, count);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Start or stop the RTC
|
||||
* @return 0 if the RTC was successfully started/stopped
|
||||
*/
|
||||
inline int metal_rtc_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
|
||||
return rtc->vtable->run(rtc, option);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt handle for the RTC compare
|
||||
* @return The interrupt handle
|
||||
*/
|
||||
inline struct metal_interrupt *metal_rtc_get_interrupt(const struct metal_rtc *const rtc) {
|
||||
return rtc->vtable->get_interrupt(rtc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt ID for the RTC compare
|
||||
* @return The interrupt ID
|
||||
*/
|
||||
inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc) {
|
||||
return rtc->vtable->get_interrupt_id(rtc);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the handle for an RTC by index
|
||||
* @return The RTC handle, or NULL if none is available at that index
|
||||
*/
|
||||
struct metal_rtc *metal_rtc_get_device(int index);
|
||||
|
||||
#endif
|
||||
|
|
@ -19,8 +19,8 @@ struct __metal_shutdown {
|
|||
const struct __metal_shutdown_vtable *vtable;
|
||||
};
|
||||
|
||||
inline void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
|
||||
inline void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) { sd->vtable->exit(sd, code); }
|
||||
__inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
|
||||
__inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code) { sd->vtable->exit(sd, code); }
|
||||
|
||||
/*!
|
||||
* @brief The public METAL shutdown interface
|
||||
|
|
|
@ -25,6 +25,18 @@ struct metal_spi_config {
|
|||
unsigned int cs_active_high : 1;
|
||||
/*! @brief The chip select ID to activate for the SPI transfer */
|
||||
unsigned int csid;
|
||||
/*! @brief The spi command frame number (cycles = num * frame_len) */
|
||||
unsigned int cmd_num;
|
||||
/*! @brief The spi address frame number */
|
||||
unsigned int addr_num;
|
||||
/*! @brief The spi dummy frame number */
|
||||
unsigned int dummy_num;
|
||||
/*! @brief The Dual/Quad spi mode selection.*/
|
||||
enum {
|
||||
MULTI_WIRE_ALL,
|
||||
MULTI_WIRE_DATA_ONLY,
|
||||
MULTI_WIRE_ADDR_DATA
|
||||
} multi_wire;
|
||||
};
|
||||
|
||||
struct metal_spi_vtable {
|
||||
|
@ -42,13 +54,13 @@ struct metal_spi {
|
|||
/*! @brief Get a handle for a SPI device
|
||||
* @param device_num The index of the desired SPI device
|
||||
* @return A handle to the SPI device, or NULL if the device does not exist*/
|
||||
struct metal_spi *metal_spi_get_device(int device_num);
|
||||
struct metal_spi *metal_spi_get_device(unsigned int device_num);
|
||||
|
||||
/*! @brief Initialize a SPI device with a certain baud rate
|
||||
* @param spi The handle for the SPI device to initialize
|
||||
* @param baud_rate The baud rate to set the SPI device to
|
||||
*/
|
||||
inline void metal_spi_init(struct metal_spi *spi, int baud_rate) { spi->vtable->init(spi, baud_rate); }
|
||||
__inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate) { spi->vtable->init(spi, baud_rate); }
|
||||
|
||||
/*! @brief Perform a SPI transfer
|
||||
* @param spi The handle for the SPI device to perform the transfer
|
||||
|
@ -58,7 +70,7 @@ inline void metal_spi_init(struct metal_spi *spi, int baud_rate) { spi->vtable->
|
|||
* @param rx_buf The buffer to receive data into. Must be len bytes long. If NULL, the SPI will ignore received bytes.
|
||||
* @return 0 if the transfer succeeds
|
||||
*/
|
||||
inline int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf) {
|
||||
__inline__ int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf) {
|
||||
return spi->vtable->transfer(spi, config, len, tx_buf, rx_buf);
|
||||
}
|
||||
|
||||
|
@ -66,13 +78,13 @@ inline int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *co
|
|||
* @param spi The handle for the SPI device
|
||||
* @return The baud rate in Hz
|
||||
*/
|
||||
inline int metal_spi_get_baud_rate(struct metal_spi *spi) { return spi->vtable->get_baud_rate(spi); }
|
||||
__inline__ int metal_spi_get_baud_rate(struct metal_spi *spi) { return spi->vtable->get_baud_rate(spi); }
|
||||
|
||||
/*! @brief Set the current baud rate of the SPI device
|
||||
* @param spi The handle for the SPI device
|
||||
* @param baud_rate The desired baud rate of the SPI device
|
||||
* @return 0 if the baud rate is successfully changed
|
||||
*/
|
||||
inline int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate) { return spi->vtable->set_baud_rate(spi, baud_rate); }
|
||||
__inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate) { return spi->vtable->set_baud_rate(spi, baud_rate); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,7 @@ struct metal_switch* metal_switch_get(char *label);
|
|||
* @param sw The handle for the switch
|
||||
* @return The interrupt controller handle
|
||||
*/
|
||||
inline struct metal_interrupt*
|
||||
__inline__ struct metal_interrupt*
|
||||
metal_switch_interrupt_controller(struct metal_switch *sw) { return sw->vtable->interrupt_controller(sw); }
|
||||
|
||||
/*!
|
||||
|
@ -46,6 +46,6 @@ inline struct metal_interrupt*
|
|||
* @param sw The handle for the switch
|
||||
* @return The interrupt ID for the switch
|
||||
*/
|
||||
inline int metal_switch_get_interrupt_id(struct metal_switch *sw) { return sw->vtable->get_interrupt_id(sw); }
|
||||
__inline__ int metal_switch_get_interrupt_id(struct metal_switch *sw) { return sw->vtable->get_interrupt_id(sw); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__TIME_H
|
||||
#define METAL__TIME_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/*!
|
||||
* @file time.h
|
||||
* @brief API for dealing with time
|
||||
*/
|
||||
|
||||
int metal_gettimeofday(struct timeval *tp, void *tzp);
|
||||
|
||||
time_t metal_time(void);
|
||||
|
||||
#endif
|
|
@ -14,10 +14,39 @@
|
|||
*
|
||||
* Write a character to the default output device, which for most
|
||||
* targets is the UART serial port.
|
||||
*
|
||||
*
|
||||
* putc() does CR/LF mapping.
|
||||
* putc_raw() does not.
|
||||
*
|
||||
* @param c The character to write to the terminal
|
||||
* @return 0 on success, or -1 on failure.
|
||||
*/
|
||||
int metal_tty_putc(unsigned char c);
|
||||
int metal_tty_putc(int c);
|
||||
|
||||
/*!
|
||||
* @brief Write a raw character to the default output device
|
||||
*
|
||||
* Write a character to the default output device, which for most
|
||||
* targets is the UART serial port.
|
||||
*
|
||||
* putc() does CR/LF mapping.
|
||||
* putc_raw() does not.
|
||||
*
|
||||
* @param c The character to write to the terminal
|
||||
* @return 0 on success, or -1 on failure.
|
||||
*/
|
||||
int metal_tty_putc_raw(int c);
|
||||
|
||||
/*!
|
||||
* @brief Get a byte from the default output device
|
||||
*
|
||||
* The default output device, is typically the UART serial port.
|
||||
*
|
||||
* This call is non-blocking, if nothing is ready c==-1
|
||||
* if something is ready, then c=[0x00 to 0xff] byte value.
|
||||
*
|
||||
* @return 0 on success, or -1 on failure.
|
||||
*/
|
||||
int metal_tty_getc(int *c);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
#include <metal/interrupt.h>
|
||||
|
||||
struct metal_uart;
|
||||
|
||||
#undef getc
|
||||
#undef putc
|
||||
struct metal_uart_vtable {
|
||||
void (*init)(struct metal_uart *uart, int baud_rate);
|
||||
int (*putc)(struct metal_uart *uart, unsigned char c);
|
||||
int (*getc)(struct metal_uart *uart, unsigned char *c);
|
||||
int (*putc)(struct metal_uart *uart, int c);
|
||||
int (*txready)(struct metal_uart *uart);
|
||||
int (*getc)(struct metal_uart *uart, int *c);
|
||||
int (*get_baud_rate)(struct metal_uart *uart);
|
||||
int (*set_baud_rate)(struct metal_uart *uart, int baud_rate);
|
||||
struct metal_interrupt* (*controller_interrupt)(struct metal_uart *uart);
|
||||
|
@ -39,7 +41,7 @@ struct metal_uart {
|
|||
* @param uart The UART device handle
|
||||
* @param baud_rate the baud rate to set the UART to
|
||||
*/
|
||||
inline void metal_uart_init(struct metal_uart *uart, int baud_rate) { return uart->vtable->init(uart, baud_rate); }
|
||||
__inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate) { uart->vtable->init(uart, baud_rate); }
|
||||
|
||||
/*!
|
||||
* @brief Output a character over the UART
|
||||
|
@ -47,22 +49,32 @@ inline void metal_uart_init(struct metal_uart *uart, int baud_rate) { return uar
|
|||
* @param c The character to send over the UART
|
||||
* @return 0 upon success
|
||||
*/
|
||||
inline int metal_uart_putc(struct metal_uart *uart, unsigned char c) { return uart->vtable->putc(uart, c); }
|
||||
__inline__ int metal_uart_putc(struct metal_uart *uart, int c) { return uart->vtable->putc(uart, c); }
|
||||
|
||||
/*!
|
||||
* @brief Test, determine if tx output is blocked(full/busy)
|
||||
* @param uart The UART device handle
|
||||
* @return 0 not blocked
|
||||
*/
|
||||
__inline__ int metal_uart_txready(struct metal_uart *uart) { return uart->vtable->txready(uart); }
|
||||
|
||||
/*!
|
||||
* @brief Read a character sent over the UART
|
||||
* @param uart The UART device handle
|
||||
* @param c The varible to hold the read character
|
||||
* @return 0 upon success
|
||||
*
|
||||
* If "c == -1" no char was ready.
|
||||
* If "c != -1" then C == byte value (0x00 to 0xff)
|
||||
*/
|
||||
inline int metal_uart_getc(struct metal_uart *uart, unsigned char *c) { return uart->vtable->getc(uart, c); }
|
||||
__inline__ int metal_uart_getc(struct metal_uart *uart, int *c) { return uart->vtable->getc(uart, c); }
|
||||
|
||||
/*!
|
||||
* @brief Get the baud rate of the UART peripheral
|
||||
* @param uart The UART device handle
|
||||
* @return The current baud rate of the UART
|
||||
*/
|
||||
inline int metal_uart_get_baud_rate(struct metal_uart *uart) { return uart->vtable->get_baud_rate(uart); }
|
||||
__inline__ int metal_uart_get_baud_rate(struct metal_uart *uart) { return uart->vtable->get_baud_rate(uart); }
|
||||
|
||||
/*!
|
||||
* @brief Set the baud rate of the UART peripheral
|
||||
|
@ -70,7 +82,7 @@ inline int metal_uart_get_baud_rate(struct metal_uart *uart) { return uart->vtab
|
|||
* @param baud_rate The baud rate to configure
|
||||
* @return the new baud rate of the UART
|
||||
*/
|
||||
inline int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate) { return uart->vtable->set_baud_rate(uart, baud_rate); }
|
||||
__inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate) { return uart->vtable->set_baud_rate(uart, baud_rate); }
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt controller of the UART peripheral
|
||||
|
@ -82,13 +94,13 @@ inline int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate) { re
|
|||
* @param uart The UART device handle
|
||||
* @return The handle for the UART interrupt controller
|
||||
*/
|
||||
inline struct metal_interrupt* metal_uart_interrupt_controller(struct metal_uart *uart) { return uart->vtable->controller_interrupt(uart); }
|
||||
__inline__ struct metal_interrupt* metal_uart_interrupt_controller(struct metal_uart *uart) { return uart->vtable->controller_interrupt(uart); }
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt ID of the UART controller
|
||||
* @param uart The UART device handle
|
||||
* @return The UART interrupt id
|
||||
*/
|
||||
inline int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
|
||||
__inline__ int metal_uart_get_interrupt_id(struct metal_uart *uart) { return uart->vtable->get_interrupt_id(uart); }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef METAL__WATCHDOG_H
|
||||
#define METAL__WATCHDOG_H
|
||||
|
||||
/*!
|
||||
* @file watchdog.h
|
||||
*
|
||||
* @brief API for configuring watchdog timers
|
||||
*/
|
||||
|
||||
#include <metal/interrupt.h>
|
||||
|
||||
struct metal_watchdog;
|
||||
|
||||
/*!
|
||||
* @brief List of watchdog timer count behaviors
|
||||
*/
|
||||
enum metal_watchdog_run_option {
|
||||
METAL_WATCHDOG_STOP = 0, /*!< Stop the watchdog */
|
||||
METAL_WATCHDOG_RUN_ALWAYS, /*!< Run the watchdog continuously, even during sleep */
|
||||
METAL_WATCHDOG_RUN_AWAKE, /*!< Run the watchdog only while the CPU is awake */
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief List of behaviors when a watchdog triggers
|
||||
*/
|
||||
enum metal_watchdog_result {
|
||||
METAL_WATCHDOG_NO_RESULT = 0, /*!< When the watchdog triggers, do nothing */
|
||||
METAL_WATCHDOG_INTERRUPT, /*!< When the watchdog triggers, fire an interrupt */
|
||||
METAL_WATCHDOG_FULL_RESET, /*!< When the watchdog triggers, cause a full system reset */
|
||||
};
|
||||
|
||||
|
||||
struct metal_watchdog_vtable {
|
||||
int (*feed)(const struct metal_watchdog *const wdog);
|
||||
long int (*get_rate)(const struct metal_watchdog *const wdog);
|
||||
long int (*set_rate)(const struct metal_watchdog *const wdog, const long int rate);
|
||||
long int (*get_timeout)(const struct metal_watchdog *const wdog);
|
||||
long int (*set_timeout)(const struct metal_watchdog *const wdog, const long int timeout);
|
||||
int (*set_result)(const struct metal_watchdog *const wdog,
|
||||
const enum metal_watchdog_result result);
|
||||
int (*run)(const struct metal_watchdog *const wdog,
|
||||
const enum metal_watchdog_run_option option);
|
||||
struct metal_interrupt *(*get_interrupt)(const struct metal_watchdog *const wdog);
|
||||
int (*get_interrupt_id)(const struct metal_watchdog *const wdog);
|
||||
int (*clear_interrupt)(const struct metal_watchdog *const wdog);
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Handle for a Watchdog Timer
|
||||
*/
|
||||
struct metal_watchdog {
|
||||
const struct metal_watchdog_vtable *vtable;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Feed the watchdog timer
|
||||
*/
|
||||
inline int metal_watchdog_feed(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return wdog->vtable->feed(wdog);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the rate of the watchdog timer in Hz
|
||||
*
|
||||
* @return the rate of the watchdog timer
|
||||
*/
|
||||
inline long int metal_watchdog_get_rate(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return wdog->vtable->get_rate(wdog);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the rate of the watchdog timer in Hz
|
||||
*
|
||||
* There is no guarantee that the new rate will match the requested rate.
|
||||
*
|
||||
* @return the new rate of the watchdog timer
|
||||
*/
|
||||
inline long int metal_watchdog_set_rate(const struct metal_watchdog *const wdog, const long int rate)
|
||||
{
|
||||
return wdog->vtable->set_rate(wdog, rate);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the timeout of the watchdog timer
|
||||
*
|
||||
* @return the watchdog timeout value
|
||||
*/
|
||||
inline long int metal_watchdog_get_timeout(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return wdog->vtable->get_timeout(wdog);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the timeout of the watchdog timer
|
||||
*
|
||||
* The set rate will be the minimimum of the requested and maximum supported rates.
|
||||
*
|
||||
* @return the new watchdog timeout value
|
||||
*/
|
||||
inline long int metal_watchdog_set_timeout(const struct metal_watchdog *const wdog, const long int timeout)
|
||||
{
|
||||
return wdog->vtable->set_timeout(wdog, timeout);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Sets the result behavior of a watchdog timer timeout
|
||||
*
|
||||
* @return 0 if the requested result behavior is supported
|
||||
*/
|
||||
inline int metal_watchdog_set_result(const struct metal_watchdog *const wdog,
|
||||
const enum metal_watchdog_result result)
|
||||
{
|
||||
return wdog->vtable->set_result(wdog, result);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the run behavior of the watchdog
|
||||
*
|
||||
* Used to enable/disable the watchdog timer
|
||||
*
|
||||
* @return 0 if the watchdog was successfully started/stopped
|
||||
*/
|
||||
inline int metal_watchdog_run(const struct metal_watchdog *const wdog,
|
||||
const enum metal_watchdog_run_option option)
|
||||
{
|
||||
return wdog->vtable->run(wdog, option);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the interrupt controller for the watchdog interrupt
|
||||
*/
|
||||
inline struct metal_interrupt *metal_watchdog_get_interrupt(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return wdog->vtable->get_interrupt(wdog);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @Brief Get the interrupt id for the watchdog interrupt
|
||||
*/
|
||||
inline int metal_watchdog_get_interrupt_id(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return wdog->vtable->get_interrupt_id(wdog);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Clear the watchdog interrupt
|
||||
*/
|
||||
inline int metal_watchdog_clear_interrupt(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return wdog->vtable->clear_interrupt(wdog);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get a watchdog handle
|
||||
*/
|
||||
struct metal_watchdog *metal_watchdog_get_device(const int index);
|
||||
|
||||
#endif /* METAL__WATCHDOG_H */
|
|
@ -22,6 +22,6 @@ struct metal_button* metal_button_get (char *label)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern inline struct metal_interrupt*
|
||||
extern __inline__ struct metal_interrupt*
|
||||
metal_button_interrupt_controller(struct metal_button *button);
|
||||
extern inline int metal_button_get_interrupt_id(struct metal_button *button);
|
||||
extern __inline__ int metal_button_get_interrupt_id(struct metal_button *button);
|
||||
|
|
|
@ -2,7 +2,186 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/cache.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways);
|
||||
extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache);
|
||||
extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways);
|
||||
|
||||
int metal_dcache_l1_available(int hartid) {
|
||||
switch (hartid) {
|
||||
case 0:
|
||||
#ifdef __METAL_CPU_0_DCACHE_HANDLE
|
||||
return __METAL_CPU_0_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
#ifdef __METAL_CPU_1_DCACHE_HANDLE
|
||||
return __METAL_CPU_1_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
#ifdef __METAL_CPU_2_DCACHE_HANDLE
|
||||
return __METAL_CPU_2_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
#ifdef __METAL_CPU_3_DCACHE_HANDLE
|
||||
return __METAL_CPU_3_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
#ifdef __METAL_CPU_4_DCACHE_HANDLE
|
||||
return __METAL_CPU_4_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 5:
|
||||
#ifdef __METAL_CPU_5_DCACHE_HANDLE
|
||||
return __METAL_CPU_5_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 6:
|
||||
#ifdef __METAL_CPU_6_DCACHE_HANDLE
|
||||
return __METAL_CPU_6_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 7:
|
||||
#ifdef __METAL_CPU_7_DCACHE_HANDLE
|
||||
return __METAL_CPU_7_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 8:
|
||||
#ifdef __METAL_CPU_8_DCACHE_HANDLE
|
||||
return __METAL_CPU_8_DCACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int metal_icache_l1_available(int hartid) {
|
||||
switch (hartid) {
|
||||
case 0:
|
||||
#ifdef __METAL_CPU_0_ICACHE_HANDLE
|
||||
return __METAL_CPU_0_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
#ifdef __METAL_CPU_1_ICACHE_HANDLE
|
||||
return __METAL_CPU_1_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
#ifdef __METAL_CPU_2_ICACHE_HANDLE
|
||||
return __METAL_CPU_2_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
#ifdef __METAL_CPU_3_ICACHE_HANDLE
|
||||
return __METAL_CPU_3_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
#ifdef __METAL_CPU_4_ICACHE_HANDLE
|
||||
return __METAL_CPU_4_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 5:
|
||||
#ifdef __METAL_CPU_5_ICACHE_HANDLE
|
||||
return __METAL_CPU_5_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 6:
|
||||
#ifdef __METAL_CPU_6_ICACHE_HANDLE
|
||||
return __METAL_CPU_6_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 7:
|
||||
#ifdef __METAL_CPU_7_ICACHE_HANDLE
|
||||
return __METAL_CPU_7_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case 8:
|
||||
#ifdef __METAL_CPU_8_ICACHE_HANDLE
|
||||
return __METAL_CPU_8_ICACHE_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief CFlush.D.L1 instruction is a custom instruction implemented as a
|
||||
* state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
|
||||
* It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
|
||||
* 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
|
||||
* |--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
* +-------------+------------+----------+------+--------+-----------------+
|
||||
* |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
|
||||
* |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
|
||||
* +--------------------------+----------+------+--------+-----------------+
|
||||
* 31 -0x40 20 15 0 12 x0 7 0x73 0
|
||||
* +--------+--------+--------+----------+------+--------+--------+--------+
|
||||
* where,
|
||||
* rs1 = 0x0, CFLUSH.D.L1 writes back and invalidates all lines in the L1 D$
|
||||
* rs1 != x0, CFLUSH.D.L1 writes back and invalidates the L1 D$ line containing
|
||||
* the virtual address in integer register rs1.
|
||||
*/
|
||||
void metal_dcache_l1_flush(int hartid, uintptr_t address)
|
||||
{
|
||||
if (metal_dcache_l1_available(hartid)) {
|
||||
// Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
|
||||
__asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x40" : : "r" (address));
|
||||
__asm__ __volatile__ ("fence.i"); // FENCE
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief CDiscard.D.L1 instruction is a custom instruction implemented as a
|
||||
* state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
|
||||
* It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
|
||||
* 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
|
||||
* |--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
* +-------------+------------+----------+------+--------+-----------------+
|
||||
* |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
|
||||
* |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
|
||||
* +--------------------------+----------+------+--------+-----------------+
|
||||
* 31 -0x3E 20 15 0 12 x0 7 0x73 0
|
||||
* +--------+--------+--------+----------+------+--------+--------+--------+
|
||||
* where,
|
||||
* rs1 = 0x0, CDISCARD.D.L1 invalidates all lines in the L1 D$ with no writes back.
|
||||
* rs1 != x0, CDISCARD.D.L1 invalidates the L1 D$ line containing the virtual address
|
||||
* in integer register rs1, with no writes back.
|
||||
*/
|
||||
void metal_dcache_l1_discard(int hartid, uintptr_t address)
|
||||
{
|
||||
if (metal_dcache_l1_available(hartid)) {
|
||||
// Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
|
||||
__asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x3E" : : "r" (address));
|
||||
__asm__ __volatile__ ("fence.i"); // FENCE
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief CFlush.I.L1 instruction is a custom instruction implemented as a state
|
||||
* machine in L1 Instruction Cache (I$) with funct3=0, (for core with data caches)
|
||||
* It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
|
||||
* 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
|
||||
* |--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
* +-------------+------------+----------+------+--------+-----------------+
|
||||
* |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
|
||||
* |-1-1-1-1 -1-1-0-0 -0-0-0-0|-0-0-0-0-0|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
|
||||
* +--------------------------+----------+------+--------+-----------------+
|
||||
* 31 -0x3F 20 15 0 12 x0 7 0x73 0
|
||||
* +--------+--------+--------+----------+------+--------+--------+--------+
|
||||
* CFLUSH.I.L1 invalidates all lines in the L1 I$.
|
||||
*/
|
||||
void metal_icache_l1_flush(int hartid)
|
||||
{
|
||||
if (metal_icache_l1_available(hartid)) {
|
||||
// Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
|
||||
__asm__ __volatile__ (".insn i 0x73, 0, x0, x0, -0x3F" : : );
|
||||
__asm__ __volatile__ ("fence.i"); // FENCE
|
||||
}
|
||||
}
|
||||
|
||||
extern inline void metal_cache_init(struct metal_cache *cache, int ways);
|
||||
extern inline int metal_cache_get_enabled_ways(struct metal_cache *cache);
|
||||
extern inline int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways);
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
#include <metal/clock.h>
|
||||
|
||||
extern inline long metal_clock_get_rate_hz(const struct metal_clock *clk);
|
||||
extern inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz);
|
||||
extern inline void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_post_rate_change_callback cb, void *priv);
|
||||
extern inline void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_pre_rate_change_callback cb, void *priv);
|
||||
extern __inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list);
|
||||
extern __inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb);
|
||||
|
||||
extern __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk);
|
||||
extern __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz);
|
||||
extern __inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb);
|
||||
extern __inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <metal/cpu.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
struct metal_cpu* metal_cpu_get(int hartid)
|
||||
struct metal_cpu* metal_cpu_get(unsigned int hartid)
|
||||
{
|
||||
if (hartid < __METAL_DT_MAX_HARTS) {
|
||||
return (struct metal_cpu *)__metal_cpu_table[hartid];
|
||||
|
@ -16,7 +16,7 @@ int metal_cpu_get_current_hartid()
|
|||
{
|
||||
#ifdef __riscv
|
||||
int mhartid;
|
||||
asm volatile("csrr %0, mhartid" : "=r" (mhartid));
|
||||
__asm__ volatile("csrr %0, mhartid" : "=r" (mhartid));
|
||||
return mhartid;
|
||||
#endif
|
||||
}
|
||||
|
@ -26,34 +26,34 @@ int metal_cpu_get_num_harts()
|
|||
return __METAL_DT_MAX_HARTS;
|
||||
}
|
||||
|
||||
extern inline unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu);
|
||||
extern __inline__ unsigned long long metal_cpu_get_timer(struct metal_cpu *cpu);
|
||||
|
||||
extern inline unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu);
|
||||
extern __inline__ unsigned long long metal_cpu_get_timebase(struct metal_cpu *cpu);
|
||||
|
||||
extern inline unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu);
|
||||
extern __inline__ unsigned long long metal_cpu_get_mtime(struct metal_cpu *cpu);
|
||||
|
||||
extern inline int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time);
|
||||
extern __inline__ int metal_cpu_set_mtimecmp(struct metal_cpu *cpu, unsigned long long time);
|
||||
|
||||
extern inline struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu);
|
||||
extern __inline__ struct metal_interrupt* metal_cpu_timer_interrupt_controller(struct metal_cpu *cpu);
|
||||
|
||||
extern inline int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu);
|
||||
extern __inline__ int metal_cpu_timer_get_interrupt_id(struct metal_cpu *cpu);
|
||||
|
||||
extern inline struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu);
|
||||
extern __inline__ struct metal_interrupt* metal_cpu_software_interrupt_controller(struct metal_cpu *cpu);
|
||||
|
||||
extern inline int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu);
|
||||
extern __inline__ int metal_cpu_software_get_interrupt_id(struct metal_cpu *cpu);
|
||||
|
||||
extern inline int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid);
|
||||
extern __inline__ int metal_cpu_software_set_ipi(struct metal_cpu *cpu, int hartid);
|
||||
|
||||
extern inline int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid);
|
||||
extern __inline__ int metal_cpu_software_clear_ipi(struct metal_cpu *cpu, int hartid);
|
||||
|
||||
extern inline int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid);
|
||||
extern __inline__ int metal_cpu_get_msip(struct metal_cpu *cpu, int hartid);
|
||||
|
||||
extern inline struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu);
|
||||
extern __inline__ struct metal_interrupt* metal_cpu_interrupt_controller(struct metal_cpu *cpu);
|
||||
|
||||
extern inline int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
|
||||
extern __inline__ int metal_cpu_exception_register(struct metal_cpu *cpu, int ecode, metal_exception_handler_t handler);
|
||||
|
||||
extern inline int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc);
|
||||
extern __inline__ int metal_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc);
|
||||
|
||||
extern inline uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu);
|
||||
extern __inline__ uintptr_t metal_cpu_get_exception_pc(struct metal_cpu *cpu);
|
||||
|
||||
extern inline int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc);
|
||||
extern __inline__ int metal_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t epc);
|
||||
|
|
|
@ -25,3 +25,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_clock) = {
|
|||
};
|
||||
|
||||
#endif /* METAL_FIXED_CLOCK */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -30,3 +30,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_fixed_factor_clock) = {
|
|||
.clock.set_rate_hz = __metal_driver_fixed_factor_clock_set_rate_hz,
|
||||
};
|
||||
#endif /* METAL_FIXED_FACTOR_CLOCK */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -76,11 +76,15 @@ int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller,
|
|||
void *priv)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
|
||||
struct metal_interrupt *intc = NULL;
|
||||
struct metal_interrupt *cpu_intc = _get_cpu_intc();
|
||||
int num_interrupts = __metal_driver_sifive_clint0_num_interrupts(controller);
|
||||
|
||||
if ( (mode != METAL_VECTOR_MODE) && (mode != METAL_DIRECT_MODE) ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
for(int i = 0; i < num_interrupts; i++) {
|
||||
int line = __metal_driver_sifive_clint0_interrupt_lines(controller, i);
|
||||
intc = __metal_driver_sifive_clint0_interrupt_parents(controller, i);
|
||||
|
@ -97,6 +101,41 @@ int __metal_driver_riscv_clint0_register (struct metal_interrupt *controller,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_vector_register (struct metal_interrupt *controller,
|
||||
int id, metal_interrupt_vector_handler_t isr,
|
||||
void *priv)
|
||||
{
|
||||
/* Not supported. User can override the 'weak' handler with their own */
|
||||
int rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
metal_vector_mode __metal_driver_riscv_clint0_get_vector_mode (struct metal_interrupt *controller)
|
||||
{
|
||||
return __metal_controller_interrupt_vector_mode();
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
|
||||
{
|
||||
int rc = -1;
|
||||
struct metal_interrupt *intc = _get_cpu_intc();
|
||||
|
||||
if (intc) {
|
||||
/* Valid vector modes are VECTOR and DIRECT, anything else is invalid (-1) */
|
||||
switch (mode) {
|
||||
case METAL_VECTOR_MODE:
|
||||
case METAL_DIRECT_MODE:
|
||||
rc = intc->vtable->interrupt_set_vector_mode(intc, mode);
|
||||
break;
|
||||
case METAL_HARDWARE_VECTOR_MODE:
|
||||
case METAL_SELECTIVE_NONVECTOR_MODE:
|
||||
case METAL_SELECTIVE_VECTOR_MODE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
int rc = -1;
|
||||
|
@ -120,6 +159,8 @@ int __metal_driver_riscv_clint0_enable (struct metal_interrupt *controller, int
|
|||
rc = intc->vtable->interrupt_enable(intc, id);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int id)
|
||||
|
@ -145,6 +186,8 @@ int __metal_driver_riscv_clint0_disable (struct metal_interrupt *controller, int
|
|||
rc = intc->vtable->interrupt_disable(intc, id);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *controller,
|
||||
|
@ -206,13 +249,35 @@ int __metal_driver_riscv_clint0_command_request (struct metal_interrupt *control
|
|||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_clear_interrupt (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
int hartid = metal_cpu_get_current_hartid();
|
||||
return __metal_driver_riscv_clint0_command_request(controller,
|
||||
METAL_SOFTWARE_IPI_CLEAR, &hartid);
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_clint0_set_interrupt (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
int hartid = metal_cpu_get_current_hartid();
|
||||
return __metal_driver_riscv_clint0_command_request(controller,
|
||||
METAL_SOFTWARE_IPI_SET, &hartid);
|
||||
}
|
||||
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_clint0) = {
|
||||
.clint_vtable.interrupt_init = __metal_driver_riscv_clint0_init,
|
||||
.clint_vtable.interrupt_register = __metal_driver_riscv_clint0_register,
|
||||
.clint_vtable.interrupt_vector_register = __metal_driver_riscv_clint0_vector_register,
|
||||
.clint_vtable.interrupt_enable = __metal_driver_riscv_clint0_enable,
|
||||
.clint_vtable.interrupt_disable = __metal_driver_riscv_clint0_disable,
|
||||
.clint_vtable.interrupt_get_vector_mode = __metal_driver_riscv_clint0_get_vector_mode,
|
||||
.clint_vtable.interrupt_set_vector_mode = __metal_driver_riscv_clint0_set_vector_mode,
|
||||
.clint_vtable.interrupt_clear = __metal_driver_riscv_clint0_clear_interrupt,
|
||||
.clint_vtable.interrupt_set = __metal_driver_riscv_clint0_set_interrupt,
|
||||
.clint_vtable.command_request = __metal_driver_riscv_clint0_command_request,
|
||||
.clint_vtable.mtimecmp_set = __metal_driver_riscv_clint0_mtimecmp_set,
|
||||
};
|
||||
|
||||
#endif /* METAL_RISCV_CLINT0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <metal/shutdown.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
extern void __metal_vector_table();
|
||||
unsigned long long __metal_driver_cpu_mtime_get(struct metal_cpu *cpu);
|
||||
int __metal_driver_cpu_mtimecmp_set(struct metal_cpu *cpu, unsigned long long time);
|
||||
|
||||
|
@ -20,7 +21,7 @@ struct metal_cpu *__metal_driver_cpu_get(int hartid)
|
|||
uintptr_t __metal_myhart_id (void)
|
||||
{
|
||||
uintptr_t myhart;
|
||||
asm volatile ("csrr %0, mhartid" : "=r"(myhart));
|
||||
__asm__ volatile ("csrr %0, mhartid" : "=r"(myhart));
|
||||
return myhart;
|
||||
}
|
||||
|
||||
|
@ -34,54 +35,54 @@ void __metal_zero_memory (unsigned char *base, unsigned int size)
|
|||
|
||||
void __metal_interrupt_global_enable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
|
||||
__asm__ volatile ("csrrs %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
|
||||
}
|
||||
|
||||
void __metal_interrupt_global_disable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
|
||||
__asm__ volatile ("csrrc %0, mstatus, %1" : "=r"(m) : "r"(METAL_MIE_INTERRUPT));
|
||||
}
|
||||
|
||||
void __metal_interrupt_software_enable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
|
||||
__asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
|
||||
}
|
||||
|
||||
void __metal_interrupt_software_disable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
|
||||
__asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_SW));
|
||||
}
|
||||
|
||||
void __metal_interrupt_timer_enable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
|
||||
__asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
|
||||
}
|
||||
|
||||
void __metal_interrupt_timer_disable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
|
||||
__asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_TMR));
|
||||
}
|
||||
|
||||
void __metal_interrupt_external_enable (void) {
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
|
||||
__asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
|
||||
}
|
||||
|
||||
void __metal_interrupt_external_disable (void) {
|
||||
unsigned long m;
|
||||
asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
|
||||
__asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(METAL_LOCAL_INTERRUPT_EXT));
|
||||
}
|
||||
|
||||
void __metal_interrupt_local_enable (int id) {
|
||||
uintptr_t b = 1 << id;
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b));
|
||||
__asm__ volatile ("csrrs %0, mie, %1" : "=r"(m) : "r"(b));
|
||||
}
|
||||
|
||||
void __metal_interrupt_local_disable (int id) {
|
||||
uintptr_t b = 1 << id;
|
||||
uintptr_t m;
|
||||
asm volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
|
||||
__asm__ volatile ("csrrc %0, mie, %1" : "=r"(m) : "r"(b));
|
||||
}
|
||||
|
||||
void __metal_default_exception_handler (struct metal_cpu *cpu, int ecode) {
|
||||
|
@ -92,12 +93,31 @@ void __metal_default_interrupt_handler (int id, void *priv) {
|
|||
metal_shutdown(200);
|
||||
}
|
||||
|
||||
/* The metal_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_interrupt_vector_handler (void) {
|
||||
metal_shutdown(300);
|
||||
}
|
||||
|
||||
/* The metal_software_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_software_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_SW].handler(METAL_INTERRUPT_ID_SW, priv);
|
||||
}
|
||||
}
|
||||
|
||||
void __metal_default_sw_handler (int id, void *priv) {
|
||||
uintptr_t mcause;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
asm volatile ("csrr %0, mcause" : "=r"(mcause));
|
||||
__asm__ volatile ("csrr %0, mcause" : "=r"(mcause));
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
|
@ -105,6 +125,20 @@ void __metal_default_sw_handler (int id, void *priv) {
|
|||
}
|
||||
}
|
||||
|
||||
/* The metal_timer_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_timer_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_TMR].handler(METAL_INTERRUPT_ID_TMR, priv);
|
||||
}
|
||||
}
|
||||
|
||||
void __metal_default_timer_handler (int id, void *priv) {
|
||||
struct metal_cpu *cpu = __metal_driver_cpu_get(__metal_myhart_id());
|
||||
unsigned long long time = __metal_driver_cpu_mtime_get(cpu);
|
||||
|
@ -113,6 +147,20 @@ void __metal_default_timer_handler (int id, void *priv) {
|
|||
__metal_driver_cpu_mtimecmp_set(cpu, time + 10);
|
||||
}
|
||||
|
||||
/* The metal_external_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_external_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_EXT].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_EXT].handler(METAL_INTERRUPT_ID_EXT, priv);
|
||||
}
|
||||
}
|
||||
|
||||
void __metal_exception_handler(void) __attribute__((interrupt, aligned(128)));
|
||||
void __metal_exception_handler (void) {
|
||||
int id;
|
||||
|
@ -121,17 +169,17 @@ void __metal_exception_handler (void) {
|
|||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
asm volatile ("csrr %0, mcause" : "=r"(mcause));
|
||||
asm volatile ("csrr %0, mepc" : "=r"(mepc));
|
||||
asm volatile ("csrr %0, mtval" : "=r"(mtval));
|
||||
asm volatile ("csrr %0, mtvec" : "=r"(mtvec));
|
||||
__asm__ volatile ("csrr %0, mcause" : "=r"(mcause));
|
||||
__asm__ volatile ("csrr %0, mepc" : "=r"(mepc));
|
||||
__asm__ volatile ("csrr %0, mtval" : "=r"(mtval));
|
||||
__asm__ volatile ("csrr %0, mtvec" : "=r"(mtvec));
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
id = mcause & METAL_MCAUSE_CAUSE;
|
||||
if (mcause & METAL_MCAUSE_INTR) {
|
||||
if ((id < METAL_INTERRUPT_ID_LC0) ||
|
||||
if ((id < METAL_INTERRUPT_ID_CSW) ||
|
||||
((mtvec & METAL_MTVEC_MASK) == METAL_MTVEC_DIRECT)) {
|
||||
priv = intc->metal_int_table[id].exint_data;
|
||||
intc->metal_int_table[id].handler(id, priv);
|
||||
|
@ -141,9 +189,9 @@ void __metal_exception_handler (void) {
|
|||
uintptr_t mtvt;
|
||||
metal_interrupt_handler_t mtvt_handler;
|
||||
|
||||
asm volatile ("csrr %0, mtvt" : "=r"(mtvt));
|
||||
__asm__ volatile ("csrr %0, 0x307" : "=r"(mtvt));
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
|
||||
mtvt_handler = (metal_interrupt_handler_t)mtvt;
|
||||
mtvt_handler = (metal_interrupt_handler_t)*(uintptr_t *)mtvt;
|
||||
mtvt_handler(id, priv);
|
||||
return;
|
||||
}
|
||||
|
@ -153,28 +201,271 @@ void __metal_exception_handler (void) {
|
|||
}
|
||||
}
|
||||
|
||||
/* The metal_lc0_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc0_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC0].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC0].handler(METAL_INTERRUPT_ID_LC0, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc1_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc1_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC1].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC1].handler(METAL_INTERRUPT_ID_LC1, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc2_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc2_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC2].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC2].handler(METAL_INTERRUPT_ID_LC2, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc3_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc3_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC3].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC3].handler(METAL_INTERRUPT_ID_LC3, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc4_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc4_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC4].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC4].handler(METAL_INTERRUPT_ID_LC4, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc5_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc5_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC5].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC5].handler(METAL_INTERRUPT_ID_LC5, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc6_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc6_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC6].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC6].handler(METAL_INTERRUPT_ID_LC6, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc7_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc7_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC7].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC7].handler(METAL_INTERRUPT_ID_LC7, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc8_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc8_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC8].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC8].handler(METAL_INTERRUPT_ID_LC8, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc9_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc9_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC9].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC9].handler(METAL_INTERRUPT_ID_LC9, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc10_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc10_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC10].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC10].handler(METAL_INTERRUPT_ID_LC10, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc11_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc11_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC11].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC11].handler(METAL_INTERRUPT_ID_LC11, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc12_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc12_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC12].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC12].handler(METAL_INTERRUPT_ID_LC12, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc13_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc13_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC13].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC13].handler(METAL_INTERRUPT_ID_LC13, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc14_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc14_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC14].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC14].handler(METAL_INTERRUPT_ID_LC14, priv);
|
||||
}
|
||||
}
|
||||
|
||||
/* The metal_lc15_interrupt_vector_handler() function can be redefined. */
|
||||
void __attribute__((weak, interrupt)) metal_lc15_interrupt_vector_handler (void) {
|
||||
void *priv;
|
||||
struct __metal_driver_riscv_cpu_intc *intc;
|
||||
struct __metal_driver_cpu *cpu = __metal_cpu_table[__metal_myhart_id()];
|
||||
|
||||
if ( cpu ) {
|
||||
intc = (struct __metal_driver_riscv_cpu_intc *)
|
||||
__metal_driver_cpu_interrupt_controller((struct metal_cpu *)cpu);
|
||||
priv = intc->metal_int_table[METAL_INTERRUPT_ID_LC15].exint_data;
|
||||
intc->metal_int_table[METAL_INTERRUPT_ID_LC15].handler(METAL_INTERRUPT_ID_LC15, priv);
|
||||
}
|
||||
}
|
||||
|
||||
metal_vector_mode __metal_controller_interrupt_vector_mode (void)
|
||||
{
|
||||
uintptr_t val;
|
||||
|
||||
asm volatile ("csrr %0, mtvec" : "=r"(val));
|
||||
val &= METAL_MTVEC_MASK;
|
||||
|
||||
switch (val) {
|
||||
case METAL_MTVEC_CLIC:
|
||||
return METAL_SELECTIVE_VECTOR_MODE;
|
||||
case METAL_MTVEC_CLIC_VECTORED:
|
||||
return METAL_HARDWARE_VECTOR_MODE;
|
||||
case METAL_MTVEC_VECTORED:
|
||||
return METAL_VECTOR_MODE;
|
||||
}
|
||||
return METAL_DIRECT_MODE;
|
||||
}
|
||||
|
||||
void __metal_controller_interrupt_vector (metal_vector_mode mode, void *vec_table)
|
||||
{
|
||||
uintptr_t trap_entry, val;
|
||||
|
||||
asm volatile ("csrr %0, mtvec" : "=r"(val));
|
||||
__asm__ volatile ("csrr %0, mtvec" : "=r"(val));
|
||||
val &= ~(METAL_MTVEC_CLIC_VECTORED | METAL_MTVEC_CLIC_RESERVED);
|
||||
trap_entry = (uintptr_t)vec_table;
|
||||
|
||||
switch (mode) {
|
||||
case METAL_SELECTIVE_NONVECTOR_MODE:
|
||||
case METAL_SELECTIVE_VECTOR_MODE:
|
||||
asm volatile ("csrw mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC));
|
||||
asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
|
||||
__asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
|
||||
__asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC));
|
||||
break;
|
||||
case METAL_HARDWARE_VECTOR_MODE:
|
||||
asm volatile ("csrw mtvt, %0" :: "r"(trap_entry | METAL_MTVEC_CLIC_VECTORED));
|
||||
asm volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
|
||||
__asm__ volatile ("csrw 0x307, %0" :: "r"(trap_entry));
|
||||
__asm__ volatile ("csrw mtvec, %0" :: "r"(val | METAL_MTVEC_CLIC_VECTORED));
|
||||
break;
|
||||
case METAL_VECTOR_MODE:
|
||||
asm volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED));
|
||||
__asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry | METAL_MTVEC_VECTORED));
|
||||
break;
|
||||
case METAL_DIRECT_MODE:
|
||||
asm volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
|
||||
__asm__ volatile ("csrw mtvec, %0" :: "r"(trap_entry & ~METAL_MTVEC_CLIC_VECTORED));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +561,7 @@ int __metal_local_interrupt_enable (struct metal_interrupt *controller,
|
|||
__metal_interrupt_local_disable(id);
|
||||
}
|
||||
break;
|
||||
defaut:
|
||||
default:
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
|
@ -295,25 +586,25 @@ void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt
|
|||
|
||||
if ( !intc->init_done ) {
|
||||
/* Disable and clear all interrupt sources */
|
||||
asm volatile ("csrc mie, %0" :: "r"(-1));
|
||||
asm volatile ("csrc mip, %0" :: "r"(-1));
|
||||
__asm__ volatile ("csrc mie, %0" :: "r"(-1));
|
||||
__asm__ volatile ("csrc mip, %0" :: "r"(-1));
|
||||
|
||||
/* Read the misa CSR to determine if the delegation registers exist */
|
||||
uintptr_t misa;
|
||||
asm volatile ("csrr %0, misa" : "=r" (misa));
|
||||
__asm__ volatile ("csrr %0, misa" : "=r" (misa));
|
||||
|
||||
/* The delegation CSRs exist if user mode interrupts (N extension) or
|
||||
* supervisor mode (S extension) are supported */
|
||||
if((misa & METAL_ISA_N_EXTENSIONS) || (misa & METAL_ISA_S_EXTENSIONS)) {
|
||||
/* Disable interrupt and exception delegation */
|
||||
asm volatile ("csrc mideleg, %0" :: "r"(-1));
|
||||
asm volatile ("csrc medeleg, %0" :: "r"(-1));
|
||||
__asm__ volatile ("csrc mideleg, %0" :: "r"(-1));
|
||||
__asm__ volatile ("csrc medeleg, %0" :: "r"(-1));
|
||||
}
|
||||
|
||||
/* The satp CSR exists if supervisor mode (S extension) is supported */
|
||||
if(misa & METAL_ISA_S_EXTENSIONS) {
|
||||
/* Clear the entire CSR to make sure that satp.MODE = 0 */
|
||||
asm volatile ("csrc satp, %0" :: "r"(-1));
|
||||
__asm__ volatile ("csrc satp, %0" :: "r"(-1));
|
||||
}
|
||||
|
||||
/* Default to use direct interrupt, setup sw cb table*/
|
||||
|
@ -325,12 +616,12 @@ void __metal_driver_riscv_cpu_controller_interrupt_init (struct metal_interrupt
|
|||
for (int i = 0; i < METAL_MAX_ME; i++) {
|
||||
intc->metal_exception_table[i] = __metal_default_exception_handler;
|
||||
}
|
||||
__metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler);
|
||||
asm volatile ("csrr %0, misa" : "=r"(val));
|
||||
__metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler);
|
||||
__asm__ volatile ("csrr %0, misa" : "=r"(val));
|
||||
if (val & (METAL_ISA_D_EXTENSIONS | METAL_ISA_F_EXTENSIONS | METAL_ISA_Q_EXTENSIONS)) {
|
||||
/* Floating point architecture, so turn on FP register saving*/
|
||||
asm volatile ("csrr %0, mstatus" : "=r"(val));
|
||||
asm volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT));
|
||||
__asm__ volatile ("csrr %0, mstatus" : "=r"(val));
|
||||
__asm__ volatile ("csrw mstatus, %0" :: "r"(val | METAL_MSTATUS_FS_INIT));
|
||||
}
|
||||
intc->init_done = 1;
|
||||
}
|
||||
|
@ -380,7 +671,7 @@ int __metal_driver_riscv_cpu_controller_interrupt_register(struct metal_interrup
|
|||
intc->metal_int_table[id].handler = __metal_default_interrupt_handler;
|
||||
intc->metal_int_table[id].sub_int = priv;
|
||||
break;
|
||||
defaut:
|
||||
default:
|
||||
rc = -12;
|
||||
}
|
||||
}
|
||||
|
@ -406,11 +697,11 @@ int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_int
|
|||
|
||||
if (id == METAL_INTERRUPT_ID_BASE) {
|
||||
if (mode == METAL_DIRECT_MODE) {
|
||||
__metal_controller_interrupt_vector(mode, &__metal_exception_handler);
|
||||
__metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
|
||||
return 0;
|
||||
}
|
||||
if (mode == METAL_VECTOR_MODE) {
|
||||
__metal_controller_interrupt_vector(mode, &intc->metal_mtvec_table);
|
||||
__metal_controller_interrupt_vector(mode, (void *)&intc->metal_mtvec_table);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -420,10 +711,30 @@ int __metal_driver_riscv_cpu_controller_interrupt_enable_vector(struct metal_int
|
|||
int __metal_driver_riscv_cpu_controller_interrupt_disable_vector(struct metal_interrupt *controller,
|
||||
int id)
|
||||
{
|
||||
struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
|
||||
|
||||
if (id == METAL_INTERRUPT_ID_BASE) {
|
||||
__metal_controller_interrupt_vector(METAL_DIRECT_MODE, &__metal_exception_handler);
|
||||
__metal_controller_interrupt_vector(METAL_DIRECT_MODE, (void *)(uintptr_t)&__metal_exception_handler);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
metal_vector_mode __metal_driver_riscv_cpu_controller_get_vector_mode (struct metal_interrupt *controller)
|
||||
{
|
||||
return __metal_controller_interrupt_vector_mode();
|
||||
}
|
||||
|
||||
int __metal_driver_riscv_cpu_controller_set_vector_mode (struct metal_interrupt *controller,
|
||||
metal_vector_mode mode)
|
||||
{
|
||||
struct __metal_driver_riscv_cpu_intc *intc = (void *)(controller);
|
||||
( void ) intc;
|
||||
|
||||
if (mode == METAL_DIRECT_MODE) {
|
||||
__metal_controller_interrupt_vector(mode, (void *)(uintptr_t)&__metal_exception_handler);
|
||||
return 0;
|
||||
}
|
||||
if (mode == METAL_VECTOR_MODE) {
|
||||
__metal_controller_interrupt_vector(mode, (void *)__metal_vector_table);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
|
@ -436,25 +747,23 @@ int __metal_driver_riscv_cpu_controller_command_request (struct metal_interrupt
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern inline int __metal_controller_interrupt_is_selective_vectored(void);
|
||||
|
||||
/* CPU driver !!! */
|
||||
|
||||
unsigned long long __metal_driver_cpu_timer_get(struct metal_cpu *cpu)
|
||||
unsigned long long __metal_driver_cpu_mcycle_get(struct metal_cpu *cpu)
|
||||
{
|
||||
unsigned long long val = 0;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
unsigned long hi, hi1, lo;
|
||||
|
||||
asm volatile ("csrr %0, mcycleh" : "=r"(hi));
|
||||
asm volatile ("csrr %0, mcycle" : "=r"(lo));
|
||||
asm volatile ("csrr %0, mcycleh" : "=r"(hi1));
|
||||
__asm__ volatile ("csrr %0, mcycleh" : "=r"(hi));
|
||||
__asm__ volatile ("csrr %0, mcycle" : "=r"(lo));
|
||||
__asm__ volatile ("csrr %0, mcycleh" : "=r"(hi1));
|
||||
if (hi == hi1) {
|
||||
val = ((unsigned long long)hi << 32) | lo;
|
||||
}
|
||||
#else
|
||||
asm volatile ("csrr %0, mcycle" : "=r"(val));
|
||||
__asm__ volatile ("csrr %0, mcycle" : "=r"(val));
|
||||
#endif
|
||||
|
||||
return val;
|
||||
|
@ -477,7 +786,6 @@ unsigned long long __metal_driver_cpu_mtime_get (struct metal_cpu *cpu)
|
|||
struct metal_interrupt *tmr_intc;
|
||||
struct __metal_driver_riscv_cpu_intc *intc =
|
||||
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
|
||||
struct __metal_driver_cpu *_cpu = (void *)cpu;
|
||||
|
||||
if (intc) {
|
||||
tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
|
||||
|
@ -495,7 +803,6 @@ int __metal_driver_cpu_mtimecmp_set (struct metal_cpu *cpu, unsigned long long t
|
|||
struct metal_interrupt *tmr_intc;
|
||||
struct __metal_driver_riscv_cpu_intc *intc =
|
||||
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
|
||||
struct __metal_driver_cpu *_cpu = (void *)cpu;
|
||||
|
||||
if (intc) {
|
||||
tmr_intc = intc->metal_int_table[METAL_INTERRUPT_ID_TMR].sub_int;
|
||||
|
@ -517,7 +824,7 @@ __metal_driver_cpu_timer_controller_interrupt(struct metal_cpu *cpu)
|
|||
#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
|
||||
return __METAL_DT_SIFIVE_CLIC0_HANDLE;
|
||||
#else
|
||||
#warning "There is no interrupt controller for Timer interrupt"
|
||||
#pragma message("There is no interrupt controller for Timer interrupt")
|
||||
return NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -537,7 +844,7 @@ __metal_driver_cpu_sw_controller_interrupt(struct metal_cpu *cpu)
|
|||
#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
|
||||
return __METAL_DT_SIFIVE_CLIC0_HANDLE;
|
||||
#else
|
||||
#warning "There is no interrupt controller for Software interrupt"
|
||||
#pragma message("There is no interrupt controller for Software interrupt")
|
||||
return NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -554,7 +861,6 @@ int __metal_driver_cpu_set_sw_ipi (struct metal_cpu *cpu, int hartid)
|
|||
struct metal_interrupt *sw_intc;
|
||||
struct __metal_driver_riscv_cpu_intc *intc =
|
||||
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
|
||||
struct __metal_driver_cpu *_cpu = (void *)cpu;
|
||||
|
||||
if (intc) {
|
||||
sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
|
||||
|
@ -572,7 +878,6 @@ int __metal_driver_cpu_clear_sw_ipi (struct metal_cpu *cpu, int hartid)
|
|||
struct metal_interrupt *sw_intc;
|
||||
struct __metal_driver_riscv_cpu_intc *intc =
|
||||
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
|
||||
struct __metal_driver_cpu *_cpu = (void *)cpu;
|
||||
|
||||
if (intc) {
|
||||
sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
|
||||
|
@ -590,7 +895,6 @@ int __metal_driver_cpu_get_msip (struct metal_cpu *cpu, int hartid)
|
|||
struct metal_interrupt *sw_intc;
|
||||
struct __metal_driver_riscv_cpu_intc *intc =
|
||||
(struct __metal_driver_riscv_cpu_intc *)__metal_driver_cpu_interrupt_controller(cpu);
|
||||
struct __metal_driver_cpu *_cpu = (void *)cpu;
|
||||
|
||||
if (intc) {
|
||||
sw_intc = intc->metal_int_table[METAL_INTERRUPT_ID_SW].sub_int;
|
||||
|
@ -642,35 +946,40 @@ int __metal_driver_cpu_exception_register(struct metal_cpu *cpu, int ecode,
|
|||
|
||||
int __metal_driver_cpu_get_instruction_length(struct metal_cpu *cpu, uintptr_t epc)
|
||||
{
|
||||
/* Per ISA compressed instruction has last two bits of opcode set */
|
||||
return (*(unsigned short*)epc & 3) ? 4 : 2;
|
||||
/**
|
||||
* Per ISA compressed instruction has last two bits of opcode set.
|
||||
* The encoding '00' '01' '10' are used for compressed instruction.
|
||||
* Only enconding '11' isn't regarded as compressed instruction (>16b).
|
||||
*/
|
||||
return ((*(unsigned short*)epc & METAL_INSN_LENGTH_MASK)
|
||||
== METAL_INSN_NOT_COMPRESSED) ? 4 : 2;
|
||||
}
|
||||
|
||||
uintptr_t __metal_driver_cpu_get_exception_pc(struct metal_cpu *cpu)
|
||||
{
|
||||
uintptr_t mepc;
|
||||
asm volatile ("csrr %0, mepc" : "=r"(mepc));
|
||||
__asm__ volatile ("csrr %0, mepc" : "=r"(mepc));
|
||||
return mepc;
|
||||
}
|
||||
|
||||
int __metal_driver_cpu_set_exception_pc(struct metal_cpu *cpu, uintptr_t mepc)
|
||||
{
|
||||
asm volatile ("csrw mepc, %0" :: "r"(mepc));
|
||||
__asm__ volatile ("csrw mepc, %0" :: "r"(mepc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_cpu_intc) = {
|
||||
.controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
|
||||
.controller_vtable.interrupt_init = __metal_driver_riscv_cpu_controller_interrupt_init,
|
||||
.controller_vtable.interrupt_register = __metal_driver_riscv_cpu_controller_interrupt_register,
|
||||
.controller_vtable.interrupt_enable = __metal_driver_riscv_cpu_controller_interrupt_enable,
|
||||
.controller_vtable.interrupt_disable = __metal_driver_riscv_cpu_controller_interrupt_disable,
|
||||
.controller_vtable.interrupt_vector_enable = __metal_driver_riscv_cpu_controller_interrupt_enable_vector,
|
||||
.controller_vtable.interrupt_vector_disable = __metal_driver_riscv_cpu_controller_interrupt_disable_vector,
|
||||
.controller_vtable.interrupt_get_vector_mode = __metal_driver_riscv_cpu_controller_get_vector_mode,
|
||||
.controller_vtable.interrupt_set_vector_mode = __metal_driver_riscv_cpu_controller_set_vector_mode,
|
||||
.controller_vtable.command_request = __metal_driver_riscv_cpu_controller_command_request,
|
||||
};
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_cpu) = {
|
||||
.cpu_vtable.timer_get = __metal_driver_cpu_timer_get,
|
||||
.cpu_vtable.mcycle_get = __metal_driver_cpu_mcycle_get,
|
||||
.cpu_vtable.timebase_get = __metal_driver_cpu_timebase_get,
|
||||
.cpu_vtable.mtime_get = __metal_driver_cpu_mtime_get,
|
||||
.cpu_vtable.mtimecmp_set = __metal_driver_cpu_mtimecmp_set,
|
||||
|
|
|
@ -25,30 +25,47 @@ void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic,
|
|||
METAL_RISCV_PLIC0_CLAIM)) = id;
|
||||
}
|
||||
|
||||
void __metal_plic0_set_threshold(struct __metal_driver_riscv_plic0 *plic,
|
||||
unsigned int threshold)
|
||||
int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_THRESHOLD)) = threshold;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __metal_plic0_set_priority(struct __metal_driver_riscv_plic0 *plic,
|
||||
int id, unsigned int priority)
|
||||
unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
|
||||
int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)plic);
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
|
||||
|
||||
return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_THRESHOLD));
|
||||
}
|
||||
|
||||
int __metal_plic0_set_priority(struct metal_interrupt *controller, int id, unsigned int priority)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)controller);
|
||||
unsigned int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)controller);
|
||||
if ( (max_priority) && (priority < max_priority) ) {
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_PRIORITY_BASE +
|
||||
(id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int __metal_plic0_get_priority(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
|
||||
|
||||
return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
METAL_RISCV_PLIC0_PRIORITY_BASE +
|
||||
(id << METAL_PLIC_SOURCE_PRIORITY_SHIFT)));
|
||||
}
|
||||
|
||||
void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable)
|
||||
{
|
||||
unsigned int current;
|
||||
unsigned long hartid = __metal_myhart_id();
|
||||
unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
|
||||
|
||||
current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
|
||||
|
@ -69,7 +86,7 @@ void __metal_plic0_handler (int id, void *priv)
|
|||
{
|
||||
struct __metal_driver_riscv_plic0 *plic = priv;
|
||||
unsigned int idx = __metal_plic0_claim_interrupt(plic);
|
||||
int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic);
|
||||
unsigned int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic);
|
||||
|
||||
if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) {
|
||||
plic->metal_exint_table[idx](idx,
|
||||
|
@ -97,13 +114,13 @@ void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
|
|||
|
||||
for (int i = 0; i < num_interrupts; i++) {
|
||||
__metal_plic0_enable(plic, i, METAL_DISABLE);
|
||||
__metal_plic0_set_priority(plic, i, 0);
|
||||
__metal_plic0_set_priority(controller, i, 0);
|
||||
plic->metal_exint_table[i] = NULL;
|
||||
plic->metal_exdata_table[i].sub_int = NULL;
|
||||
plic->metal_exdata_table[i].exint_data = NULL;
|
||||
}
|
||||
|
||||
__metal_plic0_set_threshold(plic, 0);
|
||||
__metal_plic0_set_threshold(controller, 0);
|
||||
|
||||
/* Register plic (ext) interrupt with with parent controller */
|
||||
intc->vtable->interrupt_register(intc, line, NULL, plic);
|
||||
|
@ -127,11 +144,11 @@ int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
|
|||
}
|
||||
|
||||
if (isr) {
|
||||
__metal_plic0_set_priority(plic ,id, 2);
|
||||
__metal_plic0_set_priority(controller, id, 2);
|
||||
plic->metal_exint_table[id] = isr;
|
||||
plic->metal_exdata_table[id].exint_data = priv;
|
||||
} else {
|
||||
__metal_plic0_set_priority(plic, id, 1);
|
||||
__metal_plic0_set_priority(controller, id, 1);
|
||||
plic->metal_exint_table[id] = __metal_plic0_default_handler;
|
||||
plic->metal_exdata_table[id].sub_int = priv;
|
||||
}
|
||||
|
@ -167,6 +184,12 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
|
|||
.plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register,
|
||||
.plic_vtable.interrupt_enable = __metal_driver_riscv_plic0_enable,
|
||||
.plic_vtable.interrupt_disable = __metal_driver_riscv_plic0_disable,
|
||||
.plic_vtable.interrupt_get_threshold = __metal_plic0_get_threshold,
|
||||
.plic_vtable.interrupt_set_threshold = __metal_plic0_set_threshold,
|
||||
.plic_vtable.interrupt_get_priority = __metal_plic0_get_priority,
|
||||
.plic_vtable.interrupt_set_priority = __metal_plic0_set_priority,
|
||||
};
|
||||
|
||||
#endif /* METAL_RISCV_PLIC0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_CCACHE0
|
||||
|
||||
#include <stdint.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/drivers/sifive_ccache0.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
#define L2_CONFIG_WAYS_SHIFT 8
|
||||
#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT)
|
||||
|
||||
void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways);
|
||||
|
||||
static void metal_driver_sifive_ccache0_init(void) __attribute__((constructor));
|
||||
static void metal_driver_sifive_ccache0_init(void)
|
||||
{
|
||||
#ifdef __METAL_DT_SIFIVE_CCACHE0_HANDLE
|
||||
/* Get the handle for the L2 cache controller */
|
||||
struct metal_cache *l2 = __METAL_DT_SIFIVE_CCACHE0_HANDLE;
|
||||
if(!l2) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the number of available ways per bank */
|
||||
unsigned long control_base = __metal_driver_sifive_ccache0_control_base(l2);
|
||||
uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_CONFIG));
|
||||
ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT);
|
||||
|
||||
/* Enable all the ways */
|
||||
__metal_driver_sifive_ccache0_init(l2, ways);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways)
|
||||
{
|
||||
metal_cache_set_enabled_ways(l2, ways);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_ccache0_get_enabled_ways(struct metal_cache *cache)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache);
|
||||
|
||||
uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE));
|
||||
|
||||
/* The stored number is the index, so add one */
|
||||
return (0xFF & way_enable) + 1;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_ccache0_set_enabled_ways(struct metal_cache *cache, int ways)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_ccache0_control_base(cache);
|
||||
|
||||
/* We can't decrease the number of enabled ways */
|
||||
if(metal_cache_get_enabled_ways(cache) > ways) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* The stored value is the index, so subtract one */
|
||||
uint32_t value = 0xFF & (ways - 1);
|
||||
|
||||
/* Set the number of enabled ways */
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)) = value;
|
||||
|
||||
/* Make sure the number of ways was set correctly */
|
||||
if(metal_cache_get_enabled_ways(cache) != ways) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_ccache0) = {
|
||||
.cache.init = __metal_driver_sifive_ccache0_init,
|
||||
.cache.get_enabled_ways = __metal_driver_sifive_ccache0_get_enabled_ways,
|
||||
.cache.set_enabled_ways = __metal_driver_sifive_ccache0_set_enabled_ways,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
|
@ -11,12 +11,6 @@
|
|||
#include <metal/drivers/sifive_clic0.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
typedef enum metal_priv_mode_ {
|
||||
METAL_PRIV_M_MODE = 0,
|
||||
METAL_PRIV_MU_MODE = 1,
|
||||
METAL_PRIV_MSU_MODE = 2
|
||||
} metal_priv_mode;
|
||||
|
||||
typedef enum metal_clic_vector_{
|
||||
METAL_CLIC_NONVECTOR = 0,
|
||||
METAL_CLIC_VECTORED = 1
|
||||
|
@ -30,17 +24,20 @@ struct __metal_clic_cfg {
|
|||
};
|
||||
|
||||
const struct __metal_clic_cfg __metal_clic_defaultcfg = {
|
||||
.nmbits = METAL_PRIV_M_MODE,
|
||||
.nmbits = METAL_INTR_PRIV_M_MODE,
|
||||
.nlbits = 0,
|
||||
.nvbit = METAL_CLIC_NONVECTOR
|
||||
};
|
||||
|
||||
void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
|
||||
|
||||
void __metal_clic0_default_vector_handler (void) __attribute__((interrupt, aligned(64)));
|
||||
|
||||
struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic,
|
||||
struct __metal_clic_cfg *cfg)
|
||||
{
|
||||
volatile unsigned char val;
|
||||
struct __metal_clic_cfg cliccfg;
|
||||
uintptr_t hartid = __metal_myhart_id();
|
||||
unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
|
||||
|
||||
if ( cfg ) {
|
||||
|
@ -80,7 +77,7 @@ int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, int level)
|
||||
int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, unsigned int level)
|
||||
{
|
||||
uint8_t mask, nmmask, nlmask, val;
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
|
@ -102,7 +99,7 @@ int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
|
||||
unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
|
||||
{
|
||||
int level;
|
||||
uint8_t mask, val, freebits, nlbits;
|
||||
|
@ -185,7 +182,7 @@ int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *cl
|
|||
return priority;
|
||||
}
|
||||
|
||||
int __metal_clic0_interrupt_set_vector (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
|
||||
int __metal_clic0_interrupt_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
|
||||
{
|
||||
uint8_t mask, val;
|
||||
unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
|
||||
|
@ -272,36 +269,102 @@ int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic
|
|||
|
||||
int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
|
||||
int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
|
||||
|
||||
if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
|
||||
if (id < num_subinterrupts) {
|
||||
__METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
|
||||
METAL_SIFIVE_CLIC0_MMODE_APERTURE +
|
||||
METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_ENABLE;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id)
|
||||
{
|
||||
unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
|
||||
int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
|
||||
|
||||
if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
|
||||
if (id < num_subinterrupts) {
|
||||
__METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
|
||||
METAL_SIFIVE_CLIC0_MMODE_APERTURE +
|
||||
METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_DISABLE;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __metal_clic0_configure_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, metal_vector_mode mode)
|
||||
{
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
|
||||
switch (mode) {
|
||||
case METAL_SELECTIVE_NONVECTOR_MODE:
|
||||
cfg.nvbit = METAL_CLIC_NONVECTOR;
|
||||
__metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
|
||||
break;
|
||||
case METAL_SELECTIVE_VECTOR_MODE:
|
||||
cfg.nvbit = METAL_CLIC_VECTORED;
|
||||
__metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
|
||||
break;
|
||||
case METAL_HARDWARE_VECTOR_MODE:
|
||||
cfg.nvbit = METAL_CLIC_VECTORED;
|
||||
__metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
__metal_clic0_configuration(clic, &cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __metal_clic0_configure_privilege (struct __metal_driver_sifive_clic0 *clic, metal_priv_mode priv)
|
||||
metal_vector_mode __metal_clic0_configure_get_vector_mode (struct __metal_driver_sifive_clic0 *clic)
|
||||
{
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
|
||||
|
||||
if (mode == METAL_SELECTIVE_VECTOR_MODE) {
|
||||
if (cfg.nvbit) {
|
||||
return METAL_SELECTIVE_VECTOR_MODE;
|
||||
} else {
|
||||
return METAL_SELECTIVE_NONVECTOR_MODE;
|
||||
}
|
||||
} else {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
int __metal_clic0_configure_set_privilege (struct __metal_driver_sifive_clic0 *clic, metal_intr_priv_mode priv)
|
||||
{
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
|
||||
cfg.nmbits = priv;
|
||||
__metal_clic0_configuration(clic, &cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __metal_clic0_configure_level (struct __metal_driver_sifive_clic0 *clic, int level)
|
||||
metal_intr_priv_mode __metal_clic0_configure_get_privilege (struct __metal_driver_sifive_clic0 *clic)
|
||||
{
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
|
||||
cfg.nlbits = level;
|
||||
return cfg.nmbits;
|
||||
}
|
||||
|
||||
int __metal_clic0_configure_set_level (struct __metal_driver_sifive_clic0 *clic, int level)
|
||||
{
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
|
||||
cfg.nlbits = level & 0xF;
|
||||
__metal_clic0_configuration(clic, &cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_clic0_configure_get_level (struct __metal_driver_sifive_clic0 *clic)
|
||||
{
|
||||
struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
|
||||
|
||||
return cfg.nlbits;
|
||||
}
|
||||
|
||||
unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic)
|
||||
|
@ -338,16 +401,13 @@ int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
|
||||
void __metal_clic0_handler (int id, void *priv)
|
||||
{
|
||||
int idx;
|
||||
struct __metal_driver_sifive_clic0 *clic = priv;
|
||||
int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
|
||||
|
||||
idx = id - METAL_INTERRUPT_ID_LC0;
|
||||
if ( (idx < num_subinterrupts) && (clic->metal_mtvt_table[idx]) ) {
|
||||
clic->metal_mtvt_table[idx](id, clic->metal_exint_table[idx].exint_data);
|
||||
if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) {
|
||||
clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,6 +415,10 @@ void __metal_clic0_default_handler (int id, void *priv) {
|
|||
metal_shutdown(300);
|
||||
}
|
||||
|
||||
void __metal_clic0_default_vector_handler (void) {
|
||||
metal_shutdown(400);
|
||||
}
|
||||
|
||||
void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
|
@ -368,8 +432,8 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
|
|||
|
||||
/* Initialize ist parent controller, aka cpu_intc. */
|
||||
intc->vtable->interrupt_init(intc);
|
||||
__metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE,
|
||||
&__metal_clic0_handler);
|
||||
__metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE,
|
||||
&clic->metal_mtvt_table);
|
||||
|
||||
/*
|
||||
* Register its interrupts with with parent controller,
|
||||
|
@ -389,8 +453,10 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
|
|||
|
||||
level = (1 << cfg.nlbits) - 1;
|
||||
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
for (int i = 0; i < num_subinterrupts; i++) {
|
||||
clic->metal_mtvt_table[0] = &__metal_clic0_handler;
|
||||
for (int i = 1; i < num_subinterrupts; i++) {
|
||||
clic->metal_mtvt_table[i] = NULL;
|
||||
clic->metal_exint_table[i].handler = NULL;
|
||||
clic->metal_exint_table[i].sub_int = NULL;
|
||||
clic->metal_exint_table[i].exint_data = NULL;
|
||||
__metal_clic0_interrupt_disable(clic, i);
|
||||
|
@ -403,31 +469,71 @@ void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
|
|||
int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller,
|
||||
int id, metal_interrupt_handler_t isr,
|
||||
void *priv)
|
||||
{
|
||||
{
|
||||
int rc = -1;
|
||||
int num_subinterrupts;
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
struct metal_interrupt *intc =
|
||||
__metal_driver_sifive_clic0_interrupt_parent(controller);
|
||||
|
||||
/* Register its interrupts with parent controller */
|
||||
if ( id < METAL_INTERRUPT_ID_LC0) {
|
||||
return intc->vtable->interrupt_register(intc, id, isr, priv);
|
||||
metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
|
||||
|
||||
if ( ( (mode == METAL_SELECTIVE_VECTOR_MODE) &&
|
||||
(__metal_clic0_interrupt_is_vectored(clic, id)) ) ||
|
||||
(mode == METAL_HARDWARE_VECTOR_MODE) ||
|
||||
(mode == METAL_VECTOR_MODE) ||
|
||||
(mode == METAL_DIRECT_MODE) ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
/* Register its interrupts with parent controller */
|
||||
if (id < METAL_INTERRUPT_ID_CSW) {
|
||||
return intc->vtable->interrupt_register(intc, id, isr, priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0
|
||||
* Reset the IDs to reflects this.
|
||||
* Reset the IDs to reflects this.
|
||||
*/
|
||||
id -= METAL_INTERRUPT_ID_LC0;
|
||||
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
if (id < num_subinterrupts) {
|
||||
if ( isr) {
|
||||
clic->metal_exint_table[id].handler = isr;
|
||||
clic->metal_exint_table[id].exint_data = priv;
|
||||
} else {
|
||||
clic->metal_exint_table[id].handler = __metal_clic0_default_handler;
|
||||
clic->metal_exint_table[id].sub_int = priv;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_vector_register (struct metal_interrupt *controller,
|
||||
int id, metal_interrupt_vector_handler_t isr,
|
||||
void *priv)
|
||||
{
|
||||
int rc = -1;
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
struct metal_interrupt *intc =
|
||||
__metal_driver_sifive_clic0_interrupt_parent(controller);
|
||||
int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
|
||||
|
||||
if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
|
||||
return rc;
|
||||
}
|
||||
if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
|
||||
(__metal_clic0_interrupt_is_vectored(clic, id) == 0) ) {
|
||||
return rc;
|
||||
}
|
||||
if (id < num_subinterrupts) {
|
||||
if ( isr) {
|
||||
clic->metal_mtvt_table[id] = isr;
|
||||
clic->metal_exint_table[id].exint_data = priv;
|
||||
} else {
|
||||
clic->metal_mtvt_table[id] = __metal_clic0_default_handler;
|
||||
clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler;
|
||||
clic->metal_exint_table[id].sub_int = priv;
|
||||
}
|
||||
rc = 0;
|
||||
|
@ -449,31 +555,20 @@ int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int
|
|||
return __metal_clic0_interrupt_disable(clic, id);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller,
|
||||
int id, metal_vector_mode mode)
|
||||
int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
int num_subinterrupts;
|
||||
int rc = -1;
|
||||
int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
|
||||
|
||||
if (id == METAL_INTERRUPT_ID_BASE) {
|
||||
if (mode == METAL_SELECTIVE_VECTOR_MODE) {
|
||||
__metal_controller_interrupt_vector(mode, &__metal_clic0_handler);
|
||||
return 0;
|
||||
}
|
||||
if (mode == METAL_HARDWARE_VECTOR_MODE) {
|
||||
__metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
|
||||
return 0;
|
||||
}
|
||||
if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
|
||||
return rc;
|
||||
}
|
||||
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
|
||||
if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
|
||||
__metal_controller_interrupt_is_selective_vectored()) {
|
||||
__metal_clic0_interrupt_set_vector(clic, id, METAL_ENABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id < num_subinterrupts) {
|
||||
__metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -484,20 +579,84 @@ int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt
|
|||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
|
||||
if (id == METAL_INTERRUPT_ID_BASE) {
|
||||
__metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE, &__metal_clic0_handler);
|
||||
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
if (id < num_subinterrupts) {
|
||||
__metal_clic0_interrupt_set_vector_mode(clic, id, METAL_DISABLE);
|
||||
return 0;
|
||||
}
|
||||
num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
|
||||
if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
|
||||
if (__metal_controller_interrupt_is_selective_vectored()) {
|
||||
__metal_clic0_interrupt_set_vector(clic, id, METAL_DISABLE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
metal_vector_mode __metal_driver_sifive_clic0_get_vector_mode (struct metal_interrupt *controller)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_configure_get_vector_mode(clic);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_configure_set_vector_mode(clic, mode);
|
||||
}
|
||||
|
||||
metal_intr_priv_mode __metal_driver_sifive_clic0_get_privilege (struct metal_interrupt *controller)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_configure_get_privilege(clic);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_set_privilege (struct metal_interrupt *controller, metal_intr_priv_mode priv)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_configure_set_privilege(clic, priv);
|
||||
}
|
||||
|
||||
unsigned int __metal_driver_sifive_clic0_get_threshold (struct metal_interrupt *controller)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_configure_get_level(clic);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_set_threshold (struct metal_interrupt *controller, unsigned int level)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_configure_set_level(clic, level);
|
||||
}
|
||||
|
||||
unsigned int __metal_driver_sifive_clic0_get_priority (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_interrupt_get_priority(clic, id);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_set_priority (struct metal_interrupt *controller, int id, unsigned int priority)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_interrupt_set_priority(clic, id, priority);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_clear_interrupt (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_interrupt_clear(clic, id);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_set_interrupt (struct metal_interrupt *controller, int id)
|
||||
{
|
||||
struct __metal_driver_sifive_clic0 *clic =
|
||||
(struct __metal_driver_sifive_clic0 *)(controller);
|
||||
return __metal_clic0_interrupt_set(clic, id);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller,
|
||||
int command, void *data)
|
||||
{
|
||||
|
@ -553,12 +712,25 @@ int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *control
|
|||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = {
|
||||
.clic_vtable.interrupt_init = __metal_driver_sifive_clic0_init,
|
||||
.clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register,
|
||||
.clic_vtable.interrupt_vector_register = __metal_driver_sifive_clic0_vector_register,
|
||||
.clic_vtable.interrupt_enable = __metal_driver_sifive_clic0_enable,
|
||||
.clic_vtable.interrupt_disable = __metal_driver_sifive_clic0_disable,
|
||||
.clic_vtable.interrupt_vector_enable = __metal_driver_sifive_clic0_enable_interrupt_vector,
|
||||
.clic_vtable.interrupt_vector_disable = __metal_driver_sifive_clic0_disable_interrupt_vector,
|
||||
.clic_vtable.interrupt_get_vector_mode = __metal_driver_sifive_clic0_get_vector_mode,
|
||||
.clic_vtable.interrupt_set_vector_mode = __metal_driver_sifive_clic0_set_vector_mode,
|
||||
.clic_vtable.interrupt_get_privilege = __metal_driver_sifive_clic0_get_privilege,
|
||||
.clic_vtable.interrupt_set_privilege = __metal_driver_sifive_clic0_set_privilege,
|
||||
.clic_vtable.interrupt_get_threshold = __metal_driver_sifive_clic0_get_threshold,
|
||||
.clic_vtable.interrupt_set_threshold = __metal_driver_sifive_clic0_set_threshold,
|
||||
.clic_vtable.interrupt_get_priority = __metal_driver_sifive_clic0_get_priority,
|
||||
.clic_vtable.interrupt_set_priority = __metal_driver_sifive_clic0_set_priority,
|
||||
.clic_vtable.interrupt_clear = __metal_driver_sifive_clic0_clear_interrupt,
|
||||
.clic_vtable.interrupt_set = __metal_driver_sifive_clic0_set_interrupt,
|
||||
.clic_vtable.command_request = __metal_driver_sifive_clic0_command_request,
|
||||
.clic_vtable.mtimecmp_set = __metal_driver_sifive_clic0_mtimecmp_set,
|
||||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_CLIC0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -23,9 +23,9 @@ long __metal_driver_sifive_fe310_g000_hfrosc_get_rate_hz(const struct metal_cloc
|
|||
__metal_driver_sifive_fe310_g000_prci_vtable();
|
||||
long cfg = vtable->get_reg(config_base, config_offset);
|
||||
|
||||
if (cfg & CONFIG_ENABLE == 0)
|
||||
if ((cfg & CONFIG_ENABLE) == 0)
|
||||
return -1;
|
||||
if (cfg & CONFIG_READY == 0)
|
||||
if ((cfg & CONFIG_READY) == 0)
|
||||
return -1;
|
||||
return metal_clock_get_rate_hz(ref) / ((cfg & CONFIG_DIVIDER) + 1);
|
||||
}
|
||||
|
@ -40,3 +40,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfrosc) = {
|
|||
.clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_hfrosc_set_rate_hz,
|
||||
};
|
||||
#endif /* METAL_SIFIVE_FE310_G000_HFROSC */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -21,9 +21,9 @@ long __metal_driver_sifive_fe310_g000_hfxosc_get_rate_hz(const struct metal_cloc
|
|||
__metal_driver_sifive_fe310_g000_prci_vtable();
|
||||
long cfg = vtable->get_reg(config_base, config_offset);
|
||||
|
||||
if (cfg & CONFIG_ENABLE == 0)
|
||||
if ((cfg & CONFIG_ENABLE) == 0)
|
||||
return -1;
|
||||
if (cfg & CONFIG_READY == 0)
|
||||
if ((cfg & CONFIG_READY) == 0)
|
||||
return -1;
|
||||
return metal_clock_get_rate_hz(ref);
|
||||
}
|
||||
|
@ -39,3 +39,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_hfxosc) = {
|
|||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_FE310_G000_HFXOSC */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_FE310_G000_LFROSC
|
||||
|
||||
#include <metal/drivers/sifive_fe310-g000_lfrosc.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
/* LFROSCCFG */
|
||||
#define METAL_LFROSCCFG_DIV_MASK 0x3F
|
||||
#define METAL_LFROSCCFG_TRIM_SHIFT 16
|
||||
#define METAL_LFROSCCFG_TRIM_MASK (0x1F << METAL_LFROSCCFG_TRIM_SHIFT)
|
||||
#define METAL_LFROSCCFG_EN (1 << 30)
|
||||
#define METAL_LFROSCCFG_RDY (1 << 31)
|
||||
|
||||
/* LFCLKMUX */
|
||||
#define METAL_LFCLKMUX_SEL 1
|
||||
#define METAL_LFCLKMUX_EXT_MUX_STATUS (1 << 31)
|
||||
|
||||
#define LFROSC_REGW(addr) (__METAL_ACCESS_ONCE((__metal_io_u32 *)addr))
|
||||
|
||||
long __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(const struct metal_clock *clock)
|
||||
{
|
||||
struct metal_clock *internal_ref = __metal_driver_sifive_fe310_g000_lfrosc_lfrosc(clock);
|
||||
struct metal_clock *external_ref = __metal_driver_sifive_fe310_g000_lfrosc_psdlfaltclk(clock);
|
||||
|
||||
unsigned long int cfg_reg = __metal_driver_sifive_fe310_g000_lfrosc_config_reg(clock);
|
||||
unsigned long int mux_reg = __metal_driver_sifive_fe310_g000_lfrosc_mux_reg(clock);
|
||||
|
||||
if(LFROSC_REGW(mux_reg) & METAL_LFCLKMUX_EXT_MUX_STATUS) {
|
||||
return metal_clock_get_rate_hz(external_ref);
|
||||
}
|
||||
|
||||
const unsigned long int div = (LFROSC_REGW(cfg_reg) & METAL_LFROSCCFG_DIV_MASK) + 1;
|
||||
|
||||
return metal_clock_get_rate_hz(internal_ref) / div;
|
||||
}
|
||||
|
||||
long __metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz(struct metal_clock *clock, long rate)
|
||||
{
|
||||
return __metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz(clock);
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_lfrosc) = {
|
||||
.clock.get_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_get_rate_hz,
|
||||
.clock.set_rate_hz = &__metal_driver_sifive_fe310_g000_lfrosc_set_rate_hz,
|
||||
};
|
||||
#endif /* METAL_SIFIVE_FE310_G000_LFROSC */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
@ -133,7 +133,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31
|
|||
* Returns:
|
||||
* - PLL_CONFIG_NOT_VALID if the configuration is not valid for the input frequency
|
||||
* - the output frequency, in hertz */
|
||||
static long get_pll_config_freq(long pll_input_rate, const struct pll_config_t *config)
|
||||
static long get_pll_config_freq(unsigned long pll_input_rate, const struct pll_config_t *config)
|
||||
{
|
||||
if(pll_input_rate < config->min_input_rate || pll_input_rate > config->max_input_rate)
|
||||
return PLL_CONFIG_NOT_VALID;
|
||||
|
@ -162,8 +162,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31
|
|||
__metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
|
||||
|
||||
/* If the PLL clock has had a _pre_rate_change_callback configured, call it */
|
||||
if(pll->clock._pre_rate_change_callback != NULL)
|
||||
pll->clock._pre_rate_change_callback(pll->clock._pre_rate_change_callback_priv);
|
||||
_metal_clock_call_all_callbacks(pll->clock._pre_rate_change_callback);
|
||||
|
||||
/* If we're running off of the PLL, switch off before we start configuring it*/
|
||||
if((__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0)
|
||||
|
@ -179,8 +178,7 @@ void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe31
|
|||
pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate);
|
||||
|
||||
/* If the PLL clock has had a rate_change_callback configured, call it */
|
||||
if(pll->clock._post_rate_change_callback != NULL)
|
||||
pll->clock._post_rate_change_callback(pll->clock._post_rate_change_callback_priv);
|
||||
_metal_clock_call_all_callbacks(pll->clock._post_rate_change_callback);
|
||||
}
|
||||
|
||||
long __metal_driver_sifive_fe310_g000_pll_get_rate_hz(const struct metal_clock *clock)
|
||||
|
@ -358,3 +356,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = {
|
|||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_FE310_G000_PLL */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -24,3 +24,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_prci) = {
|
|||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_FE310_G000_PRCI */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -2,25 +2,32 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_FU540_C000_L2
|
||||
|
||||
#include <stdint.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/drivers/sifive_fu540-c000_l2.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
#define L2_CONFIG_WAYS_SHIFT 8
|
||||
#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT)
|
||||
|
||||
#ifdef CONFIG_SIFIVE_FU540_C000_L2
|
||||
void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways);
|
||||
|
||||
static void metal_driver_sifive_fu540_c000_l2_init(void) __attribute__((constructor));
|
||||
static void metal_driver_sifive_fu540_c000_l2_init(void)
|
||||
{
|
||||
#ifdef __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE
|
||||
/* Get the handle for the L2 cache controller */
|
||||
struct __metal_driver_sifive_fu540_c000_l2 *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE;
|
||||
struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE;
|
||||
if(!l2) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the number of available ways per bank */
|
||||
uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_CONFIG));
|
||||
unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(l2);
|
||||
uint32_t ways = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_CONFIG));
|
||||
ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT);
|
||||
|
||||
/* Enable all the ways */
|
||||
|
@ -35,12 +42,9 @@ void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways)
|
|||
|
||||
int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cache)
|
||||
{
|
||||
struct __metal_driver_sifive_fu540_c000_l2 *l2 = (struct __metal_driver_sifive_fu540_c000_l2 *) cache;
|
||||
if(!l2) {
|
||||
return -1;
|
||||
}
|
||||
unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
|
||||
|
||||
uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_WAYENABLE));
|
||||
uint32_t way_enable = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE));
|
||||
|
||||
/* The stored number is the index, so add one */
|
||||
return (0xFF & way_enable) + 1;
|
||||
|
@ -48,10 +52,7 @@ int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways(struct metal_cache *cac
|
|||
|
||||
int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cache, int ways)
|
||||
{
|
||||
struct __metal_driver_sifive_fu540_c000_l2 *l2 = (struct __metal_driver_sifive_fu540_c000_l2 *) cache;
|
||||
if(!l2) {
|
||||
return -1;
|
||||
}
|
||||
unsigned long control_base = __metal_driver_sifive_fu540_c000_l2_control_base(cache);
|
||||
|
||||
/* We can't decrease the number of enabled ways */
|
||||
if(metal_cache_get_enabled_ways(cache) > ways) {
|
||||
|
@ -62,7 +63,7 @@ int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways(struct metal_cache *cac
|
|||
uint32_t value = 0xFF & (ways - 1);
|
||||
|
||||
/* Set the number of enabled ways */
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(l2->control_base + SIFIVE_FU540_C000_L2_WAYENABLE)) = value;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)) = value;
|
||||
|
||||
/* Make sure the number of ways was set correctly */
|
||||
if(metal_cache_get_enabled_ways(cache) != ways) {
|
||||
|
@ -79,3 +80,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = {
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -84,6 +84,50 @@ int __metal_driver_sifive_global_external_interrupt_disable(struct metal_interru
|
|||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_global_external_interrupt_set_threshold(struct metal_interrupt *controller,
|
||||
unsigned int threshold)
|
||||
{
|
||||
struct metal_interrupt *intc =
|
||||
__metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
|
||||
if (intc) {
|
||||
return intc->vtable->interrupt_set_threshold(intc, threshold);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int __metal_driver_sifive_global_external_interrupt_get_threshold(struct metal_interrupt *controller)
|
||||
{
|
||||
struct metal_interrupt *intc =
|
||||
__metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
|
||||
|
||||
if (intc) {
|
||||
return intc->vtable->interrupt_get_threshold(intc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_global_external_interrupt_set_priority(struct metal_interrupt *controller,
|
||||
int id, unsigned int priority)
|
||||
{
|
||||
struct metal_interrupt *intc =
|
||||
__metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
|
||||
if (intc) {
|
||||
return intc->vtable->interrupt_set_priority(intc, id, priority);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int __metal_driver_sifive_global_external_interrupt_get_priority(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
struct metal_interrupt *intc =
|
||||
__metal_driver_sifive_global_external_interrupts0_interrupt_parent(controller);
|
||||
|
||||
if (intc) {
|
||||
return intc->vtable->interrupt_get_priority(intc, id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_global_external_command_request (struct metal_interrupt *controller,
|
||||
int command, void *data)
|
||||
{
|
||||
|
@ -113,8 +157,13 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_global_external_interrupts0)
|
|||
.global0_vtable.interrupt_register = __metal_driver_sifive_global_external_interrupt_register,
|
||||
.global0_vtable.interrupt_enable = __metal_driver_sifive_global_external_interrupt_enable,
|
||||
.global0_vtable.interrupt_disable = __metal_driver_sifive_global_external_interrupt_disable,
|
||||
.global0_vtable.interrupt_get_threshold = __metal_driver_sifive_global_external_interrupt_get_threshold,
|
||||
.global0_vtable.interrupt_set_threshold = __metal_driver_sifive_global_external_interrupt_set_threshold,
|
||||
.global0_vtable.interrupt_get_priority = __metal_driver_sifive_global_external_interrupt_get_priority,
|
||||
.global0_vtable.interrupt_set_priority = __metal_driver_sifive_global_external_interrupt_set_priority,
|
||||
.global0_vtable.command_request = __metal_driver_sifive_global_external_command_request,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -53,3 +53,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_button) = {
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -81,3 +81,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_led) = {
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -52,3 +52,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_switch) = {
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -9,6 +9,15 @@
|
|||
#include <metal/io.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
int __metal_driver_sifive_gpio0_enable_input(struct metal_gpio *ggpio, long source)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_INPUT_EN)) |= source;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long source)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
@ -18,6 +27,13 @@ int __metal_driver_sifive_gpio0_disable_input(struct metal_gpio *ggpio, long sou
|
|||
return 0;
|
||||
}
|
||||
|
||||
long __metal_driver_sifive_gpio0_input(struct metal_gpio *ggpio)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
||||
return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_VALUE));
|
||||
}
|
||||
|
||||
long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
@ -25,6 +41,16 @@ long __metal_driver_sifive_gpio0_output(struct metal_gpio *ggpio)
|
|||
return __METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_PORT));
|
||||
}
|
||||
|
||||
|
||||
int __metal_driver_sifive_gpio0_disable_output(struct metal_gpio *ggpio, long source)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_OUTPUT_EN)) &= ~source;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_gpio0_enable_output(struct metal_gpio *ggpio, long source)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
@ -72,14 +98,124 @@ int __metal_driver_sifive_gpio0_enable_io(struct metal_gpio *ggpio, long source,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_gpio0_disable_io(struct metal_gpio *ggpio, long source)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_IOF_EN)) &= ~source;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_gpio0_config_int(struct metal_gpio *ggpio, long source, int intr_type)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
||||
switch (intr_type)
|
||||
{
|
||||
case METAL_GPIO_INT_DISABLE:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) &= ~source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) &= ~source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) &= ~source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) &= ~source;
|
||||
break;
|
||||
case METAL_GPIO_INT_RISING:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_FALLING:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_BOTH_EDGE:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_HIGH:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_LOW:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_BOTH_LEVEL:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_MAX:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IE)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IE)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IE)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IE)) |= source;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_gpio0_clear_int(struct metal_gpio *ggpio, long source, int intr_type)
|
||||
{
|
||||
long base = __metal_driver_sifive_gpio0_base(ggpio);
|
||||
|
||||
switch (intr_type)
|
||||
{
|
||||
case METAL_GPIO_INT_RISING:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_FALLING:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_BOTH_EDGE:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_HIGH:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_LOW:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_BOTH_LEVEL:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
|
||||
break;
|
||||
case METAL_GPIO_INT_MAX:
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_RISE_IP)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_FALL_IP)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_HIGH_IP)) |= source;
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_GPIO0_LOW_IP)) |= source;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct metal_interrupt *
|
||||
__metal_driver_gpio_interrupt_controller(struct metal_gpio *gpio)
|
||||
{
|
||||
return __metal_driver_sifive_gpio0_interrupt_parent(gpio);
|
||||
}
|
||||
|
||||
int __metal_driver_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin)
|
||||
{
|
||||
int irq;
|
||||
irq = __metal_driver_sifive_gpio0_interrupt_lines(gpio, pin);
|
||||
return irq;
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_gpio0) = {
|
||||
.gpio.disable_input = __metal_driver_sifive_gpio0_disable_input,
|
||||
.gpio.output = __metal_driver_sifive_gpio0_output,
|
||||
.gpio.enable_output = __metal_driver_sifive_gpio0_enable_output,
|
||||
.gpio.output_set = __metal_driver_sifive_gpio0_output_set,
|
||||
.gpio.output_clear = __metal_driver_sifive_gpio0_output_clear,
|
||||
.gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle,
|
||||
.gpio.enable_io = __metal_driver_sifive_gpio0_enable_io,
|
||||
.gpio.disable_input = __metal_driver_sifive_gpio0_disable_input,
|
||||
.gpio.enable_input = __metal_driver_sifive_gpio0_enable_input,
|
||||
.gpio.input = __metal_driver_sifive_gpio0_input,
|
||||
.gpio.output = __metal_driver_sifive_gpio0_output,
|
||||
.gpio.disable_output = __metal_driver_sifive_gpio0_disable_output,
|
||||
.gpio.enable_output = __metal_driver_sifive_gpio0_enable_output,
|
||||
.gpio.output_set = __metal_driver_sifive_gpio0_output_set,
|
||||
.gpio.output_clear = __metal_driver_sifive_gpio0_output_clear,
|
||||
.gpio.output_toggle = __metal_driver_sifive_gpio0_output_toggle,
|
||||
.gpio.enable_io = __metal_driver_sifive_gpio0_enable_io,
|
||||
.gpio.disable_io = __metal_driver_sifive_gpio0_disable_io,
|
||||
.gpio.config_int = __metal_driver_sifive_gpio0_config_int,
|
||||
.gpio.clear_int = __metal_driver_sifive_gpio0_clear_int,
|
||||
.gpio.interrupt_controller = __metal_driver_gpio_interrupt_controller,
|
||||
.gpio.get_interrupt_id = __metal_driver_gpio_get_interrupt_id,
|
||||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_GPIO0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -82,6 +82,33 @@ int __metal_driver_sifive_local_external_interrupt_disable(struct metal_interrup
|
|||
return rc;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_local_external_interrupt_set_threshold(struct metal_interrupt *controller,
|
||||
unsigned int threshold)
|
||||
{
|
||||
/* Core controller does not support threshold configuration */
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int __metal_driver_sifive_local_external_interrupt_get_threshold(struct metal_interrupt *controller)
|
||||
{
|
||||
/* Core controller does not support threshold configuration */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int __metal_driver_sifive_local_external_interrupt_set_priority(struct metal_interrupt *controller,
|
||||
int id, unsigned int priority)
|
||||
{
|
||||
/* Core controller does not support priority configuration */
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int __metal_driver_sifive_local_external_interrupt_get_priority(struct metal_interrupt *controller, int id)
|
||||
{
|
||||
/* Core controller does not support priority configuration */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_local_external_command_request (struct metal_interrupt *controller,
|
||||
int command, void *data)
|
||||
{
|
||||
|
@ -111,7 +138,14 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_local_external_interrupts0) =
|
|||
.local0_vtable.interrupt_register = __metal_driver_sifive_local_external_interrupt_register,
|
||||
.local0_vtable.interrupt_enable = __metal_driver_sifive_local_external_interrupt_enable,
|
||||
.local0_vtable.interrupt_disable = __metal_driver_sifive_local_external_interrupt_disable,
|
||||
.local0_vtable.interrupt_get_threshold = __metal_driver_sifive_local_external_interrupt_get_threshold,
|
||||
.local0_vtable.interrupt_set_threshold = __metal_driver_sifive_local_external_interrupt_set_threshold,
|
||||
.local0_vtable.interrupt_get_priority = __metal_driver_sifive_local_external_interrupt_get_priority,
|
||||
.local0_vtable.interrupt_set_priority = __metal_driver_sifive_local_external_interrupt_set_priority,
|
||||
.local0_vtable.command_request = __metal_driver_sifive_local_external_command_request,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_RTC0
|
||||
|
||||
#include <metal/drivers/sifive_rtc0.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* RTCCFG */
|
||||
#define METAL_RTCCFG_RTCSCALE_MASK 0xF
|
||||
#define METAL_RTCCFG_ENALWAYS (1 << 12)
|
||||
#define METAL_RTCCFG_IP0 (1 << 28)
|
||||
|
||||
/* RTCCMP0 */
|
||||
#define METAL_RTCCMP0_MAX UINT32_MAX
|
||||
|
||||
#define RTC_REG(base, offset) (((unsigned long)base + offset))
|
||||
#define RTC_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)RTC_REG(base, offset)))
|
||||
|
||||
uint64_t __metal_driver_sifive_rtc0_get_rate(const struct metal_rtc *const rtc) {
|
||||
const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc);
|
||||
return metal_clock_get_rate_hz(clock);
|
||||
}
|
||||
|
||||
uint64_t __metal_driver_sifive_rtc0_set_rate(const struct metal_rtc *const rtc, const uint64_t rate) {
|
||||
const struct metal_clock *const clock = __metal_driver_sifive_rtc0_clock(rtc);
|
||||
return metal_clock_get_rate_hz(clock);
|
||||
}
|
||||
|
||||
uint64_t __metal_driver_sifive_rtc0_get_compare(const struct metal_rtc *const rtc) {
|
||||
const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
|
||||
|
||||
const uint32_t shift = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) & METAL_RTCCFG_RTCSCALE_MASK;
|
||||
|
||||
return ((uint64_t)RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) << shift);
|
||||
}
|
||||
|
||||
uint64_t __metal_driver_sifive_rtc0_set_compare(const struct metal_rtc *const rtc, const uint64_t compare) {
|
||||
const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
|
||||
|
||||
/* Determine the bit shift and shifted value to store in rtccmp0/rtccfg.scale */
|
||||
uint32_t shift = 0;
|
||||
uint64_t comp_shifted = compare;
|
||||
while (comp_shifted > METAL_RTCCMP0_MAX) {
|
||||
shift += 1;
|
||||
comp_shifted = comp_shifted >> shift;
|
||||
}
|
||||
|
||||
/* Set the value of rtccfg.scale */
|
||||
uint32_t cfg = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG);
|
||||
cfg &= ~(METAL_RTCCFG_RTCSCALE_MASK);
|
||||
cfg |= (METAL_RTCCFG_RTCSCALE_MASK & shift);
|
||||
RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) = cfg;
|
||||
|
||||
/* Set the value of rtccmp0 */
|
||||
RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCMP0) = (uint32_t) comp_shifted;
|
||||
|
||||
return __metal_driver_sifive_rtc0_get_compare(rtc);
|
||||
}
|
||||
|
||||
uint64_t __metal_driver_sifive_rtc0_get_count(const struct metal_rtc *const rtc) {
|
||||
const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
|
||||
|
||||
uint64_t count = RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI);
|
||||
count <<= 32;
|
||||
count |= RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint64_t __metal_driver_sifive_rtc0_set_count(const struct metal_rtc *const rtc, const uint64_t count) {
|
||||
const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
|
||||
|
||||
RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTHI) = (UINT_MAX & (count >> 32));
|
||||
RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCOUNTLO) = (UINT_MAX & count);
|
||||
|
||||
return __metal_driver_sifive_rtc0_get_count(rtc);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_rtc0_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option) {
|
||||
const uint64_t base = __metal_driver_sifive_rtc0_control_base(rtc);
|
||||
|
||||
switch (option) {
|
||||
default:
|
||||
case METAL_RTC_STOP:
|
||||
RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) &= ~(METAL_RTCCFG_ENALWAYS);
|
||||
break;
|
||||
case METAL_RTC_RUN:
|
||||
RTC_REGW(base, METAL_SIFIVE_RTC0_RTCCFG) |= METAL_RTCCFG_ENALWAYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct metal_interrupt *__metal_driver_sifive_rtc0_get_interrupt(const struct metal_rtc *const rtc) {
|
||||
return __metal_driver_sifive_rtc0_interrupt_parent(rtc);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_rtc0_get_interrupt_id(const struct metal_rtc *const rtc) {
|
||||
return __metal_driver_sifive_rtc0_interrupt_line(rtc);
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_rtc0) = {
|
||||
.rtc.get_rate = __metal_driver_sifive_rtc0_get_rate,
|
||||
.rtc.set_rate = __metal_driver_sifive_rtc0_set_rate,
|
||||
.rtc.get_compare = __metal_driver_sifive_rtc0_get_compare,
|
||||
.rtc.set_compare = __metal_driver_sifive_rtc0_set_compare,
|
||||
.rtc.get_count = __metal_driver_sifive_rtc0_get_count,
|
||||
.rtc.set_count = __metal_driver_sifive_rtc0_set_count,
|
||||
.rtc.run = __metal_driver_sifive_rtc0_run,
|
||||
.rtc.get_interrupt = __metal_driver_sifive_rtc0_get_interrupt,
|
||||
.rtc.get_interrupt_id = __metal_driver_sifive_rtc0_get_interrupt_id,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include <metal/drivers/sifive_spi0.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/machine.h>
|
||||
#include <metal/time.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Register fields */
|
||||
|
@ -54,19 +55,25 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp
|
|||
long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)spi);
|
||||
/* Set protocol */
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK);
|
||||
switch(config->protocol) {
|
||||
case METAL_SPI_SINGLE:
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
|
||||
break;
|
||||
case METAL_SPI_DUAL:
|
||||
switch (config->protocol) {
|
||||
case METAL_SPI_SINGLE:
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
|
||||
break;
|
||||
case METAL_SPI_DUAL:
|
||||
if (config->multi_wire == MULTI_WIRE_ALL)
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL;
|
||||
break;
|
||||
case METAL_SPI_QUAD:
|
||||
else
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
|
||||
break;
|
||||
case METAL_SPI_QUAD:
|
||||
if (config->multi_wire == MULTI_WIRE_ALL)
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD;
|
||||
break;
|
||||
default:
|
||||
/* Unsupported value */
|
||||
return -1;
|
||||
else
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_SINGLE;
|
||||
break;
|
||||
default:
|
||||
/* Unsupported value */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set Polarity */
|
||||
|
@ -107,7 +114,7 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp
|
|||
}
|
||||
|
||||
/* Set CS line */
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = config->csid;
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSID) = 1 << (config->csid);
|
||||
|
||||
/* Toggle off memory-mapped SPI flash mode, toggle on programmable IO mode
|
||||
* It seems that with this line uncommented, the debugger cannot have access
|
||||
|
@ -121,6 +128,28 @@ static int configure_spi(struct __metal_driver_sifive_spi0 *spi, struct metal_sp
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void spi_mode_switch(struct __metal_driver_sifive_spi0 *spi,
|
||||
struct metal_spi_config *config,
|
||||
unsigned int trans_stage) {
|
||||
long control_base =
|
||||
__metal_driver_sifive_spi0_control_base((struct metal_spi *)spi);
|
||||
|
||||
if (config->multi_wire == trans_stage) {
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) &= ~(METAL_SPI_PROTO_MASK);
|
||||
switch (config->protocol) {
|
||||
case METAL_SPI_DUAL:
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_DUAL;
|
||||
break;
|
||||
case METAL_SPI_QUAD:
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_FMT) |= METAL_SPI_PROTO_QUAD;
|
||||
break;
|
||||
default:
|
||||
/* Unsupported value */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
|
||||
struct metal_spi_config *config,
|
||||
size_t len,
|
||||
|
@ -130,6 +159,7 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
|
|||
struct __metal_driver_sifive_spi0 *spi = (void *)gspi;
|
||||
long control_base = __metal_driver_sifive_spi0_control_base(gspi);
|
||||
int rc = 0;
|
||||
size_t i = 0;
|
||||
|
||||
rc = configure_spi(spi, config);
|
||||
if(rc != 0) {
|
||||
|
@ -145,7 +175,97 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
|
|||
/* Declare time_t variables to break out of infinite while loop */
|
||||
time_t endwait;
|
||||
|
||||
for(int i = 0; i < len; i++) {
|
||||
for (i = 0; i < config->cmd_num; i++) {
|
||||
|
||||
while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
|
||||
;
|
||||
|
||||
if (tx_buf) {
|
||||
METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
|
||||
} else {
|
||||
METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
|
||||
}
|
||||
|
||||
endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
|
||||
|
||||
while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
|
||||
METAL_SPI_RXDATA_EMPTY) {
|
||||
if (metal_time() > endwait) {
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
|
||||
~(METAL_SPI_CSMODE_MASK);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_buf) {
|
||||
rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
/* switch to Dual/Quad mode */
|
||||
spi_mode_switch(spi, config, MULTI_WIRE_ADDR_DATA);
|
||||
|
||||
/* Send Addr data */
|
||||
for (; i < (config->cmd_num + config->addr_num); i++) {
|
||||
|
||||
while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
|
||||
;
|
||||
|
||||
if (tx_buf) {
|
||||
METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
|
||||
} else {
|
||||
METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
|
||||
}
|
||||
|
||||
endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
|
||||
|
||||
while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
|
||||
METAL_SPI_RXDATA_EMPTY) {
|
||||
if (metal_time() > endwait) {
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
|
||||
~(METAL_SPI_CSMODE_MASK);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_buf) {
|
||||
rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send Dummy data */
|
||||
for (; i < (config->cmd_num + config->addr_num + config->dummy_num); i++) {
|
||||
|
||||
while (METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXDATA) & METAL_SPI_TXDATA_FULL)
|
||||
;
|
||||
|
||||
if (tx_buf) {
|
||||
METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = tx_buf[i];
|
||||
} else {
|
||||
METAL_SPI_REGB(METAL_SIFIVE_SPI0_TXDATA) = 0;
|
||||
}
|
||||
|
||||
endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
|
||||
|
||||
while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) &
|
||||
METAL_SPI_RXDATA_EMPTY) {
|
||||
if (metal_time() > endwait) {
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &=
|
||||
~(METAL_SPI_CSMODE_MASK);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (rx_buf) {
|
||||
rx_buf[i] = (char)(rxdata & METAL_SPI_TXRXDATA_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
/* switch to Dual/Quad mode */
|
||||
spi_mode_switch(spi, config, MULTI_WIRE_DATA_ONLY);
|
||||
|
||||
for (; i < len; i++) {
|
||||
/* Master send bytes to the slave */
|
||||
|
||||
/* Wait for TXFIFO to not be full */
|
||||
|
@ -164,10 +284,10 @@ int __metal_driver_sifive_spi0_transfer(struct metal_spi *gspi,
|
|||
/* Wait for RXFIFO to not be empty, but break the nested loops if timeout
|
||||
* this timeout method needs refining, preferably taking into account
|
||||
* the device specs */
|
||||
endwait = time(NULL) + METAL_SPI_RXDATA_TIMEOUT;
|
||||
endwait = metal_time() + METAL_SPI_RXDATA_TIMEOUT;
|
||||
|
||||
while ((rxdata = METAL_SPI_REGW(METAL_SIFIVE_SPI0_RXDATA)) & METAL_SPI_RXDATA_EMPTY) {
|
||||
if (time(NULL) > endwait) {
|
||||
if (metal_time() > endwait) {
|
||||
/* If timeout, deassert the CS */
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_CSMODE) &= ~(METAL_SPI_CSMODE_MASK);
|
||||
|
||||
|
@ -227,18 +347,19 @@ int __metal_driver_sifive_spi0_set_baud_rate(struct metal_spi *gspi, int baud_ra
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pre_rate_change_callback(void *priv)
|
||||
static void pre_rate_change_callback_func(void *priv)
|
||||
{
|
||||
long control_base = __metal_driver_sifive_spi0_control_base((struct metal_spi *)priv);
|
||||
|
||||
/* Detect when the TXDATA is empty by setting the transmit watermark count
|
||||
* to zero and waiting until an interrupt is pending */
|
||||
* to one and waiting until an interrupt is pending (indicating an empty TXFIFO) */
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) &= ~(METAL_SPI_TXMARK_MASK);
|
||||
METAL_SPI_REGW(METAL_SIFIVE_SPI0_TXMARK) |= (METAL_SPI_TXMARK_MASK & 1);
|
||||
|
||||
while((METAL_SPI_REGW(METAL_SIFIVE_SPI0_IP) & METAL_SPI_TXWM) == 0) ;
|
||||
}
|
||||
|
||||
static void post_rate_change_callback(void *priv)
|
||||
static void post_rate_change_callback_func(void *priv)
|
||||
{
|
||||
struct __metal_driver_sifive_spi0 *spi = priv;
|
||||
metal_spi_set_baud_rate(&spi->spi, spi->baud_rate);
|
||||
|
@ -251,8 +372,13 @@ void __metal_driver_sifive_spi0_init(struct metal_spi *gspi, int baud_rate)
|
|||
struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_spi0_pinmux(gspi);
|
||||
|
||||
if(clock != NULL) {
|
||||
metal_clock_register_pre_rate_change_callback(clock, &pre_rate_change_callback, spi);
|
||||
metal_clock_register_post_rate_change_callback(clock, &post_rate_change_callback, spi);
|
||||
spi->pre_rate_change_callback.callback = &pre_rate_change_callback_func;
|
||||
spi->pre_rate_change_callback.priv = spi;
|
||||
metal_clock_register_pre_rate_change_callback(clock, &(spi->pre_rate_change_callback));
|
||||
|
||||
spi->post_rate_change_callback.callback = &post_rate_change_callback_func;
|
||||
spi->post_rate_change_callback.priv = spi;
|
||||
metal_clock_register_post_rate_change_callback(clock, &(spi->post_rate_change_callback));
|
||||
}
|
||||
|
||||
metal_spi_set_baud_rate(&(spi->spi), baud_rate);
|
||||
|
@ -275,3 +401,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_spi0) = {
|
|||
.spi.set_baud_rate = __metal_driver_sifive_spi0_set_baud_rate,
|
||||
};
|
||||
#endif /* METAL_SIFIVE_SPI0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -5,15 +5,17 @@
|
|||
|
||||
#ifdef METAL_SIFIVE_TEST0
|
||||
|
||||
#include <metal/machine.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <metal/drivers/sifive_test0.h>
|
||||
#include <metal/io.h>
|
||||
#include <stdint.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code) __attribute__((noreturn));
|
||||
void __metal_driver_sifive_test0_exit(const struct __metal_shutdown *sd, int code)
|
||||
{
|
||||
long base = __metal_driver_sifive_test0_base();
|
||||
long base = __metal_driver_sifive_test0_base(sd);
|
||||
uint32_t out = (code << 16) + (code == 0 ? 0x5555 : 0x3333);
|
||||
while (1) {
|
||||
__METAL_ACCESS_ONCE((__metal_io_u32 *)(base + METAL_SIFIVE_TEST0_FINISHER_OFFSET)) = out;
|
||||
|
@ -24,3 +26,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_test0) = {
|
|||
.shutdown.exit = &__metal_driver_sifive_test0_exit,
|
||||
};
|
||||
#endif /* METAL_SIFIVE_TEST0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_TRACE
|
||||
|
||||
#include <metal/drivers/sifive_trace.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
#define TRACE_REG(offset) (((unsigned long)base + (offset)))
|
||||
#define TRACE_REG8(offset) \
|
||||
(__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset)))
|
||||
#define TRACE_REG16(offset) \
|
||||
(__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset)))
|
||||
#define TRACE_REG32(offset) \
|
||||
(__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset)))
|
||||
|
||||
static void write_itc_uint32(struct metal_uart *trace, uint32_t data) {
|
||||
long base = __metal_driver_sifive_trace_base(trace);
|
||||
|
||||
TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data;
|
||||
}
|
||||
|
||||
static void write_itc_uint16(struct metal_uart *trace, uint16_t data) {
|
||||
long base = __metal_driver_sifive_trace_base(trace);
|
||||
|
||||
TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data;
|
||||
}
|
||||
|
||||
static void write_itc_uint8(struct metal_uart *trace, uint8_t data) {
|
||||
long base = __metal_driver_sifive_trace_base(trace);
|
||||
|
||||
TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_trace_putc(struct metal_uart *trace,
|
||||
unsigned char c) {
|
||||
static uint32_t buffer = 0;
|
||||
static int bytes_in_buffer = 0;
|
||||
|
||||
buffer |= (((uint32_t)c) << (bytes_in_buffer * 8));
|
||||
|
||||
bytes_in_buffer += 1;
|
||||
|
||||
if (bytes_in_buffer >= 4) {
|
||||
write_itc_uint32(trace, buffer);
|
||||
|
||||
buffer = 0;
|
||||
bytes_in_buffer = 0;
|
||||
} else if ((c == '\n') || (c == '\r')) { // partial write
|
||||
switch (bytes_in_buffer) {
|
||||
case 3: // do a full word write
|
||||
write_itc_uint16(trace, (uint16_t)(buffer));
|
||||
write_itc_uint8(trace, (uint8_t)(buffer >> 16));
|
||||
break;
|
||||
case 2: // do a 16 bit write
|
||||
write_itc_uint16(trace, (uint16_t)buffer);
|
||||
break;
|
||||
case 1: // do a 1 byte write
|
||||
write_itc_uint8(trace, (uint8_t)buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = 0;
|
||||
bytes_in_buffer = 0;
|
||||
}
|
||||
|
||||
return (int)c;
|
||||
}
|
||||
|
||||
void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) {
|
||||
// The only init we do here is to make sure ITC 0 is enabled. It is up to
|
||||
// Freedom Studio or other mechanisms to make sure tracing is enabled. If we
|
||||
// try to enable tracing here, it will likely conflict with Freedom Studio,
|
||||
// and they will just fight with each other.
|
||||
|
||||
long base = __metal_driver_sifive_trace_base(trace);
|
||||
|
||||
TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001;
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = {
|
||||
.uart.init = __metal_driver_sifive_trace_init,
|
||||
.uart.putc = __metal_driver_sifive_trace_putc,
|
||||
.uart.getc = NULL,
|
||||
|
||||
.uart.get_baud_rate = NULL,
|
||||
.uart.set_baud_rate = NULL,
|
||||
|
||||
.uart.controller_interrupt = NULL,
|
||||
.uart.get_interrupt_id = NULL,
|
||||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_TRACE */
|
|
@ -38,27 +38,42 @@ int __metal_driver_sifive_uart0_get_interrupt_id(struct metal_uart *uart)
|
|||
return (__metal_driver_sifive_uart0_interrupt_line(uart) + METAL_INTERRUPT_ID_GL0);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, unsigned char c)
|
||||
|
||||
int __metal_driver_sifive_uart0_txready(struct metal_uart *uart)
|
||||
{
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(uart);
|
||||
|
||||
return !((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL));
|
||||
}
|
||||
|
||||
|
||||
int __metal_driver_sifive_uart0_putc(struct metal_uart *uart, int c)
|
||||
{
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(uart);
|
||||
|
||||
while ((UART_REGW(METAL_SIFIVE_UART0_TXDATA) & UART_TXFULL) != 0) { }
|
||||
while (!__metal_driver_sifive_uart0_txready(uart)) {
|
||||
/* wait */
|
||||
}
|
||||
UART_REGW(METAL_SIFIVE_UART0_TXDATA) = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, unsigned char *c)
|
||||
{
|
||||
uint32_t ch = UART_RXEMPTY;
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(uart);
|
||||
|
||||
while (ch & UART_RXEMPTY) {
|
||||
ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);
|
||||
int __metal_driver_sifive_uart0_getc(struct metal_uart *uart, int *c)
|
||||
{
|
||||
uint32_t ch;
|
||||
long control_base = __metal_driver_sifive_uart0_control_base(uart);
|
||||
/* No seperate status register, we get status and the byte at same time */
|
||||
ch = UART_REGW(METAL_SIFIVE_UART0_RXDATA);;
|
||||
if( ch & UART_RXEMPTY ){
|
||||
*c = -1; /* aka: EOF in most of the world */
|
||||
} else {
|
||||
*c = ch & 0x0ff;
|
||||
}
|
||||
*c = ch & 0xff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int __metal_driver_sifive_uart0_get_baud_rate(struct metal_uart *guart)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = (void *)guart;
|
||||
|
@ -82,7 +97,7 @@ int __metal_driver_sifive_uart0_set_baud_rate(struct metal_uart *guart, int baud
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pre_rate_change_callback(void *priv)
|
||||
static void pre_rate_change_callback_func(void *priv)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = priv;
|
||||
long control_base = __metal_driver_sifive_uart0_control_base((struct metal_uart *)priv);
|
||||
|
@ -105,10 +120,10 @@ static void pre_rate_change_callback(void *priv)
|
|||
long cycles_to_wait = bits_per_symbol * clk_freq / uart->baud_rate;
|
||||
|
||||
for(volatile long x = 0; x < cycles_to_wait; x++)
|
||||
asm("nop");
|
||||
__asm__("nop");
|
||||
}
|
||||
|
||||
static void post_rate_change_callback(void *priv)
|
||||
static void post_rate_change_callback_func(void *priv)
|
||||
{
|
||||
struct __metal_driver_sifive_uart0 *uart = priv;
|
||||
metal_uart_set_baud_rate(&uart->uart, uart->baud_rate);
|
||||
|
@ -121,8 +136,13 @@ void __metal_driver_sifive_uart0_init(struct metal_uart *guart, int baud_rate)
|
|||
struct __metal_driver_sifive_gpio0 *pinmux = __metal_driver_sifive_uart0_pinmux(guart);
|
||||
|
||||
if(clock != NULL) {
|
||||
metal_clock_register_pre_rate_change_callback(clock, &pre_rate_change_callback, guart);
|
||||
metal_clock_register_post_rate_change_callback(clock, &post_rate_change_callback, guart);
|
||||
uart->pre_rate_change_callback.callback = &pre_rate_change_callback_func;
|
||||
uart->pre_rate_change_callback.priv = guart;
|
||||
metal_clock_register_pre_rate_change_callback(clock, &(uart->pre_rate_change_callback));
|
||||
|
||||
uart->post_rate_change_callback.callback = &post_rate_change_callback_func;
|
||||
uart->post_rate_change_callback.priv = guart;
|
||||
metal_clock_register_post_rate_change_callback(clock, &(uart->post_rate_change_callback));
|
||||
}
|
||||
|
||||
metal_uart_set_baud_rate(&(uart->uart), baud_rate);
|
||||
|
@ -149,3 +169,5 @@ __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_uart0) = {
|
|||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_UART0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine/platform.h>
|
||||
|
||||
#ifdef METAL_SIFIVE_WDOG0
|
||||
|
||||
#include <metal/drivers/sifive_uart0.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* WDOGCFG */
|
||||
#define METAL_WDOGCFG_SCALE_MASK 7
|
||||
#define METAL_WDOGCFG_RSTEN (1 << 8)
|
||||
#define METAL_WDOGCFG_ZEROCMP (1 << 9)
|
||||
#define METAL_WDOGCFG_ENALWAYS (1 << 12)
|
||||
#define METAL_WDOGCFG_COREAWAKE (1 << 13)
|
||||
#define METAL_WDOGCFG_IP (1 << 28)
|
||||
|
||||
/* WDOGCMP */
|
||||
#define METAL_WDOGCMP_MASK 0xFFFF
|
||||
|
||||
#define WDOG_REG(base, offset) (((unsigned long)base + offset))
|
||||
#define WDOG_REGB(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)WDOG_REG(base, offset)))
|
||||
#define WDOG_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)WDOG_REG(base, offset)))
|
||||
|
||||
/* All writes to watchdog registers must be precedded by a write of
|
||||
* a magic number to WDOGKEY */
|
||||
#define WDOG_UNLOCK(base) (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGKEY) = METAL_SIFIVE_WDOG0_MAGIC_KEY)
|
||||
|
||||
/* Unlock the watchdog and then perform a register access */
|
||||
#define WDOG_UNLOCK_REGW(base, offset) \
|
||||
WDOG_UNLOCK(base);\
|
||||
WDOG_REGW(base, offset)
|
||||
|
||||
int __metal_driver_sifive_wdog0_feed(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGFEED) = METAL_SIFIVE_WDOG0_MAGIC_FOOD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long int __metal_driver_sifive_wdog0_get_rate(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog);
|
||||
|
||||
const long int clock_rate = metal_clock_get_rate_hz(clock);
|
||||
|
||||
if (clock_rate == 0)
|
||||
return -1;
|
||||
|
||||
const unsigned int scale = (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) & METAL_WDOGCFG_SCALE_MASK);
|
||||
|
||||
return clock_rate / (1 << scale);
|
||||
}
|
||||
|
||||
long int __metal_driver_sifive_wdog0_set_rate(const struct metal_watchdog *const wdog, const long int rate)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
const struct metal_clock *const clock = __metal_driver_sifive_wdog0_clock(wdog);
|
||||
|
||||
const long int clock_rate = metal_clock_get_rate_hz(clock);
|
||||
|
||||
if (rate >= clock_rate) {
|
||||
/* We can't scale the rate above the driving clock. Clear the scale
|
||||
* field and return the driving clock rate */
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK);
|
||||
return clock_rate;
|
||||
}
|
||||
|
||||
/* Look for the closest scale value */
|
||||
long min_diff = LONG_MAX;
|
||||
unsigned int min_scale = 0;
|
||||
for (int i = 0; i < METAL_WDOGCFG_SCALE_MASK; i++) {
|
||||
const long int new_rate = clock_rate / (1 << i);
|
||||
|
||||
long int diff = rate - new_rate;
|
||||
if (diff < 0)
|
||||
diff *= -1;
|
||||
|
||||
if (diff < min_diff) {
|
||||
min_diff = diff;
|
||||
min_scale = i;
|
||||
}
|
||||
}
|
||||
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_SCALE_MASK);
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= (METAL_WDOGCFG_SCALE_MASK & min_scale);
|
||||
|
||||
return clock_rate / (1 << min_scale);
|
||||
}
|
||||
|
||||
long int __metal_driver_sifive_wdog0_get_timeout(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
|
||||
return (WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) & METAL_WDOGCMP_MASK);
|
||||
}
|
||||
|
||||
long int __metal_driver_sifive_wdog0_set_timeout(const struct metal_watchdog *const wdog, const long int timeout)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
|
||||
/* Cap the timeout at the max value */
|
||||
const long int set_timeout = timeout > METAL_WDOGCMP_MASK ? METAL_WDOGCMP_MASK : timeout;
|
||||
|
||||
/* If we edit the timeout value in-place by masking the compare value to 0 and
|
||||
* then writing it, we cause a spurious interrupt because the compare value
|
||||
* is temporarily 0. Instead, read the value into a local variable, modify it
|
||||
* there, and then write the whole register back */
|
||||
uint32_t wdogcmp = WDOG_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP);
|
||||
|
||||
wdogcmp &= ~(METAL_WDOGCMP_MASK);
|
||||
wdogcmp |= set_timeout;
|
||||
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCMP) = wdogcmp;
|
||||
|
||||
return set_timeout;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_wdog0_set_result(const struct metal_watchdog *const wdog,
|
||||
const enum metal_watchdog_result result)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
|
||||
/* Turn off reset enable and counter reset */
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_RSTEN | METAL_WDOGCFG_ZEROCMP);
|
||||
|
||||
switch (result) {
|
||||
default:
|
||||
case METAL_WATCHDOG_NO_RESULT:
|
||||
break;
|
||||
case METAL_WATCHDOG_INTERRUPT:
|
||||
/* Reset counter to zero after match */
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ZEROCMP;
|
||||
break;
|
||||
case METAL_WATCHDOG_FULL_RESET:
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_RSTEN;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_wdog0_run(const struct metal_watchdog *const wdog,
|
||||
const enum metal_watchdog_run_option option)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_ENALWAYS | METAL_WDOGCFG_COREAWAKE);
|
||||
|
||||
switch (option) {
|
||||
default:
|
||||
case METAL_WATCHDOG_STOP:
|
||||
break;
|
||||
case METAL_WATCHDOG_RUN_ALWAYS:
|
||||
/* Feed the watchdog before starting to reset counter */
|
||||
__metal_driver_sifive_wdog0_feed(wdog);
|
||||
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_ENALWAYS;
|
||||
break;
|
||||
case METAL_WATCHDOG_RUN_AWAKE:
|
||||
/* Feed the watchdog before starting to reset counter */
|
||||
__metal_driver_sifive_wdog0_feed(wdog);
|
||||
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) |= METAL_WDOGCFG_COREAWAKE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct metal_interrupt *__metal_driver_sifive_wdog0_get_interrupt(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return __metal_driver_sifive_wdog0_interrupt_parent(wdog);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_wdog0_get_interrupt_id(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
return __metal_driver_sifive_wdog0_interrupt_line(wdog);
|
||||
}
|
||||
|
||||
int __metal_driver_sifive_wdog0_clear_interrupt(const struct metal_watchdog *const wdog)
|
||||
{
|
||||
const uintptr_t base = (uintptr_t)__metal_driver_sifive_wdog0_control_base(wdog);
|
||||
|
||||
/* Clear the interrupt pending bit */
|
||||
WDOG_UNLOCK_REGW(base, METAL_SIFIVE_WDOG0_WDOGCFG) &= ~(METAL_WDOGCFG_IP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_wdog0) = {
|
||||
.watchdog.feed = __metal_driver_sifive_wdog0_feed,
|
||||
.watchdog.get_rate = __metal_driver_sifive_wdog0_get_rate,
|
||||
.watchdog.set_rate = __metal_driver_sifive_wdog0_set_rate,
|
||||
.watchdog.get_timeout = __metal_driver_sifive_wdog0_get_timeout,
|
||||
.watchdog.set_timeout = __metal_driver_sifive_wdog0_set_timeout,
|
||||
.watchdog.set_result = __metal_driver_sifive_wdog0_set_result,
|
||||
.watchdog.run = __metal_driver_sifive_wdog0_run,
|
||||
.watchdog.get_interrupt = __metal_driver_sifive_wdog0_get_interrupt,
|
||||
.watchdog.get_interrupt_id = __metal_driver_sifive_wdog0_get_interrupt_id,
|
||||
.watchdog.clear_interrupt = __metal_driver_sifive_wdog0_clear_interrupt,
|
||||
};
|
||||
|
||||
#endif /* METAL_SIFIVE_WDOG0 */
|
||||
|
||||
typedef int no_empty_translation_units;
|
||||
|
|
@ -8,7 +8,6 @@
|
|||
* defined to have the first address being where execution should start. */
|
||||
.section .text.metal.init.enter
|
||||
.global _enter
|
||||
|
||||
_enter:
|
||||
.cfi_startproc
|
||||
|
||||
|
|
|
@ -4,15 +4,23 @@
|
|||
#include <metal/machine.h>
|
||||
#include <metal/gpio.h>
|
||||
|
||||
extern inline int metal_gpio_disable_input(struct metal_gpio *gpio, int pin);
|
||||
extern inline int metal_gpio_enable_output(struct metal_gpio *gpio, int pin);
|
||||
extern inline int metal_gpio_set_pin(struct metal_gpio *, int pin, int value);
|
||||
extern inline int metal_gpio_get_pin(struct metal_gpio *, int pin);
|
||||
extern inline int metal_gpio_clear_pin(struct metal_gpio *, int pin);
|
||||
extern inline int metal_gpio_toggle_pin(struct metal_gpio *, int pin);
|
||||
extern inline int metal_gpio_enable_pinmux(struct metal_gpio *, int pin, int io_function);
|
||||
extern __inline__ int metal_gpio_disable_input(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_enable_input(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_enable_output(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_disable_output(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_get_output_pin(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_get_input_pin(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_set_pin(struct metal_gpio *, int pin, int value);
|
||||
extern __inline__ int metal_gpio_clear_pin(struct metal_gpio *, int pin);
|
||||
extern __inline__ int metal_gpio_toggle_pin(struct metal_gpio *, int pin);
|
||||
extern __inline__ int metal_gpio_enable_pinmux(struct metal_gpio *, int pin, int io_function);
|
||||
extern __inline__ int metal_gpio_disable_pinmux(struct metal_gpio *, int pin);
|
||||
extern __inline__ struct metal_interrupt* metal_gpio_interrupt_controller(struct metal_gpio *gpio);
|
||||
extern __inline__ int metal_gpio_get_interrupt_id(struct metal_gpio *gpio, int pin);
|
||||
extern __inline__ int metal_gpio_config_interrupt(struct metal_gpio *gpio, int pin, int intr_type);
|
||||
extern __inline__ int metal_gpio_clear_interrupt(struct metal_gpio *gpio, int pin, int intr_type);
|
||||
|
||||
struct metal_gpio *metal_gpio_get_device(int device_num)
|
||||
struct metal_gpio *metal_gpio_get_device(unsigned int device_num)
|
||||
{
|
||||
if(device_num > __MEE_DT_MAX_GPIOS) {
|
||||
return NULL;
|
||||
|
|
|
@ -1,24 +1,82 @@
|
|||
/* Copyright 2018 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <string.h>
|
||||
#include <metal/interrupt.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
extern inline void metal_interrupt_init(struct metal_interrupt *controller);
|
||||
struct metal_interrupt* metal_interrupt_get_controller (metal_intr_cntrl_type cntrl,
|
||||
int id)
|
||||
{
|
||||
switch (cntrl) {
|
||||
case METAL_CPU_CONTROLLER:
|
||||
break;
|
||||
case METAL_CLINT_CONTROLLER:
|
||||
#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
|
||||
return __METAL_DT_RISCV_CLINT0_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case METAL_CLIC_CONTROLLER:
|
||||
#ifdef __METAL_DT_SIFIVE_CLIC0_HANDLE
|
||||
return __METAL_DT_SIFIVE_CLIC0_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
case METAL_PLIC_CONTROLLER:
|
||||
#ifdef __METAL_DT_RISCV_PLIC0_HANDLE
|
||||
return __METAL_DT_RISCV_PLIC0_HANDLE;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern inline int metal_interrupt_register_handler(struct metal_interrupt *controller,
|
||||
extern __inline__ void metal_interrupt_init(struct metal_interrupt *controller);
|
||||
|
||||
extern __inline__ int metal_interrupt_set_vector_mode(struct metal_interrupt *controller,
|
||||
metal_vector_mode mode);
|
||||
extern __inline__ metal_vector_mode metal_interrupt_get_vector_mode(struct metal_interrupt *controller);
|
||||
|
||||
extern __inline__ int metal_interrupt_set_privilege(struct metal_interrupt *controller,
|
||||
metal_intr_priv_mode mode);
|
||||
extern __inline__ metal_intr_priv_mode metal_interrupt_get_privilege(struct metal_interrupt *controller);
|
||||
|
||||
extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller,
|
||||
unsigned int level);
|
||||
extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller);
|
||||
|
||||
extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority);
|
||||
|
||||
extern __inline__ int metal_interrupt_clear(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern __inline__ int metal_interrupt_set(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern __inline__ int metal_interrupt_register_handler(struct metal_interrupt *controller,
|
||||
int id,
|
||||
metal_interrupt_handler_t handler,
|
||||
void *priv);
|
||||
|
||||
extern inline int metal_interrupt_enable(struct metal_interrupt *controller, int id);
|
||||
extern __inline__ int metal_interrupt_register_vector_handler(struct metal_interrupt *controller,
|
||||
int id,
|
||||
metal_interrupt_vector_handler_t handler,
|
||||
void *priv_data);
|
||||
|
||||
extern inline int metal_interrupt_disable(struct metal_interrupt *controller, int id);
|
||||
extern __inline__ int metal_interrupt_enable(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern inline int metal_interrupt_vector_enable(struct metal_interrupt *controller,
|
||||
int id, metal_vector_mode mode);
|
||||
extern __inline__ int metal_interrupt_disable(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern inline int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id);
|
||||
extern __inline__ unsigned int metal_interrupt_get_threshold(struct metal_interrupt *controller);
|
||||
|
||||
extern inline int _metal_interrupt_command_request(struct metal_interrupt *controller,
|
||||
extern __inline__ int metal_interrupt_set_threshold(struct metal_interrupt *controller, unsigned int threshold);
|
||||
|
||||
extern __inline__ unsigned int metal_interrupt_get_priority(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern __inline__ int metal_interrupt_set_priority(struct metal_interrupt *controller, int id, unsigned int priority);
|
||||
|
||||
extern __inline__ int metal_interrupt_vector_enable(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern __inline__ int metal_interrupt_vector_disable(struct metal_interrupt *controller, int id);
|
||||
|
||||
extern __inline__ int _metal_interrupt_command_request(struct metal_interrupt *controller,
|
||||
int cmd, void *data);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct metal_led* metal_led_get (char *label)
|
|||
return metal_led_get_rgb(label, "");
|
||||
}
|
||||
|
||||
extern inline void metal_led_enable(struct metal_led *led);
|
||||
extern inline void metal_led_on(struct metal_led *led);
|
||||
extern inline void metal_led_off(struct metal_led *led);
|
||||
extern inline void metal_led_toggle(struct metal_led *led);
|
||||
extern __inline__ void metal_led_enable(struct metal_led *led);
|
||||
extern __inline__ void metal_led_on(struct metal_led *led);
|
||||
extern __inline__ void metal_led_off(struct metal_led *led);
|
||||
extern __inline__ void metal_led_toggle(struct metal_led *led);
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
#include <metal/lock.h>
|
||||
|
||||
extern inline int metal_lock_init(struct metal_lock *lock);
|
||||
extern inline int metal_lock_take(struct metal_lock *lock);
|
||||
extern inline int metal_lock_give(struct metal_lock *lock);
|
||||
extern __inline__ int metal_lock_init(struct metal_lock *lock);
|
||||
extern __inline__ int metal_lock_take(struct metal_lock *lock);
|
||||
extern __inline__ int metal_lock_give(struct metal_lock *lock);
|
||||
|
|
|
@ -19,8 +19,8 @@ struct metal_memory *metal_get_memory_from_address(const uintptr_t address) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern inline uintptr_t metal_memory_get_base_address(const struct metal_memory *memory);
|
||||
extern inline size_t metal_memory_get_size(const struct metal_memory *memory);
|
||||
extern inline int metal_memory_supports_atomics(const struct metal_memory *memory);
|
||||
extern inline int metal_memory_is_cachable(const struct metal_memory *memory);
|
||||
extern __inline__ uintptr_t metal_memory_get_base_address(const struct metal_memory *memory);
|
||||
extern __inline__ size_t metal_memory_get_size(const struct metal_memory *memory);
|
||||
extern __inline__ int metal_memory_supports_atomics(const struct metal_memory *memory);
|
||||
extern __inline__ int metal_memory_is_cachable(const struct metal_memory *memory);
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include <metal/pmp.h>
|
||||
#include <metal/cpu.h>
|
||||
|
||||
#define CONFIG_TO_INT(_config) (*((size_t *) &(_config)))
|
||||
#define INT_TO_CONFIG(_int) (*((struct metal_pmp_config *) &(_int)))
|
||||
#define CONFIG_TO_INT(_config) (*((char *) &(_config)))
|
||||
#define INT_TO_CONFIG(_int) (*((struct metal_pmp_config *)(char *) &(_int)))
|
||||
|
||||
struct metal_pmp *metal_pmp_get_device(void)
|
||||
{
|
||||
|
@ -63,13 +63,18 @@ static uintptr_t _get_pmpaddr_granularity(uintptr_t address) {
|
|||
return (1 << (index + 3));
|
||||
}
|
||||
|
||||
/* Get the number of pmp regions for the current hart */
|
||||
static int _pmp_regions() {
|
||||
struct metal_cpu *current_cpu = metal_cpu_get(metal_cpu_get_current_hartid());
|
||||
/* Get the number of pmp regions for the given hart */
|
||||
int metal_pmp_num_regions(int hartid)
|
||||
{
|
||||
struct metal_cpu *cpu = metal_cpu_get(hartid);
|
||||
|
||||
return __metal_driver_cpu_num_pmp_regions(current_cpu);
|
||||
return __metal_driver_cpu_num_pmp_regions(cpu);
|
||||
}
|
||||
|
||||
/* Get the number of pmp regions for the current hart */
|
||||
static unsigned int _pmp_regions() {
|
||||
return metal_pmp_num_regions(metal_cpu_get_current_hartid());
|
||||
}
|
||||
|
||||
void metal_pmp_init(struct metal_pmp *pmp) {
|
||||
if(!pmp) {
|
||||
|
@ -151,67 +156,67 @@ int metal_pmp_set_region(struct metal_pmp *pmp,
|
|||
if(old_address != address) {
|
||||
switch(region) {
|
||||
case 0:
|
||||
asm("csrw pmpaddr0, %[addr]"
|
||||
__asm__("csrw pmpaddr0, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 1:
|
||||
asm("csrw pmpaddr1, %[addr]"
|
||||
__asm__("csrw pmpaddr1, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 2:
|
||||
asm("csrw pmpaddr2, %[addr]"
|
||||
__asm__("csrw pmpaddr2, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 3:
|
||||
asm("csrw pmpaddr3, %[addr]"
|
||||
__asm__("csrw pmpaddr3, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 4:
|
||||
asm("csrw pmpaddr4, %[addr]"
|
||||
__asm__("csrw pmpaddr4, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 5:
|
||||
asm("csrw pmpaddr5, %[addr]"
|
||||
__asm__("csrw pmpaddr5, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 6:
|
||||
asm("csrw pmpaddr6, %[addr]"
|
||||
__asm__("csrw pmpaddr6, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 7:
|
||||
asm("csrw pmpaddr7, %[addr]"
|
||||
__asm__("csrw pmpaddr7, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 8:
|
||||
asm("csrw pmpaddr8, %[addr]"
|
||||
__asm__("csrw pmpaddr8, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 9:
|
||||
asm("csrw pmpaddr9, %[addr]"
|
||||
__asm__("csrw pmpaddr9, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 10:
|
||||
asm("csrw pmpaddr10, %[addr]"
|
||||
__asm__("csrw pmpaddr10, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 11:
|
||||
asm("csrw pmpaddr11, %[addr]"
|
||||
__asm__("csrw pmpaddr11, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 12:
|
||||
asm("csrw pmpaddr12, %[addr]"
|
||||
__asm__("csrw pmpaddr12, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 13:
|
||||
asm("csrw pmpaddr13, %[addr]"
|
||||
__asm__("csrw pmpaddr13, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 14:
|
||||
asm("csrw pmpaddr14, %[addr]"
|
||||
__asm__("csrw pmpaddr14, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
case 15:
|
||||
asm("csrw pmpaddr15, %[addr]"
|
||||
__asm__("csrw pmpaddr15, %[addr]"
|
||||
:: [addr] "r" (address) :);
|
||||
break;
|
||||
}
|
||||
|
@ -225,31 +230,31 @@ int metal_pmp_set_region(struct metal_pmp *pmp,
|
|||
|
||||
switch(region / 4) {
|
||||
case 0:
|
||||
asm("csrc pmpcfg0, %[mask]"
|
||||
__asm__("csrc pmpcfg0, %[mask]"
|
||||
:: [mask] "r" (cfgmask) :);
|
||||
|
||||
asm("csrs pmpcfg0, %[cfg]"
|
||||
__asm__("csrs pmpcfg0, %[cfg]"
|
||||
:: [cfg] "r" (pmpcfg) :);
|
||||
break;
|
||||
case 1:
|
||||
asm("csrc pmpcfg1, %[mask]"
|
||||
__asm__("csrc pmpcfg1, %[mask]"
|
||||
:: [mask] "r" (cfgmask) :);
|
||||
|
||||
asm("csrs pmpcfg1, %[cfg]"
|
||||
__asm__("csrs pmpcfg1, %[cfg]"
|
||||
:: [cfg] "r" (pmpcfg) :);
|
||||
break;
|
||||
case 2:
|
||||
asm("csrc pmpcfg2, %[mask]"
|
||||
__asm__("csrc pmpcfg2, %[mask]"
|
||||
:: [mask] "r" (cfgmask) :);
|
||||
|
||||
asm("csrs pmpcfg2, %[cfg]"
|
||||
__asm__("csrs pmpcfg2, %[cfg]"
|
||||
:: [cfg] "r" (pmpcfg) :);
|
||||
break;
|
||||
case 3:
|
||||
asm("csrc pmpcfg3, %[mask]"
|
||||
__asm__("csrc pmpcfg3, %[mask]"
|
||||
:: [mask] "r" (cfgmask) :);
|
||||
|
||||
asm("csrs pmpcfg3, %[cfg]"
|
||||
__asm__("csrs pmpcfg3, %[cfg]"
|
||||
:: [cfg] "r" (pmpcfg) :);
|
||||
break;
|
||||
}
|
||||
|
@ -262,17 +267,17 @@ int metal_pmp_set_region(struct metal_pmp *pmp,
|
|||
|
||||
switch(region / 8) {
|
||||
case 0:
|
||||
asm("csrc pmpcfg0, %[mask]"
|
||||
__asm__("csrc pmpcfg0, %[mask]"
|
||||
:: [mask] "r" (cfgmask) :);
|
||||
|
||||
asm("csrs pmpcfg0, %[cfg]"
|
||||
__asm__("csrs pmpcfg0, %[cfg]"
|
||||
:: [cfg] "r" (pmpcfg) :);
|
||||
break;
|
||||
case 1:
|
||||
asm("csrc pmpcfg2, %[mask]"
|
||||
__asm__("csrc pmpcfg2, %[mask]"
|
||||
:: [mask] "r" (cfgmask) :);
|
||||
|
||||
asm("csrs pmpcfg2, %[cfg]"
|
||||
__asm__("csrs pmpcfg2, %[cfg]"
|
||||
:: [cfg] "r" (pmpcfg) :);
|
||||
break;
|
||||
}
|
||||
|
@ -290,6 +295,7 @@ int metal_pmp_get_region(struct metal_pmp *pmp,
|
|||
size_t *address)
|
||||
{
|
||||
size_t pmpcfg = 0;
|
||||
char *pmpcfg_convert = (char *)&pmpcfg;
|
||||
|
||||
if(!pmp || !config || !address) {
|
||||
/* NULL pointers are invalid arguments */
|
||||
|
@ -304,19 +310,19 @@ int metal_pmp_get_region(struct metal_pmp *pmp,
|
|||
#if __riscv_xlen==32
|
||||
switch(region / 4) {
|
||||
case 0:
|
||||
asm("csrr %[cfg], pmpcfg0"
|
||||
__asm__("csrr %[cfg], pmpcfg0"
|
||||
: [cfg] "=r" (pmpcfg) ::);
|
||||
break;
|
||||
case 1:
|
||||
asm("csrr %[cfg], pmpcfg1"
|
||||
__asm__("csrr %[cfg], pmpcfg1"
|
||||
: [cfg] "=r" (pmpcfg) ::);
|
||||
break;
|
||||
case 2:
|
||||
asm("csrr %[cfg], pmpcfg2"
|
||||
__asm__("csrr %[cfg], pmpcfg2"
|
||||
: [cfg] "=r" (pmpcfg) ::);
|
||||
break;
|
||||
case 3:
|
||||
asm("csrr %[cfg], pmpcfg3"
|
||||
__asm__("csrr %[cfg], pmpcfg3"
|
||||
: [cfg] "=r" (pmpcfg) ::);
|
||||
break;
|
||||
}
|
||||
|
@ -326,11 +332,11 @@ int metal_pmp_get_region(struct metal_pmp *pmp,
|
|||
#elif __riscv_xlen==64
|
||||
switch(region / 8) {
|
||||
case 0:
|
||||
asm("csrr %[cfg], pmpcfg0"
|
||||
__asm__("csrr %[cfg], pmpcfg0"
|
||||
: [cfg] "=r" (pmpcfg) ::);
|
||||
break;
|
||||
case 1:
|
||||
asm("csrr %[cfg], pmpcfg2"
|
||||
__asm__("csrr %[cfg], pmpcfg2"
|
||||
: [cfg] "=r" (pmpcfg) ::);
|
||||
break;
|
||||
}
|
||||
|
@ -341,71 +347,71 @@ int metal_pmp_get_region(struct metal_pmp *pmp,
|
|||
#error XLEN is not set to supported value for PMP driver
|
||||
#endif
|
||||
|
||||
*config = INT_TO_CONFIG(pmpcfg);
|
||||
*config = INT_TO_CONFIG(*pmpcfg_convert);
|
||||
|
||||
switch(region) {
|
||||
case 0:
|
||||
asm("csrr %[addr], pmpaddr0"
|
||||
__asm__("csrr %[addr], pmpaddr0"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 1:
|
||||
asm("csrr %[addr], pmpaddr1"
|
||||
__asm__("csrr %[addr], pmpaddr1"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 2:
|
||||
asm("csrr %[addr], pmpaddr2"
|
||||
__asm__("csrr %[addr], pmpaddr2"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 3:
|
||||
asm("csrr %[addr], pmpaddr3"
|
||||
__asm__("csrr %[addr], pmpaddr3"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 4:
|
||||
asm("csrr %[addr], pmpaddr4"
|
||||
__asm__("csrr %[addr], pmpaddr4"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 5:
|
||||
asm("csrr %[addr], pmpaddr5"
|
||||
__asm__("csrr %[addr], pmpaddr5"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 6:
|
||||
asm("csrr %[addr], pmpaddr6"
|
||||
__asm__("csrr %[addr], pmpaddr6"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 7:
|
||||
asm("csrr %[addr], pmpaddr7"
|
||||
__asm__("csrr %[addr], pmpaddr7"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 8:
|
||||
asm("csrr %[addr], pmpaddr8"
|
||||
__asm__("csrr %[addr], pmpaddr8"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 9:
|
||||
asm("csrr %[addr], pmpaddr9"
|
||||
__asm__("csrr %[addr], pmpaddr9"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 10:
|
||||
asm("csrr %[addr], pmpaddr10"
|
||||
__asm__("csrr %[addr], pmpaddr10"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 11:
|
||||
asm("csrr %[addr], pmpaddr11"
|
||||
__asm__("csrr %[addr], pmpaddr11"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 12:
|
||||
asm("csrr %[addr], pmpaddr12"
|
||||
__asm__("csrr %[addr], pmpaddr12"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 13:
|
||||
asm("csrr %[addr], pmpaddr13"
|
||||
__asm__("csrr %[addr], pmpaddr13"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 14:
|
||||
asm("csrr %[addr], pmpaddr14"
|
||||
__asm__("csrr %[addr], pmpaddr14"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
case 15:
|
||||
asm("csrr %[addr], pmpaddr15"
|
||||
__asm__("csrr %[addr], pmpaddr15"
|
||||
: [addr] "=r" (*address) ::);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
|
|||
metal_privilege_entry_point_t entry_point)
|
||||
{
|
||||
uintptr_t mstatus;
|
||||
asm volatile("csrr %0, mstatus" : "=r" (mstatus));
|
||||
__asm__ volatile("csrr %0, mstatus" : "=r" (mstatus));
|
||||
|
||||
/* Set xPIE bits based on current xIE bits */
|
||||
if(mstatus && (1 << METAL_MSTATUS_MIE_OFFSET)) {
|
||||
|
@ -43,15 +43,15 @@ void metal_privilege_drop_to_mode(enum metal_privilege_mode mode,
|
|||
mstatus &= ~(METAL_MSTATUS_MPP_MASK << METAL_MSTATUS_MPP_OFFSET);
|
||||
mstatus |= (mode << METAL_MSTATUS_MPP_OFFSET);
|
||||
|
||||
asm volatile("csrw mstatus, %0" :: "r" (mstatus));
|
||||
__asm__ volatile("csrw mstatus, %0" :: "r" (mstatus));
|
||||
|
||||
/* Set the entry point in MEPC */
|
||||
asm volatile("csrw mepc, %0" :: "r" (entry_point));
|
||||
__asm__ volatile("csrw mepc, %0" :: "r" (entry_point));
|
||||
|
||||
/* Set the register file */
|
||||
asm volatile("mv ra, %0" :: "r" (regfile.ra));
|
||||
asm volatile("mv sp, %0" :: "r" (regfile.sp));
|
||||
__asm__ volatile("mv ra, %0" :: "r" (regfile.ra));
|
||||
__asm__ volatile("mv sp, %0" :: "r" (regfile.sp));
|
||||
|
||||
asm volatile("mret");
|
||||
__asm__ volatile("mret");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright 2019 SiFive, Inc. */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine.h>
|
||||
#include <metal/rtc.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern inline uint64_t metal_rtc_get_rate(const struct metal_rtc *const rtc);
|
||||
extern inline uint64_t metal_rtc_set_rate(const struct metal_rtc *const rtc, const uint64_t rate);
|
||||
extern inline uint64_t metal_rtc_get_compare(const struct metal_rtc *const rtc);
|
||||
extern inline uint64_t metal_rtc_set_compare(const struct metal_rtc *const rtc, const uint64_t compare);
|
||||
extern inline uint64_t metal_rtc_get_count(const struct metal_rtc *const rtc);
|
||||
extern inline uint64_t metal_rtc_set_count(const struct metal_rtc *const rtc, const uint64_t count);
|
||||
extern inline int metal_rtc_run(const struct metal_rtc *const rtc, const enum metal_rtc_run_option option);
|
||||
extern inline struct metal_interrupt *metal_rtc_get_interrupt(const struct metal_rtc *const rtc);
|
||||
extern inline int metal_rtc_get_interrupt_id(const struct metal_rtc *const rtc);
|
||||
|
||||
struct metal_rtc *metal_rtc_get_device(int index) {
|
||||
#ifdef __METAL_DT_MAX_RTCS
|
||||
if (index < __METAL_DT_MAX_RTCS) {
|
||||
return (struct metal_rtc *) __metal_rtc_table[index];
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
#include <metal/machine.h>
|
||||
#include <metal/shutdown.h>
|
||||
|
||||
extern inline void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code);
|
||||
extern __inline__ void __metal_shutdown_exit(const struct __metal_shutdown *sd, int code);
|
||||
|
||||
#if defined(__METAL_DT_SHUTDOWN_HANDLE)
|
||||
void metal_shutdown(int code)
|
||||
|
@ -12,7 +12,7 @@ void metal_shutdown(int code)
|
|||
__metal_shutdown_exit(__METAL_DT_SHUTDOWN_HANDLE, code);
|
||||
}
|
||||
#else
|
||||
# warning "There is no defined shutdown mechanism, metal_shutdown() will spin."
|
||||
#pragma message("There is no defined shutdown mechanism, metal_shutdown() will spin.")
|
||||
void metal_shutdown(int code)
|
||||
{
|
||||
while (1) {
|
||||
|
|
|
@ -4,16 +4,18 @@
|
|||
#include <metal/machine.h>
|
||||
#include <metal/spi.h>
|
||||
|
||||
extern inline void metal_spi_init(struct metal_spi *spi, int baud_rate);
|
||||
extern inline int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf);
|
||||
extern inline int metal_spi_get_baud_rate(struct metal_spi *spi);
|
||||
extern inline int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate);
|
||||
extern __inline__ void metal_spi_init(struct metal_spi *spi, int baud_rate);
|
||||
extern __inline__ int metal_spi_transfer(struct metal_spi *spi, struct metal_spi_config *config, size_t len, char *tx_buf, char *rx_buf);
|
||||
extern __inline__ int metal_spi_get_baud_rate(struct metal_spi *spi);
|
||||
extern __inline__ int metal_spi_set_baud_rate(struct metal_spi *spi, int baud_rate);
|
||||
|
||||
struct metal_spi *metal_spi_get_device(int device_num)
|
||||
struct metal_spi *metal_spi_get_device(unsigned int device_num)
|
||||
{
|
||||
if(device_num >= __METAL_DT_MAX_SPIS) {
|
||||
return NULL;
|
||||
#if __METAL_DT_MAX_SPIS > 0
|
||||
if (device_num < __METAL_DT_MAX_SPIS) {
|
||||
return (struct metal_spi *) __metal_spi_table[device_num];
|
||||
}
|
||||
#endif
|
||||
|
||||
return (struct metal_spi *) __metal_spi_table[device_num];
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,6 @@ struct metal_switch* metal_switch_get (char *label)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern inline struct metal_interrupt*
|
||||
extern __inline__ struct metal_interrupt*
|
||||
metal_switch_interrupt_controller(struct metal_switch *flip);
|
||||
extern inline int metal_switch_get_interrupt_id(struct metal_switch *flip);
|
||||
extern __inline__ int metal_switch_get_interrupt_id(struct metal_switch *flip);
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/machine.h>
|
||||
#include <metal/machine/platform.h>
|
||||
#include <metal/io.h>
|
||||
#include <metal/cpu.h>
|
||||
|
||||
#define METAL_REG(base, offset) (((unsigned long)(base) + (offset)))
|
||||
#define METAL_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)METAL_REG((base), (offset))))
|
||||
#define METAL_MSIP(base, hart) (METAL_REGW((base),4*(hart)))
|
||||
|
||||
/*
|
||||
* _synchronize_harts() is called by crt0.S to cause harts > 0 to wait for
|
||||
* hart 0 to finish copying the datat section, zeroing the BSS, and running
|
||||
* the libc contstructors.
|
||||
*/
|
||||
__attribute__((section(".init")))
|
||||
void __metal_synchronize_harts() {
|
||||
#if __METAL_DT_MAX_HARTS > 1
|
||||
|
||||
int hart;
|
||||
__asm__ volatile("csrr %0, mhartid" : "=r" (hart) ::);
|
||||
|
||||
uintptr_t msip_base = 0;
|
||||
|
||||
/* Get the base address of the MSIP registers */
|
||||
#ifdef __METAL_DT_RISCV_CLINT0_HANDLE
|
||||
msip_base = __metal_driver_sifive_clint0_control_base(__METAL_DT_RISCV_CLINT0_HANDLE);
|
||||
msip_base += METAL_RISCV_CLINT0_MSIP_BASE;
|
||||
#elif __METAL_DT_RISCV_CLIC0_HANDLE
|
||||
msip_base = __metal_driver_sifive_clic0_control_base(__METAL_DT_RISCV_CLIC0_HANDLE);
|
||||
msip_base += METAL_RISCV_CLIC0_MSIP_BASE;
|
||||
#else
|
||||
#pragma message(No handle for CLINT or CLIC found, harts may be unsynchronized after init!)
|
||||
#endif
|
||||
|
||||
/* Disable machine interrupts as a precaution */
|
||||
__asm__ volatile("csrc mstatus, %0" :: "r" (METAL_MSTATUS_MIE));
|
||||
|
||||
if (hart == 0) {
|
||||
/* Hart 0 waits for all harts to set their MSIP bit */
|
||||
for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) {
|
||||
while (METAL_MSIP(msip_base, i) == 0) ;
|
||||
}
|
||||
|
||||
/* Hart 0 clears everyone's MSIP bit */
|
||||
for (int i = 1 ; i < __METAL_DT_MAX_HARTS; i++) {
|
||||
METAL_MSIP(msip_base, i) = 0;
|
||||
}
|
||||
} else {
|
||||
/* Other harts set their MSIP bit to indicate they're ready */
|
||||
METAL_MSIP(msip_base, hart) = 1;
|
||||
__asm__ volatile ("fence w,rw");
|
||||
|
||||
/* Wait for hart 0 to clear the MSIP bit */
|
||||
while (METAL_MSIP(msip_base, hart) == 1) ;
|
||||
}
|
||||
|
||||
#endif /* __METAL_DT_MAX_HARTS > 1 */
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/time.h>
|
||||
#include <metal/timer.h>
|
||||
|
||||
int metal_gettimeofday(struct timeval *tp, void *tzp)
|
||||
{
|
||||
int rv;
|
||||
unsigned long long mcc, timebase;
|
||||
if ((rv = metal_timer_get_cyclecount(0, &mcc))) {
|
||||
return -1;
|
||||
}
|
||||
if ((rv = metal_timer_get_timebase_frequency(0, &timebase))) {
|
||||
return -1;
|
||||
}
|
||||
tp->tv_sec = mcc / timebase;
|
||||
tp->tv_usec = mcc % timebase * 1000000 / timebase;
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t metal_time (void)
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
if (metal_gettimeofday(&now, NULL) < 0)
|
||||
now.tv_sec = (time_t) -1;
|
||||
|
||||
return now.tv_sec;
|
||||
}
|
|
@ -65,15 +65,15 @@ int nop_tick(int second) __attribute__((section(".text.metal.nop.tick")));
|
|||
int nop_tick(int second) { return -1; }
|
||||
int metal_timer_get_cyclecount(int hartid, unsigned long long *c) __attribute__((weak, alias("nop_cyclecount")))
|
||||
{
|
||||
#warning "There is no default timer device, metal_timer_get_cyclecount() will always return cyclecount -1."
|
||||
#pragma message("There is no default timer device, metal_timer_get_cyclecount() will always return cyclecount -1.")
|
||||
}
|
||||
int metal_timer_get_timebase_frequency(unsigned long long *t) __attribute__((weak, alias("nop_timebase")))
|
||||
{
|
||||
#warning "There is no default timer device, metal_timer_get_timebase_frequency() will always return timebase -1."
|
||||
#pragma message("There is no default timer device, metal_timer_get_timebase_frequency() will always return timebase -1.")
|
||||
}
|
||||
int metal_timer_set_tick(int second) __attribute__((weak, alias("nop_tick")))
|
||||
{
|
||||
#warning "There is no default timer device, metal_timer_set_tick) will always return -1."
|
||||
#pragma message("There is no default timer device, metal_timer_set_tick) will always return -1.")
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,21 +2,35 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <metal/uart.h>
|
||||
#include <metal/tty.h>
|
||||
#include <metal/machine.h>
|
||||
|
||||
#if defined(__METAL_DT_STDOUT_UART_HANDLE)
|
||||
/* This implementation serves as a small shim that interfaces with the first
|
||||
* UART on a system. */
|
||||
int metal_tty_putc(unsigned char c)
|
||||
int metal_tty_putc(int c)
|
||||
{
|
||||
if (c == '\n') {
|
||||
int out = metal_uart_putc(__METAL_DT_STDOUT_UART_HANDLE, '\r');
|
||||
if (out != 0)
|
||||
return out;
|
||||
metal_tty_putc_raw( '\r' );
|
||||
}
|
||||
return metal_tty_putc_raw( c );
|
||||
}
|
||||
|
||||
int metal_tty_putc_raw(int c)
|
||||
{
|
||||
return metal_uart_putc(__METAL_DT_STDOUT_UART_HANDLE, c);
|
||||
}
|
||||
|
||||
int metal_tty_getc(int *c)
|
||||
{
|
||||
do {
|
||||
metal_uart_getc( __METAL_DT_STDOUT_UART_HANDLE, c );
|
||||
/* -1 means no key pressed, getc waits */
|
||||
} while( -1 == *c )
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __METAL_DT_STDOUT_UART_BAUD
|
||||
#define __METAL_DT_STDOUT_UART_BAUD 115200
|
||||
#endif
|
||||
|
@ -30,8 +44,8 @@ static void metal_tty_init(void)
|
|||
/* This implementation of putc doesn't actually do anything, it's just there to
|
||||
* provide a shim that eats all the characters so we can ensure that everything
|
||||
* can link to metal_tty_putc. */
|
||||
int nop_putc(unsigned char c) __attribute__((section(".text.metal.nop.putc")));
|
||||
int nop_putc(unsigned char c) { return -1; }
|
||||
int metal_tty_putc(unsigned char c) __attribute__((weak, alias("nop_putc")));
|
||||
#warning "There is no default output device, metal_tty_putc() will throw away all input."
|
||||
int nop_putc(int c) __attribute__((section(".text.metal.nop.putc")));
|
||||
int nop_putc(int c) { return -1; }
|
||||
int metal_tty_putc(int c) __attribute__((weak, alias("nop_putc")));
|
||||
#pragma message("There is no default output device, metal_tty_putc() will throw away all input.")
|
||||
#endif
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
#include <metal/uart.h>
|
||||
|
||||
extern inline void metal_uart_init(struct metal_uart *uart, int baud_rate);
|
||||
extern inline int metal_uart_putc(struct metal_uart *uart, unsigned char c);
|
||||
extern inline int metal_uart_getc(struct metal_uart *uart, unsigned char *c);
|
||||
extern inline int metal_uart_get_baud_rate(struct metal_uart *uart);
|
||||
extern inline int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate);
|
||||
extern __inline__ void metal_uart_init(struct metal_uart *uart, int baud_rate);
|
||||
extern __inline__ int metal_uart_putc(struct metal_uart *uart, int c);
|
||||
extern __inline__ int metal_uart_txready(struct metal_uart *uart);
|
||||
extern __inline__ int metal_uart_getc(struct metal_uart *uart, int *c);
|
||||
extern __inline__ int metal_uart_get_baud_rate(struct metal_uart *uart);
|
||||
extern __inline__ int metal_uart_set_baud_rate(struct metal_uart *uart, int baud_rate);
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/* Copyright 2019 SiFive, Inc */
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/*
|
||||
* Jump table for CLINT vectored mode
|
||||
*/
|
||||
.weak metal_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_interrupt_vector_handler
|
||||
|
||||
.weak metal_software_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_software_interrupt_vector_handler
|
||||
|
||||
.weak metal_timer_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_timer_interrupt_vector_handler
|
||||
|
||||
.weak metal_external_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_external_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc0_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc0_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc1_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc1_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc2_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc2_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc3_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc3_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc4_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc4_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc5_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc5_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc6_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc6_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc7_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc7_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc8_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc8_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc9_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc9_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc10_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc10_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc11_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc11_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc12_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc12_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc13_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc13_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc14_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc14_interrupt_vector_handler
|
||||
|
||||
.weak metal_lc15_interrupt_vector_handler
|
||||
.balign 4, 0
|
||||
.global metal_lc15_interrupt_vector_handler
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
.balign 128, 0
|
||||
#else
|
||||
.balign 256, 0
|
||||
#endif
|
||||
.option norvc
|
||||
.global __metal_vector_table
|
||||
__metal_vector_table:
|
||||
IRQ_0:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_1:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_2:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_3:
|
||||
j metal_software_interrupt_vector_handler
|
||||
IRQ_4:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_5:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_6:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_7:
|
||||
j metal_timer_interrupt_vector_handler
|
||||
IRQ_8:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_9:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_10:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_11:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_12:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_13:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_14:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_15:
|
||||
j metal_interrupt_vector_handler
|
||||
IRQ_LC0:
|
||||
j metal_lc0_interrupt_vector_handler
|
||||
IRQ_LC1:
|
||||
j metal_lc1_interrupt_vector_handler
|
||||
IRQ_LC2:
|
||||
j metal_lc2_interrupt_vector_handler
|
||||
IRQ_LC3:
|
||||
j metal_lc3_interrupt_vector_handler
|
||||
IRQ_LC4:
|
||||
j metal_lc4_interrupt_vector_handler
|
||||
IRQ_LC5:
|
||||
j metal_lc5_interrupt_vector_handler
|
||||
IRQ_LC6:
|
||||
j metal_lc6_interrupt_vector_handler
|
||||
IRQ_LC7:
|
||||
j metal_lc7_interrupt_vector_handler
|
||||
IRQ_LC8:
|
||||
j metal_lc8_interrupt_vector_handler
|
||||
IRQ_LC9:
|
||||
j metal_lc9_interrupt_vector_handler
|
||||
IRQ_LC10:
|
||||
j metal_lc10_interrupt_vector_handler
|
||||
IRQ_LC11:
|
||||
j metal_lc11_interrupt_vector_handler
|
||||
IRQ_LC12:
|
||||
j metal_lc12_interrupt_vector_handler
|
||||
IRQ_LC13:
|
||||
j metal_lc13_interrupt_vector_handler
|
||||
IRQ_LC14:
|
||||
j metal_lc14_interrupt_vector_handler
|
||||
IRQ_LC15:
|
||||
j metal_lc15_interrupt_vector_handler
|
||||
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
/* Set mainCREATE_SIMPLE_BLINKY_DEMO_ONLY to one to run the simple blinky demo,
|
||||
or 0 to run the more comprehensive test and demo application. */
|
||||
#define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 1
|
||||
#define mainCREATE_SIMPLE_BLINKY_DEMO_ONLY 0
|
||||
|
||||
/* Index to first HART (there is only one). */
|
||||
#define mainHART_0 0
|
||||
|
@ -265,6 +265,9 @@ void *malloc( size_t xSize )
|
|||
if something unexpectedly uses the C library heap. See
|
||||
https://www.freertos.org/a00111.html for more information. */
|
||||
configASSERT( metal_cpu_get( mainHART_0 ) == 0x00 );
|
||||
|
||||
/* Remove warnings about unused parameter. */
|
||||
( void ) xSize;
|
||||
return NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
|
Loading…
Reference in a new issue