nuttx/mm/mm_gran/mm_grantable.c
Lwazi Dube e593ba35a4 arch/mips: Add basic support for MIPS Creator CI20 board
This commit introduces a rudimentary architecture and board port for the
MIPS Creator CI20, featuring the dual core Ingenic JZ4780 SoC (MIPS32).

Included in this initial implementation:
- Basic architectural initialization and startup code for the JZ4780 Core 0.
- Minimal configuration required to execute from RAM.
- Early UART/serial console support for basic debugging and NSH output.
- Minimal board-specific configuration for the CI20 target.
- Console output is routed via UART0 on the expansion header.

This establishes basic support for running NuttX on the MIPS CI20.
Further peripherals, optimization, and extended documentation are left for
future iterations or community contributions.

Build and Runtime Deployment Info:
----------------------------------

The baseline can be configured, compiled using the MIPS MTI toolchain,
and loaded via U-Boot using the following commands (replace
<tftp_dir> with your local TFTP root directory).

./tools/configure.sh -l ci20/nsh
  make CROSSDEV=mips-mti-elf-
  mkimage -A mips -O linux -T kernel -C none -a 0x80000180 -e 0x800004ac \
    -n "nx" -d nuttx.bin <tftp_dir>/nuttx.umg

Note: U-Boot must be properly configured for networking (e.g., valid ipaddr,
serverip, and ethaddr environment variables) to fetch the image over TFTP.

Run this from U-Boot prompt:
  tftp nuttx.umg && bootm $fileaddr

Signed-off-by: Lwazi Dube <lwazeh@gmail.com>
2026-07-15 08:02:55 -03:00

313 lines
6.8 KiB
C

/****************************************************************************
* mm/mm_gran/mm_grantable.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <errno.h>
#include <strings.h>
#include <nuttx/debug.h>
#include <nuttx/bits.h>
#include <nuttx/mm/gran.h>
#include "mm_gran/mm_gran.h"
#include "mm_gran/mm_grantable.h"
#ifdef CONFIG_GRAN
/****************************************************************************
* Preprocessors
****************************************************************************/
#define GATCFULL 0xffffffffu /* a full GAT cell */
#define DEBRUJIN_NUM 0x077CB531UL /* the de Bruijn Sequence */
/****************************************************************************
* Private data
****************************************************************************/
#if !defined(CONFIG_HAVE_BUILTIN_CLZ) || !defined(CONFIG_HAVE_BUILTIN_CTZ)
/* The de Bruijn lookup table to get n from BIT(n). */
static const uint8_t DEBRUJIN_LUT[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/* return BIT(MSB(n)) */
uint32_t msb_mask(uint32_t n)
{
/* see https://www.geeksforgeeks.org/find-significant-set-bit-number */
DEBUGASSERT(n);
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n = ((n + 1) >> 1) | (n & (1 << ((sizeof(n) << 3)-1)));
return n;
}
/* return BIT(LSB(n)) */
uint32_t lsb_mask(uint32_t n)
{
DEBUGASSERT(n);
return (-n & n) & GATCFULL;
}
/* set or clear a GAT cell with given bit mask */
static void cell_set(gran_t *gran, uint32_t cell, uint32_t mask, bool val)
{
if (val)
{
gran->gat[cell] |= mask;
}
else
{
gran->gat[cell] &= ~mask;
}
}
/* set or clear a range of GAT bits */
static void gran_set_(gran_t *gran, gatr_t *rang, bool val)
{
uint32_t c;
cell_set(gran, rang->sidx, rang->smask, val);
if (rang->sidx != rang->eidx)
{
cell_set(gran, rang->eidx, rang->emask, val);
c = rang->sidx + 1;
for (; c < rang->eidx; c++)
{
cell_set(gran, c, GATCFULL, val);
}
}
return;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/* prepare given GAT range instance for later use. */
int gran_range(const gran_t *gran, size_t posi, size_t size,
gatr_t *rang)
{
if (!gran || gran->ngranules < posi + size)
{
return -EINVAL;
}
if (rang == NULL)
{
return -ENOMEM;
}
rang->width = GATC_BITS(gran);
rang->sidx = posi / rang->width;
rang->soff = posi % rang->width;
posi += size - 1;
rang->eidx = posi / GATC_BITS(gran);
rang->eoff = posi % GATC_BITS(gran);
rang->smask = ~(BIT(rang->soff) - 1);
rang->emask = (BIT(rang->eoff) - 1) | BIT(rang->eoff);
if (rang->sidx == rang->eidx)
{
rang->smask &= rang->emask; /* combine the masks */
rang->emask = rang->smask;
}
return OK;
}
/* checks if a range of granule matches the expected status */
bool gran_match(const gran_t *gran, size_t posi, size_t size, bool used,
size_t *mpos)
{
uint32_t c; /* cell index */
uint32_t v; /* masked cell value */
uint32_t e; /* expected cell value */
gatr_t r; /* range helper */
if (gran_range(gran, posi, size, &r) < 0)
{
memset(&r, 0, sizeof(r));
}
/* check the ending cell */
c = r.eidx;
e = used ? r.emask : 0 ;
v = gran->gat[c] & r.emask;
if (v != e)
{
goto failure;
}
if (r.sidx == r.eidx)
{
return true;
}
/* check cells in between */
c = r.eidx - 1;
e = used ? GATCFULL : 0;
for (; c > r.sidx; c--)
{
v = gran->gat[c];
if (v != e)
{
goto failure;
}
}
/* check the starting cell */
c = r.sidx;
e = used ? r.smask : 0 ;
v = gran->gat[c] & r.smask;
if (v != e)
{
goto failure;
}
return true;
failure:
if (mpos && !used)
{
size_t tmp;
v = gran->gat[c];
DEBUGASSERT(v);
if (v == GATCFULL)
{
/* Handle full GAT quickly */
tmp = 31;
}
else
{
/* offset of last used when matching for free */
#ifdef CONFIG_HAVE_BUILTIN_CLZ
tmp = 31 - __builtin_clz(v);
#else
tmp = (uint32_t)((msb_mask(v)) * DEBRUJIN_NUM) >> 27;
DEBUGASSERT(tmp < sizeof(DEBRUJIN_LUT));
tmp = DEBRUJIN_LUT[tmp];
#endif
}
/* return the last used position to caller */
*mpos = tmp + c * GATC_BITS(gran);
}
return false;
}
/* returns granule number of free range or negative error */
int gran_search(const gran_t *gran, size_t size)
{
int ret = -EINVAL;
size_t i;
if (gran == NULL || gran->ngranules < size)
{
return ret;
}
ret = -ENOMEM;
for (i = 0; i <= gran->ngranules - size; i++)
{
if (gran_match(gran, i, size, 0, &i))
{
ret = i;
break;
}
}
return ret;
}
/* set a range of granules */
int gran_set(gran_t *gran, size_t posi, size_t size)
{
gatr_t rang;
int ret = gran_range(gran, posi, size, &rang);
if (ret == OK)
{
gran_set_(gran, &rang, true);
}
return ret;
}
/* clear a range of granules */
int gran_clear(gran_t *gran, size_t posi, size_t size)
{
gatr_t rang;
int ret = gran_range(gran, posi, size, &rang);
if (ret == OK)
{
gran_set_(gran, &rang, false);
}
return ret;
}
#endif /* CONFIG_GRAN */