Since PostgreSQL 9.1
There is the convenient FOREACH which can loop over slices of arrays. The manual:
The target variable must be an array, and it receives successive
slices of the array value, where each slice is of the number of
dimensions specified by SLICE.
DO
$do$
DECLARE
   m   text[];
   arr text[] := '{{key1,val1},{key2,val2}}';  -- array literal
BEGIN
   FOREACH m SLICE 1 IN ARRAY arr
   LOOP
      RAISE NOTICE 'another_func(%,%)', m[1], m[2];
   END LOOP;
END
$do$;
db<>fiddle here - with a function printing results, instead of DO
LANGUAGE plpgsql is the default for a DO statement so we can omit the declaration.
There is no difference between text[] and text[][] for the Postgres type system. See:
Postgres 9.0 or older
DO
$do$
DECLARE
   arr text[] := array[['key1','val1'],['key2','val2']];  -- array constructor
BEGIN
   FOR i IN array_lower(arr, 1) .. array_upper(arr, 1)
   LOOP
      RAISE NOTICE 'another_func(%,%)', arr[i][1], arr[i][2];
   END LOOP;
END
$do$;